aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stolarski <daniel.stolarski@gmail.com>2019-10-12 07:28:13 +0700
committerWilly Sudiarto Raharjo <willysr@slackbuilds.org>2019-10-12 07:28:13 +0700
commit81ad083b0c06ea08ea33d5b05805161f50844ba2 (patch)
tree8140cb61339bac45563caaf6358b014daafab812
parente88b75639cbd0a5e73125581aea15bd7a45b636f (diff)
gis/qmapshack: Updated for version 1.13.2.
Signed-off-by: Willy Sudiarto Raharjo <willysr@slackbuilds.org>
-rw-r--r--gis/qmapshack/FindPROJ4.cmake153
-rw-r--r--gis/qmapshack/addqmaptool.patch25494
-rw-r--r--gis/qmapshack/line_3px_horizontal.pngbin0 -> 188 bytes
-rw-r--r--gis/qmapshack/line_3px_vertical.pngbin0 -> 189 bytes
-rw-r--r--gis/qmapshack/qmapshack.SlackBuild19
-rw-r--r--gis/qmapshack/qmapshack.info6
-rw-r--r--gis/qmapshack/qmt_map2jnx.patch1199
-rw-r--r--gis/qmapshack/rgb2pct.patch971
-rw-r--r--gis/qmapshack/splash.pngbin0 -> 156794 bytes
9 files changed, 27680 insertions, 162 deletions
diff --git a/gis/qmapshack/FindPROJ4.cmake b/gis/qmapshack/FindPROJ4.cmake
deleted file mode 100644
index a8213de4e036d..0000000000000
--- a/gis/qmapshack/FindPROJ4.cmake
+++ /dev/null
@@ -1,153 +0,0 @@
-#.rst:
-# FindPROJ4
-# --------
-#
-# Find the proj includes and library.
-#
-# IMPORTED Targets
-# ^^^^^^^^^^^^^^^^
-#
-# This module defines :prop_tgt:`IMPORTED` target ``PROJ4::proj``,
-# if Proj.4 has been found.
-#
-# Result Variables
-# ^^^^^^^^^^^^^^^^
-#
-# This module defines the following variables:
-#
-# ::
-#
-# PROJ4_INCLUDE_DIRS - where to find proj_api.h, etc.
-# PROJ4_LIBRARIES - List of libraries when using libproj.
-# PROJ4_FOUND - True if libproj found.
-#
-# ::
-#
-# PROJ4_VERSION - The version of libproj found (x.y.z)
-# PROJ4_VERSION_MAJOR - The major version of libproj
-# PROJ4_VERSION_MINOR - The minor version of libproj
-# PROJ4_VERSION_PATCH - The patch version of libproj
-# PROJ4_VERSION_TWEAK - always 0
-# PROJ4_VERSION_COUNT - The number of version components, always 3
-#
-# Hints
-# ^^^^^
-#
-# A user may set ``PROJ4_ROOT`` to a libproj installation root to tell this
-# module where to look exclusively.
-
-#=============================================================================
-# Copyright 2016 Kai Pastor
-#
-#
-# This file was derived from CMake 3.5's module FindZLIB.cmake
-# which has the following terms:
-#
-# Copyright 2001-2011 Kitware, Inc.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-#
-# * The names of Kitware, Inc., the Insight Consortium, or the names of
-# any consortium members, or of any contributors, may not be used to
-# endorse or promote products derived from this software without
-# specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
-
-# Search PROJ4_ROOT exclusively if it is set.
-if(PROJ4_ROOT)
- set(_PROJ4_SEARCH PATHS ${PROJ4_ROOT} NO_DEFAULT_PATH)
-else()
- set(_PROJ4_SEARCH)
-endif()
-
-find_path(PROJ4_INCLUDE_DIR NAMES proj_api.h ${_PROJ4_SEARCH} PATH_SUFFIXES include)
-mark_as_advanced(PROJ4_INCLUDE_DIR)
-
-if(PROJ4_INCLUDE_DIR AND EXISTS "${PROJ4_INCLUDE_DIR}/proj_api.h")
- file(STRINGS "${PROJ4_INCLUDE_DIR}/proj_api.h" PROJ4_H REGEX "^#define PJ_VERSION [0-9]+$")
-
- string(REGEX REPLACE "^.*PJ_VERSION ([0-9]).*$" "\\1" PROJ4_VERSION_MAJOR "${PROJ4_H}")
- string(REGEX REPLACE "^.*PJ_VERSION [0-9]([0-9]).*$" "\\1" PROJ4_VERSION_MINOR "${PROJ4_H}")
- string(REGEX REPLACE "^.*PJ_VERSION [0-9][0-9]([0-9]).*$" "\\1" PROJ4_VERSION_PATCH "${PROJ4_H}")
- set(PROJ4_VERSION "${PROJ4_VERSION_MAJOR}.${PROJ4_VERSION_MINOR}.${PROJ4_VERSION_PATCH}")
- set(PROJ4_VERSION_COUNT 3)
-endif()
-
-# Allow PROJ4_LIBRARY to be set manually, as the location of the proj library
-if(NOT PROJ4_LIBRARY)
- set(PROJ4_NAMES proj)
- set(PROJ4_NAMES_DEBUG projd)
- if(WIN32 AND DEFINED PROJ4_VERSION_MAJOR AND DEFINED PROJ4_VERSION_MINOR)
- list(APPEND PROJ4_NAMES proj_${PROJ4_VERSION_MAJOR}_${PROJ4_VERSION_MINOR})
- list(APPEND PROJ4_NAMES projd_${PROJ4_VERSION_MAJOR}_${PROJ4_VERSION_MINOR})
- endif()
- find_library(PROJ4_LIBRARY_RELEASE NAMES ${PROJ4_NAMES} ${_PROJ4_SEARCH} PATH_SUFFIXES lib)
- find_library(PROJ4_LIBRARY_DEBUG NAMES ${PROJ4_NAMES_DEBUG} ${_PROJ4_SEARCH} PATH_SUFFIXES lib)
- include(SelectLibraryConfigurations)
- select_library_configurations(PROJ4)
-endif()
-
-# handle the QUIETLY and REQUIRED arguments and set PROJ4_FOUND to TRUE if
-# all listed variables are TRUE
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(PROJ4
- REQUIRED_VARS
- PROJ4_LIBRARY
- PROJ4_INCLUDE_DIR
- VERSION_VAR
- PROJ4_VERSION
-)
-
-if(PROJ4_FOUND)
- set(PROJ4_INCLUDE_DIRS ${PROJ4_INCLUDE_DIR})
-
- if(NOT PROJ4_LIBRARIES)
- set(PROJ4_LIBRARIES ${PROJ4_LIBRARY})
- endif()
-
- if(NOT TARGET PROJ4::proj)
- add_library(PROJ4::proj UNKNOWN IMPORTED)
- set_target_properties(PROJ4::proj PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${PROJ4_INCLUDE_DIRS}")
-
- if(PROJ4_LIBRARY_RELEASE)
- set_property(TARGET PROJ4::proj APPEND PROPERTY
- IMPORTED_CONFIGURATIONS RELEASE)
- set_target_properties(PROJ4::proj PROPERTIES
- IMPORTED_LOCATION_RELEASE "${PROJ4_LIBRARY_RELEASE}")
- endif()
-
- if(PROJ4_LIBRARY_DEBUG)
- set_property(TARGET PROJ4::proj APPEND PROPERTY
- IMPORTED_CONFIGURATIONS DEBUG)
- set_target_properties(PROJ4::proj PROPERTIES
- IMPORTED_LOCATION_DEBUG "${PROJ4_LIBRARY_DEBUG}")
- endif()
-
- if(NOT PROJ4_LIBRARY_RELEASE AND NOT PROJ4_LIBRARY_DEBUG)
- set_property(TARGET PROJ4::proj APPEND PROPERTY
- IMPORTED_LOCATION "${PROJ4_LIBRARY}")
- endif()
- endif()
-endif()
-
diff --git a/gis/qmapshack/addqmaptool.patch b/gis/qmapshack/addqmaptool.patch
new file mode 100644
index 0000000000000..71553ddcc4c46
--- /dev/null
+++ b/gis/qmapshack/addqmaptool.patch
@@ -0,0 +1,25494 @@
+From c6e5240ec25b91d3320f265346a904b5bd906363 Mon Sep 17 00:00:00 2001
+From: Oliver Eichler <oliver.eichler@dspsolutions.de>
+Date: Thu, 12 Sep 2019 20:29:51 +0200
+Subject: [PATCH] [QMS-3] Add QMapTool from former sub-repo
+
+---
+ src/qmaptool/.hgtags | 1 +
+ src/qmaptool/CAbout.cpp | 46 +
+ src/qmaptool/CAbout.h | 35 +
+ src/qmaptool/CMainWindow.cpp | 182 ++
+ src/qmaptool/CMainWindow.h | 100 +
+ src/qmaptool/CMakeLists.txt | 269 +++
+ src/qmaptool/CSingleInstanceProxy.cpp | 102 +
+ src/qmaptool/CSingleInstanceProxy.h | 41 +
+ src/qmaptool/GeoMath.cpp | 54 +
+ src/qmaptool/GeoMath.h | 31 +
+ src/qmaptool/IAbout.ui | 164 ++
+ src/qmaptool/IMainWindow.ui | 208 ++
+ src/qmaptool/README.md | 7 +
+ src/qmaptool/canvas/CCanvas.cpp | 189 ++
+ src/qmaptool/canvas/CCanvas.h | 92 +
+ src/qmaptool/canvas/CDrawContextPixel.cpp | 168 ++
+ src/qmaptool/canvas/CDrawContextPixel.h | 91 +
+ src/qmaptool/canvas/CDrawContextProj.cpp | 166 ++
+ src/qmaptool/canvas/CDrawContextProj.h | 89 +
+ src/qmaptool/canvas/IDrawContext.cpp | 300 +++
+ src/qmaptool/canvas/IDrawContext.h | 164 ++
+ src/qmaptool/helpers/CDraw.cpp | 239 +++
+ src/qmaptool/helpers/CDraw.h | 96 +
+ src/qmaptool/helpers/CGdalFile.cpp | 221 +++
+ src/qmaptool/helpers/CGdalFile.h | 93 +
+ src/qmaptool/helpers/CSettings.h | 54 +
+ src/qmaptool/helpers/mitab.cpp | 260 +++
+ src/qmaptool/helpers/mitab.h | 46 +
+ src/qmaptool/items/CItemCutMap.cpp | 97 +
+ src/qmaptool/items/CItemCutMap.h | 52 +
+ src/qmaptool/items/CItemFile.cpp | 37 +
+ src/qmaptool/items/CItemFile.h | 38 +
+ src/qmaptool/items/CItemListWidget.cpp | 157 ++
+ src/qmaptool/items/CItemListWidget.h | 84 +
+ src/qmaptool/items/CItemMap.cpp | 82 +
+ src/qmaptool/items/CItemMap.h | 54 +
+ src/qmaptool/items/CItemMapLayer.cpp | 119 ++
+ src/qmaptool/items/CItemMapLayer.h | 57 +
+ src/qmaptool/items/CItemRefMap.cpp | 114 ++
+ src/qmaptool/items/CItemRefMap.h | 56 +
+ src/qmaptool/items/CItemTreeWidget.cpp | 317 +++
+ src/qmaptool/items/CItemTreeWidget.h | 94 +
+ src/qmaptool/items/IItem.cpp | 141 ++
+ src/qmaptool/items/IItem.h | 97 +
+ src/qmaptool/items/IItemListWidget.ui | 127 ++
+ src/qmaptool/items/IItemTreeWidget.ui | 135 ++
+ src/qmaptool/locale/qmaptool.ts | 1675 ++++++++++++++++
+ src/qmaptool/locale/qmaptool_de.ts | 1712 ++++++++++++++++
+ src/qmaptool/locale/qmaptool_es.ts | 1715 +++++++++++++++++
+ src/qmaptool/main.cpp | 76 +
+ src/qmaptool/overlay/COverlayCutMap.cpp | 644 +++++++
+ src/qmaptool/overlay/COverlayCutMap.h | 105 +
+ src/qmaptool/overlay/COverlayGridTool.cpp | 348 ++++
+ src/qmaptool/overlay/COverlayGridTool.h | 68 +
+ src/qmaptool/overlay/COverlayRefMap.cpp | 747 +++++++
+ src/qmaptool/overlay/COverlayRefMap.h | 103 +
+ src/qmaptool/overlay/IOverlay.cpp | 36 +
+ src/qmaptool/overlay/IOverlay.h | 43 +
+ src/qmaptool/overlay/IOverlayCutMap.ui | 202 ++
+ src/qmaptool/overlay/IOverlayGridTool.ui | 184 ++
+ src/qmaptool/overlay/IOverlayRefMap.ui | 351 ++++
+ src/qmaptool/overlay/gridtool/CGridPlacer.cpp | 274 +++
+ src/qmaptool/overlay/gridtool/CGridPlacer.h | 85 +
+ src/qmaptool/overlay/gridtool/CGridPoint.cpp | 184 ++
+ src/qmaptool/overlay/gridtool/CGridPoint.h | 70 +
+ .../overlay/gridtool/CGridSelArea.cpp | 240 +++
+ src/qmaptool/overlay/gridtool/CGridSelArea.h | 97 +
+ src/qmaptool/overlay/gridtool/CGridSetRef.cpp | 105 +
+ src/qmaptool/overlay/gridtool/CGridSetRef.h | 86 +
+ src/qmaptool/overlay/gridtool/IGridPlacer.ui | 248 +++
+ src/qmaptool/overlay/gridtool/IGridSelArea.ui | 49 +
+ src/qmaptool/overlay/gridtool/IGridSetRef.ui | 117 ++
+ .../overlay/refmap/CDialogRefPoint.cpp | 74 +
+ src/qmaptool/overlay/refmap/CDialogRefPoint.h | 46 +
+ .../overlay/refmap/COverlayRefMapPoint.cpp | 52 +
+ .../overlay/refmap/COverlayRefMapPoint.h | 67 +
+ src/qmaptool/overlay/refmap/CProjWizard.cpp | 237 +++
+ src/qmaptool/overlay/refmap/CProjWizard.h | 44 +
+ .../overlay/refmap/IDialogRefPoint.ui | 131 ++
+ src/qmaptool/overlay/refmap/IProjWizard.ui | 210 ++
+ src/qmaptool/resources.qrc | 93 +
+ src/qmaptool/setup/CAppOpts.h | 47 +
+ src/qmaptool/setup/CAppSetupLinux.cpp | 62 +
+ src/qmaptool/setup/CAppSetupLinux.h | 44 +
+ src/qmaptool/setup/CAppSetupMac.cpp | 140 ++
+ src/qmaptool/setup/CAppSetupMac.h | 49 +
+ src/qmaptool/setup/CAppSetupWin.cpp | 69 +
+ src/qmaptool/setup/CAppSetupWin.h | 45 +
+ src/qmaptool/setup/CCommandProcessor.cpp | 58 +
+ src/qmaptool/setup/CCommandProcessor.h | 33 +
+ src/qmaptool/setup/CLogHandler.cpp | 122 ++
+ src/qmaptool/setup/CLogHandler.h | 47 +
+ src/qmaptool/setup/CSetupExtTools.cpp | 93 +
+ src/qmaptool/setup/CSetupExtTools.h | 46 +
+ src/qmaptool/setup/IAppSetup.cpp | 161 ++
+ src/qmaptool/setup/IAppSetup.h | 210 ++
+ src/qmaptool/setup/ISetupExtTools.ui | 360 ++++
+ src/qmaptool/shell/CShell.cpp | 198 ++
+ src/qmaptool/shell/CShell.h | 75 +
+ src/qmaptool/shell/CShellCmd.cpp | 27 +
+ src/qmaptool/shell/CShellCmd.h | 47 +
+ src/qmaptool/tool/CToolAddOverview.cpp | 225 +++
+ src/qmaptool/tool/CToolAddOverview.h | 51 +
+ src/qmaptool/tool/CToolBox.cpp | 44 +
+ src/qmaptool/tool/CToolBox.h | 40 +
+ src/qmaptool/tool/CToolCutMap.cpp | 202 ++
+ src/qmaptool/tool/CToolCutMap.h | 51 +
+ src/qmaptool/tool/CToolExport.cpp | 193 ++
+ src/qmaptool/tool/CToolExport.h | 63 +
+ src/qmaptool/tool/CToolGrid.cpp | 124 ++
+ src/qmaptool/tool/CToolGrid.h | 57 +
+ src/qmaptool/tool/CToolOverviewGroupBox.cpp | 95 +
+ src/qmaptool/tool/CToolOverviewGroupBox.h | 43 +
+ src/qmaptool/tool/CToolPalettize.cpp | 319 +++
+ src/qmaptool/tool/CToolPalettize.h | 57 +
+ src/qmaptool/tool/CToolRefMap.cpp | 257 +++
+ src/qmaptool/tool/CToolRefMap.h | 52 +
+ src/qmaptool/tool/CToolStack.cpp | 44 +
+ src/qmaptool/tool/CToolStack.h | 41 +
+ src/qmaptool/tool/ITool.cpp | 20 +
+ src/qmaptool/tool/ITool.h | 234 +++
+ src/qmaptool/tool/IToolAddOverview.ui | 278 +++
+ src/qmaptool/tool/IToolCutMap.ui | 263 +++
+ src/qmaptool/tool/IToolExport.ui | 206 ++
+ src/qmaptool/tool/IToolGrid.ui | 158 ++
+ src/qmaptool/tool/IToolGui.cpp | 111 ++
+ src/qmaptool/tool/IToolGui.h | 48 +
+ src/qmaptool/tool/IToolOverviewGroupBox.ui | 130 ++
+ src/qmaptool/tool/IToolPalettize.ui | 269 +++
+ src/qmaptool/tool/IToolRefMap.ui | 276 +++
+ src/qmaptool/tool/export/CToolExportJnx.cpp | 28 +
+ src/qmaptool/tool/export/CToolExportJnx.h | 68 +
+ src/qmaptool/tool/export/IToolExportJnx.ui | 224 +++
+ src/qmaptool/units/CCoordFormatSetup.cpp | 67 +
+ src/qmaptool/units/CCoordFormatSetup.h | 37 +
+ src/qmaptool/units/CTimeZoneSetup.cpp | 105 +
+ src/qmaptool/units/CTimeZoneSetup.h | 36 +
+ src/qmaptool/units/CUnitImperial.cpp | 113 ++
+ src/qmaptool/units/CUnitImperial.h | 41 +
+ src/qmaptool/units/CUnitMetric.cpp | 132 ++
+ src/qmaptool/units/CUnitMetric.h | 37 +
+ src/qmaptool/units/CUnitNautic.cpp | 96 +
+ src/qmaptool/units/CUnitNautic.h | 37 +
+ src/qmaptool/units/CUnitsSetup.cpp | 59 +
+ src/qmaptool/units/CUnitsSetup.h | 35 +
+ src/qmaptool/units/ICoordFormatSetup.ui | 125 ++
+ src/qmaptool/units/ITimeZoneSetup.ui | 182 ++
+ src/qmaptool/units/IUnit.cpp | 776 ++++++++
+ src/qmaptool/units/IUnit.h | 153 ++
+ src/qmaptool/units/IUnitsSetup.ui | 125 ++
+ src/qmaptool/version.h | 33 +
+ 154 files changed, 24277 insertions(+)
+ create mode 100644 src/qmaptool/.hgtags
+ create mode 100644 src/qmaptool/CAbout.cpp
+ create mode 100644 src/qmaptool/CAbout.h
+ create mode 100644 src/qmaptool/CMainWindow.cpp
+ create mode 100644 src/qmaptool/CMainWindow.h
+ create mode 100644 src/qmaptool/CMakeLists.txt
+ create mode 100644 src/qmaptool/CSingleInstanceProxy.cpp
+ create mode 100644 src/qmaptool/CSingleInstanceProxy.h
+ create mode 100644 src/qmaptool/GeoMath.cpp
+ create mode 100644 src/qmaptool/GeoMath.h
+ create mode 100644 src/qmaptool/IAbout.ui
+ create mode 100644 src/qmaptool/IMainWindow.ui
+ create mode 100644 src/qmaptool/README.md
+ create mode 100644 src/qmaptool/canvas/CCanvas.cpp
+ create mode 100644 src/qmaptool/canvas/CCanvas.h
+ create mode 100644 src/qmaptool/canvas/CDrawContextPixel.cpp
+ create mode 100644 src/qmaptool/canvas/CDrawContextPixel.h
+ create mode 100644 src/qmaptool/canvas/CDrawContextProj.cpp
+ create mode 100644 src/qmaptool/canvas/CDrawContextProj.h
+ create mode 100644 src/qmaptool/canvas/IDrawContext.cpp
+ create mode 100644 src/qmaptool/canvas/IDrawContext.h
+ create mode 100644 src/qmaptool/helpers/CDraw.cpp
+ create mode 100644 src/qmaptool/helpers/CDraw.h
+ create mode 100644 src/qmaptool/helpers/CGdalFile.cpp
+ create mode 100644 src/qmaptool/helpers/CGdalFile.h
+ create mode 100644 src/qmaptool/helpers/CSettings.h
+ create mode 100644 src/qmaptool/helpers/mitab.cpp
+ create mode 100644 src/qmaptool/helpers/mitab.h
+ create mode 100644 src/qmaptool/items/CItemCutMap.cpp
+ create mode 100644 src/qmaptool/items/CItemCutMap.h
+ create mode 100644 src/qmaptool/items/CItemFile.cpp
+ create mode 100644 src/qmaptool/items/CItemFile.h
+ create mode 100644 src/qmaptool/items/CItemListWidget.cpp
+ create mode 100644 src/qmaptool/items/CItemListWidget.h
+ create mode 100644 src/qmaptool/items/CItemMap.cpp
+ create mode 100644 src/qmaptool/items/CItemMap.h
+ create mode 100644 src/qmaptool/items/CItemMapLayer.cpp
+ create mode 100644 src/qmaptool/items/CItemMapLayer.h
+ create mode 100644 src/qmaptool/items/CItemRefMap.cpp
+ create mode 100644 src/qmaptool/items/CItemRefMap.h
+ create mode 100644 src/qmaptool/items/CItemTreeWidget.cpp
+ create mode 100644 src/qmaptool/items/CItemTreeWidget.h
+ create mode 100644 src/qmaptool/items/IItem.cpp
+ create mode 100644 src/qmaptool/items/IItem.h
+ create mode 100644 src/qmaptool/items/IItemListWidget.ui
+ create mode 100644 src/qmaptool/items/IItemTreeWidget.ui
+ create mode 100644 src/qmaptool/locale/qmaptool.ts
+ create mode 100644 src/qmaptool/locale/qmaptool_de.ts
+ create mode 100644 src/qmaptool/locale/qmaptool_es.ts
+ create mode 100644 src/qmaptool/main.cpp
+ create mode 100644 src/qmaptool/overlay/COverlayCutMap.cpp
+ create mode 100644 src/qmaptool/overlay/COverlayCutMap.h
+ create mode 100644 src/qmaptool/overlay/COverlayGridTool.cpp
+ create mode 100644 src/qmaptool/overlay/COverlayGridTool.h
+ create mode 100644 src/qmaptool/overlay/COverlayRefMap.cpp
+ create mode 100644 src/qmaptool/overlay/COverlayRefMap.h
+ create mode 100644 src/qmaptool/overlay/IOverlay.cpp
+ create mode 100644 src/qmaptool/overlay/IOverlay.h
+ create mode 100644 src/qmaptool/overlay/IOverlayCutMap.ui
+ create mode 100644 src/qmaptool/overlay/IOverlayGridTool.ui
+ create mode 100644 src/qmaptool/overlay/IOverlayRefMap.ui
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridPlacer.cpp
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridPlacer.h
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridPoint.cpp
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridPoint.h
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridSelArea.cpp
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridSelArea.h
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridSetRef.cpp
+ create mode 100644 src/qmaptool/overlay/gridtool/CGridSetRef.h
+ create mode 100644 src/qmaptool/overlay/gridtool/IGridPlacer.ui
+ create mode 100644 src/qmaptool/overlay/gridtool/IGridSelArea.ui
+ create mode 100644 src/qmaptool/overlay/gridtool/IGridSetRef.ui
+ create mode 100644 src/qmaptool/overlay/refmap/CDialogRefPoint.cpp
+ create mode 100644 src/qmaptool/overlay/refmap/CDialogRefPoint.h
+ create mode 100644 src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp
+ create mode 100644 src/qmaptool/overlay/refmap/COverlayRefMapPoint.h
+ create mode 100644 src/qmaptool/overlay/refmap/CProjWizard.cpp
+ create mode 100644 src/qmaptool/overlay/refmap/CProjWizard.h
+ create mode 100644 src/qmaptool/overlay/refmap/IDialogRefPoint.ui
+ create mode 100644 src/qmaptool/overlay/refmap/IProjWizard.ui
+ create mode 100644 src/qmaptool/resources.qrc
+ create mode 100644 src/qmaptool/setup/CAppOpts.h
+ create mode 100644 src/qmaptool/setup/CAppSetupLinux.cpp
+ create mode 100644 src/qmaptool/setup/CAppSetupLinux.h
+ create mode 100644 src/qmaptool/setup/CAppSetupMac.cpp
+ create mode 100644 src/qmaptool/setup/CAppSetupMac.h
+ create mode 100644 src/qmaptool/setup/CAppSetupWin.cpp
+ create mode 100644 src/qmaptool/setup/CAppSetupWin.h
+ create mode 100644 src/qmaptool/setup/CCommandProcessor.cpp
+ create mode 100644 src/qmaptool/setup/CCommandProcessor.h
+ create mode 100644 src/qmaptool/setup/CLogHandler.cpp
+ create mode 100644 src/qmaptool/setup/CLogHandler.h
+ create mode 100644 src/qmaptool/setup/CSetupExtTools.cpp
+ create mode 100644 src/qmaptool/setup/CSetupExtTools.h
+ create mode 100644 src/qmaptool/setup/IAppSetup.cpp
+ create mode 100644 src/qmaptool/setup/IAppSetup.h
+ create mode 100644 src/qmaptool/setup/ISetupExtTools.ui
+ create mode 100644 src/qmaptool/shell/CShell.cpp
+ create mode 100644 src/qmaptool/shell/CShell.h
+ create mode 100644 src/qmaptool/shell/CShellCmd.cpp
+ create mode 100644 src/qmaptool/shell/CShellCmd.h
+ create mode 100644 src/qmaptool/tool/CToolAddOverview.cpp
+ create mode 100644 src/qmaptool/tool/CToolAddOverview.h
+ create mode 100644 src/qmaptool/tool/CToolBox.cpp
+ create mode 100644 src/qmaptool/tool/CToolBox.h
+ create mode 100644 src/qmaptool/tool/CToolCutMap.cpp
+ create mode 100644 src/qmaptool/tool/CToolCutMap.h
+ create mode 100644 src/qmaptool/tool/CToolExport.cpp
+ create mode 100644 src/qmaptool/tool/CToolExport.h
+ create mode 100644 src/qmaptool/tool/CToolGrid.cpp
+ create mode 100644 src/qmaptool/tool/CToolGrid.h
+ create mode 100644 src/qmaptool/tool/CToolOverviewGroupBox.cpp
+ create mode 100644 src/qmaptool/tool/CToolOverviewGroupBox.h
+ create mode 100644 src/qmaptool/tool/CToolPalettize.cpp
+ create mode 100644 src/qmaptool/tool/CToolPalettize.h
+ create mode 100644 src/qmaptool/tool/CToolRefMap.cpp
+ create mode 100644 src/qmaptool/tool/CToolRefMap.h
+ create mode 100644 src/qmaptool/tool/CToolStack.cpp
+ create mode 100644 src/qmaptool/tool/CToolStack.h
+ create mode 100644 src/qmaptool/tool/ITool.cpp
+ create mode 100644 src/qmaptool/tool/ITool.h
+ create mode 100644 src/qmaptool/tool/IToolAddOverview.ui
+ create mode 100644 src/qmaptool/tool/IToolCutMap.ui
+ create mode 100644 src/qmaptool/tool/IToolExport.ui
+ create mode 100644 src/qmaptool/tool/IToolGrid.ui
+ create mode 100644 src/qmaptool/tool/IToolGui.cpp
+ create mode 100644 src/qmaptool/tool/IToolGui.h
+ create mode 100644 src/qmaptool/tool/IToolOverviewGroupBox.ui
+ create mode 100644 src/qmaptool/tool/IToolPalettize.ui
+ create mode 100644 src/qmaptool/tool/IToolRefMap.ui
+ create mode 100644 src/qmaptool/tool/export/CToolExportJnx.cpp
+ create mode 100644 src/qmaptool/tool/export/CToolExportJnx.h
+ create mode 100644 src/qmaptool/tool/export/IToolExportJnx.ui
+ create mode 100644 src/qmaptool/units/CCoordFormatSetup.cpp
+ create mode 100644 src/qmaptool/units/CCoordFormatSetup.h
+ create mode 100644 src/qmaptool/units/CTimeZoneSetup.cpp
+ create mode 100644 src/qmaptool/units/CTimeZoneSetup.h
+ create mode 100644 src/qmaptool/units/CUnitImperial.cpp
+ create mode 100644 src/qmaptool/units/CUnitImperial.h
+ create mode 100644 src/qmaptool/units/CUnitMetric.cpp
+ create mode 100644 src/qmaptool/units/CUnitMetric.h
+ create mode 100644 src/qmaptool/units/CUnitNautic.cpp
+ create mode 100644 src/qmaptool/units/CUnitNautic.h
+ create mode 100644 src/qmaptool/units/CUnitsSetup.cpp
+ create mode 100644 src/qmaptool/units/CUnitsSetup.h
+ create mode 100644 src/qmaptool/units/ICoordFormatSetup.ui
+ create mode 100644 src/qmaptool/units/ITimeZoneSetup.ui
+ create mode 100644 src/qmaptool/units/IUnit.cpp
+ create mode 100644 src/qmaptool/units/IUnit.h
+ create mode 100644 src/qmaptool/units/IUnitsSetup.ui
+ create mode 100644 src/qmaptool/version.h
+
+diff --git a/src/qmaptool/.hgtags b/src/qmaptool/.hgtags
+new file mode 100644
+index 00000000..b3bd51f1
+--- /dev/null
++++ b/src/qmaptool/.hgtags
+@@ -0,0 +1 @@
++ed93a4558565182ee15572442250f22981d3de56 V 1.1.0
+diff --git a/src/qmaptool/CAbout.cpp b/src/qmaptool/CAbout.cpp
+new file mode 100644
+index 00000000..6c3c2cec
+--- /dev/null
++++ b/src/qmaptool/CAbout.cpp
+@@ -0,0 +1,46 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CAbout.h"
++#include "version.h"
++
++#include <gdal.h>
++#include <proj_api.h>
++#include <QtWidgets>
++
++
++CAbout::CAbout(QWidget *parent)
++ : QDialog(parent)
++{
++ setupUi(this);
++
++ if(QString(VER_SUFFIX).isEmpty())
++ {
++ labelVersion->setText(VER_STR);
++ }
++ else
++ {
++ labelVersion->setText(VER_STR "." VER_SUFFIX);
++ }
++
++ labelQtVersion->setText(qVersion());
++ labelGDALVersion->setText(GDALVersionInfo("--version"));
++ labelProj4Version->setText(QString::number(PJ_VERSION));
++}
++
++
+diff --git a/src/qmaptool/CAbout.h b/src/qmaptool/CAbout.h
+new file mode 100644
+index 00000000..52a6bfd7
+--- /dev/null
++++ b/src/qmaptool/CAbout.h
+@@ -0,0 +1,35 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CABOUT_H
++#define CABOUT_H
++
++#include "ui_IAbout.h"
++#include <QDialog>
++
++
++class CAbout : public QDialog, private Ui::IAbout
++{
++ Q_OBJECT
++public:
++ CAbout(QWidget * parent);
++ virtual ~CAbout() = default;
++};
++
++#endif //CABOUT_H
++
+diff --git a/src/qmaptool/CMainWindow.cpp b/src/qmaptool/CMainWindow.cpp
+new file mode 100644
+index 00000000..c21b566b
+--- /dev/null
++++ b/src/qmaptool/CMainWindow.cpp
+@@ -0,0 +1,182 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CAbout.h"
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "setup/CSetupExtTools.h"
++#include "tool/CToolAddOverview.h"
++#include "tool/CToolBox.h"
++#include "tool/CToolCutMap.h"
++#include "tool/CToolExport.h"
++#include "tool/CToolGrid.h"
++#include "tool/CToolPalettize.h"
++#include "tool/CToolRefMap.h"
++#include "units/CCoordFormatSetup.h"
++#include "units/CUnitsSetup.h"
++#include "units/IUnit.h"
++#include "version.h"
++
++CMainWindow * CMainWindow::pSelf = nullptr;
++
++CMainWindow::CMainWindow()
++{
++ SETTINGS;
++ IUnit::setUnitType((IUnit::type_e)cfg.value("Units/units",IUnit::eTypeMetric).toInt(), this);
++ IUnit::setCoordFormat((IUnit::coord_format_e)cfg.value("Units/coordFormat", IUnit::eCoordFormat1).toInt());
++
++ pSelf = this;
++ setupUi(this);
++ setWindowTitle(WHAT_STR);
++
++ canvas->setToolInterface(toolStack);
++
++ connect(actionAbout, &QAction::triggered, this, &CMainWindow::slotAbout);
++ connect(actionSetupExtTools, &QAction::triggered, this, &CMainWindow::slotSetupExtTools);
++ connect(actionSetupUnits, &QAction::triggered, this, &CMainWindow::slotSetupUnits);
++ connect(actionSetupCoordFormat, &QAction::triggered, this, &CMainWindow::slotSetupCoordFormat);
++ connect(&IAppSetup::self(), &IAppSetup::sigSetupChanged, this, &CMainWindow::slotSetupChanged);
++
++ menuWindow->addAction(dockTools->toggleViewAction());
++ menuWindow->addAction(dockShell->toggleViewAction());
++ prepareMenuForMac();
++
++ toolBox = new CToolBox(this);
++ toolStack->addWidget(toolBox);
++
++ toolAddOverview = new CToolAddOverview(toolBox);
++ toolBox->addItem(toolAddOverview, QIcon("://icons/32x32/AddOverview.png"), toolAddOverview->objectName());
++
++ toolCutMap = new CToolCutMap(toolBox);
++ toolBox->addItem(toolCutMap, QIcon("://icons/32x32/CutMap.png"), toolCutMap->objectName());
++
++ toolRefMap = new CToolRefMap(toolBox);
++ toolBox->addItem(toolRefMap, QIcon("://icons/32x32/ReferenceMap.png"), toolRefMap->objectName());
++
++ toolPalettize = new CToolPalettize(toolBox);
++ toolBox->addItem(toolPalettize, QIcon("://icons/32x32/Rasterize.png"), toolPalettize->objectName());
++
++ toolExport = new CToolExport(toolBox);
++ toolBox->addItem(toolExport, QIcon("://icons/32x32/Export.png"), toolExport->objectName());
++
++ toolGrid = new CToolGrid(this);
++ toolStack->addWidget(toolGrid);
++
++ // start ---- restore window geometry -----
++ if ( cfg.contains("MainWindow/geometry"))
++ {
++ restoreGeometry(cfg.value("MainWindow/geometry").toByteArray());
++ }
++ else
++ {
++ QTimer::singleShot(500, this, SLOT(showMaximized()));
++ }
++
++ if ( cfg.contains("MainWindow/state"))
++ {
++ restoreState(cfg.value("MainWindow/state").toByteArray());
++ }
++ // end ---- restore window geometry -----
++ //toolStack->setCurrentIndex(cfg.value("Tool/Stack/current",0).toInt());
++ toolBox->setCurrentIndex(cfg.value("Tool/Box/current",0).toInt());
++ actionShowToolHelp->setChecked(cfg.value("Tool/showHelp", true).toBool());
++ mapFont = cfg.value("Canvas/mapFont", font()).value<QFont>();
++ actionFlipMouseWheel->setChecked(cfg.value("Canvas/flipMouseWheel", false).toBool());
++}
++
++CMainWindow::~CMainWindow()
++{
++ SETTINGS;
++ cfg.setValue("MainWindow/state", saveState());
++ cfg.setValue("MainWindow/geometry", saveGeometry());
++
++ cfg.setValue("Canvas/mapFont", mapFont);
++ cfg.setValue("Canvas/flipMouseWheel", actionFlipMouseWheel->isChecked());
++
++ cfg.setValue("Units/units", IUnit::self().type);
++ cfg.setValue("Units/coordFormat", IUnit::getCoordFormat());
++
++ cfg.setValue("Tool/Box/current", toolBox->currentIndex());
++ cfg.setValue("Tool/showHelp", actionShowToolHelp->isChecked());
++}
++
++QString CMainWindow::getUser()
++{
++ QString user = getenv("USER");
++ if(user.isEmpty())
++ {
++ user = getenv("USERNAME"); //for windows
++
++ if(user.isEmpty())
++ {
++ user = "QMapTool";
++ }
++ }
++
++ return user;
++}
++
++void CMainWindow::prepareMenuForMac()
++{
++ dockTools->toggleViewAction()->setMenuRole(QAction::NoRole);
++}
++
++void CMainWindow::makeShellVisible()
++{
++ dockShell->show();
++}
++
++void CMainWindow::startGridTool(CItemRefMap *item)
++{
++ toolGrid->registerItem(item);
++ toolStack->setCurrentWidget(toolGrid);
++}
++
++void CMainWindow::showToolBox()
++{
++ toolStack->setCurrentWidget(toolBox);
++}
++
++void CMainWindow::slotAbout()
++{
++ CAbout dlg(this);
++ dlg.exec();
++}
++
++void CMainWindow::slotSetupExtTools()
++{
++ CSetupExtTools dlg(this);
++ dlg.exec();
++}
++
++void CMainWindow::slotSetupUnits()
++{
++ CUnitsSetup dlg(this);
++ dlg.exec();
++}
++
++void CMainWindow::slotSetupCoordFormat()
++{
++ CCoordFormatSetup dlg(this);
++ dlg.exec();
++}
++
++void CMainWindow::slotSetupChanged()
++{
++ toolStack->setupChanged();
++}
+diff --git a/src/qmaptool/CMainWindow.h b/src/qmaptool/CMainWindow.h
+new file mode 100644
+index 00000000..40077106
+--- /dev/null
++++ b/src/qmaptool/CMainWindow.h
+@@ -0,0 +1,100 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CMAINWINDOW_H
++#define CMAINWINDOW_H
++
++#include "ui_IMainWindow.h"
++#include <QMainWindow>
++
++class CToolBox;
++class CToolAddOverview;
++class CToolCutMap;
++class CToolRefMap;
++class CToolPalettize;
++class CCanvas;
++class CToolGrid;
++class CItemRefMap;
++class CToolExport;
++
++class CMainWindow : public QMainWindow, private Ui::IMainWindow
++{
++ Q_OBJECT
++public:
++ static CMainWindow& self()
++ {
++ return *pSelf;
++ }
++
++ virtual ~CMainWindow();
++
++ static QString getUser();
++
++ CCanvas * getCanvas() const
++ {
++ return canvas;
++ }
++
++ const QFont& getMapFont() const
++ {
++ return mapFont;
++ }
++
++ bool flipMouseWheel() const
++ {
++ return actionFlipMouseWheel->isChecked();
++ }
++
++ QAction * showToolHelp() const
++ {
++ return actionShowToolHelp;
++ }
++
++ void makeShellVisible();
++
++ void startGridTool(CItemRefMap * item);
++ void showToolBox();
++
++private slots:
++ void slotAbout();
++ void slotSetupExtTools();
++ void slotSetupUnits();
++ void slotSetupCoordFormat();
++ void slotSetupChanged();
++
++private:
++ friend int main(int argc, char ** argv);
++ CMainWindow();
++ static CMainWindow * pSelf;
++
++ void prepareMenuForMac();
++
++ QFont mapFont;
++
++ CToolBox * toolBox;
++ CToolGrid * toolGrid;
++
++ CToolAddOverview * toolAddOverview;
++ CToolCutMap * toolCutMap;
++ CToolRefMap * toolRefMap;
++ CToolPalettize * toolPalettize;
++ CToolExport * toolExport;
++};
++
++#endif //CMAINWINDOW_H
++
+diff --git a/src/qmaptool/CMakeLists.txt b/src/qmaptool/CMakeLists.txt
+new file mode 100644
+index 00000000..5fd64152
+--- /dev/null
++++ b/src/qmaptool/CMakeLists.txt
+@@ -0,0 +1,269 @@
++# Prevent custom commands/targets outputs to be deleted by make clean
++# We need this to prevent .ts files from being deleted with make clean, when
++# UPDATE_TRANSLATIONS=ON
++# WARNING: Only works with Makefile generator.
++set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE)
++# Find includes in corresponding build directories
++set(CMAKE_INCLUDE_CURRENT_DIR ON)
++# Instruct CMake to run moc automatically when needed.
++set(CMAKE_AUTOMOC ON)
++
++###############################################################################################
++# Setup application name and version tags
++###############################################################################################
++
++set(APPLICATION_NAME qmaptool)
++set(QMAPTOOL_VERSION_MAJOR 1)
++set(QMAPTOOL_VERSION_MINOR 1)
++set(QMAPTOOL_VERSION_PATCH 1)
++
++add_definitions(
++ -DVER_MAJOR=${QMAPTOOL_VERSION_MAJOR}
++ -DVER_MINOR=${QMAPTOOL_VERSION_MINOR}
++ -DVER_STEP=${QMAPTOOL_VERSION_PATCH}
++ -DVER_TWEAK=${VERSION_SUFFIX}
++ -DAPPLICATION_NAME=${APPLICATION_NAME}
++)
++
++###############################################################################################
++# All source files needed to compile
++###############################################################################################
++set( SRCS
++ CAbout.cpp
++ canvas/CCanvas.cpp
++ canvas/CDrawContextPixel.cpp
++ canvas/CDrawContextProj.cpp
++ canvas/IDrawContext.cpp
++ CMainWindow.cpp
++ CSingleInstanceProxy.cpp
++ GeoMath.cpp
++ helpers/CDraw.cpp
++ helpers/CGdalFile.cpp
++ helpers/mitab.cpp
++ items/CItemCutMap.cpp
++ items/CItemFile.cpp
++ items/CItemListWidget.cpp
++ items/CItemMap.cpp
++ items/CItemMapLayer.cpp
++ items/CItemRefMap.cpp
++ items/CItemTreeWidget.cpp
++ items/IItem.cpp
++ main.cpp
++ overlay/COverlayCutMap.cpp
++ overlay/COverlayGridTool.cpp
++ overlay/COverlayRefMap.cpp
++ overlay/gridtool/CGridPlacer.cpp
++ overlay/gridtool/CGridPoint.cpp
++ overlay/gridtool/CGridSelArea.cpp
++ overlay/gridtool/CGridSetRef.cpp
++ overlay/IOverlay.cpp
++ overlay/refmap/CDialogRefPoint.cpp
++ overlay/refmap/COverlayRefMapPoint.cpp
++ overlay/refmap/CProjWizard.cpp
++ setup/CAppSetupLinux.cpp
++ setup/CAppSetupMac.cpp
++ setup/CAppSetupWin.cpp
++ setup/CCommandProcessor.cpp
++ setup/CLogHandler.cpp
++ setup/CSetupExtTools.cpp
++ setup/IAppSetup.cpp
++ shell/CShellCmd.cpp
++ shell/CShell.cpp
++ tool/export/CToolExportJnx.cpp
++ tool/CToolAddOverview.cpp
++ tool/CToolBox.cpp
++ tool/CToolCutMap.cpp
++ tool/CToolExport.cpp
++ tool/CToolGrid.cpp
++ tool/CToolOverviewGroupBox.cpp
++ tool/CToolPalettize.cpp
++ tool/CToolRefMap.cpp
++ tool/CToolStack.cpp
++ tool/ITool.cpp
++ tool/IToolGui.cpp
++ units/CCoordFormatSetup.cpp
++ units/CTimeZoneSetup.cpp
++ units/CUnitImperial.cpp
++ units/CUnitMetric.cpp
++ units/CUnitNautic.cpp
++ units/CUnitsSetup.cpp
++ units/IUnit.cpp
++)
++
++set( HDRS
++ CAbout.h
++ canvas/CCanvas.h
++ canvas/CDrawContextPixel.h
++ canvas/CDrawContextProj.h
++ canvas/IDrawContext.h
++ CMainWindow.h
++ CSingleInstanceProxy.h
++ GeoMath.h
++ helpers/CDraw.h
++ helpers/CGdalFile.h
++ helpers/CSettings.h
++ helpers/CSettings.h
++ helpers/mitab.h
++ items/CItemCutMap.h
++ items/CItemFile.h
++ items/CItemListWidget.h
++ items/CItemMap.h
++ items/CItemMapLayer.h
++ items/CItemRefMap.h
++ items/CItemTreeWidget.h
++ items/IItem.h
++ overlay/COverlayCutMap.h
++ overlay/COverlayGridTool.h
++ overlay/COverlayRefMap.h
++ overlay/gridtool/CGridPlacer.h
++ overlay/gridtool/CGridPoint.h
++ overlay/gridtool/CGridSelArea.h
++ overlay/gridtool/CGridSetRef.h
++ overlay/IOverlay.h
++ overlay/refmap/CDialogRefPoint.h
++ overlay/refmap/COverlayRefMapPoint.h
++ overlay/refmap/CProjWizard.h
++ setup/CAppOpts.h
++ setup/CAppSetupLinux.h
++ setup/CAppSetupMac.h
++ setup/CAppSetupWin.h
++ setup/CCommandProcessor.h
++ setup/CLogHandler.h
++ setup/CSetupExtTools.h
++ setup/IAppSetup.h
++ shell/CShellCmd.h
++ shell/CShell.h
++ tool/export/CToolExportJnx.h
++ tool/CToolAddOverview.h
++ tool/CToolBox.h
++ tool/CToolCutMap.h
++ tool/CToolExport.h
++ tool/CToolGrid.h
++ tool/CToolOverviewGroupBox.h
++ tool/CToolPalettize.h
++ tool/CToolRefMap.h
++ tool/CToolStack.h
++ tool/IToolGui.h
++ tool/ITool.h
++ units/CCoordFormatSetup.h
++ units/CTimeZoneSetup.h
++ units/CUnitImperial.h
++ units/CUnitMetric.h
++ units/CUnitNautic.h
++ units/CUnitsSetup.h
++ units/IUnit.h
++ version.h
++)
++
++set( UIS
++ IAbout.ui
++ IMainWindow.ui
++ items/IItemListWidget.ui
++ items/IItemTreeWidget.ui
++ overlay/gridtool/IGridPlacer.ui
++ overlay/gridtool/IGridSelArea.ui
++ overlay/gridtool/IGridSetRef.ui
++ overlay/IOverlayCutMap.ui
++ overlay/IOverlayGridTool.ui
++ overlay/IOverlayRefMap.ui
++ overlay/refmap/IDialogRefPoint.ui
++ overlay/refmap/IProjWizard.ui
++ setup/ISetupExtTools.ui
++ tool/export/IToolExportJnx.ui
++ tool/IToolAddOverview.ui
++ tool/IToolCutMap.ui
++ tool/IToolExport.ui
++ tool/IToolGrid.ui
++ tool/IToolOverviewGroupBox.ui
++ tool/IToolPalettize.ui
++ tool/IToolRefMap.ui
++ units/ICoordFormatSetup.ui
++ units/ITimeZoneSetup.ui
++ units/IUnitsSetup.ui
++)
++
++
++set( RCS
++ resources.qrc
++)
++
++
++###############################################################################################
++# Some Qt magic
++###############################################################################################
++
++qt5_wrap_ui(UI_HDRS ${UIS})
++qt5_add_resources(RC_SRCS ${RCS})
++
++###############################################################################################
++# Translation related stuff
++###############################################################################################
++translate_ts(${APPLICATION_NAME}_QM_FILES
++ UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS}
++ UPDATE_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}" ${KEEP_OLD_TRANSLATIONS}
++ SOURCES ${SRCS} ${HDRS} ${UIS}
++ TEMPLATE ${APPLICATION_NAME}
++ TRANSLATION_DIR "locale"
++)
++
++if (UNIX AND NOT WIN32 AND NOT APPLE)
++ translate_desktop(${APPLICATION_NAME}_DESKTOP_FILES
++ TRANSLATION_DIR "locale"
++ SOURCES "${PROJECT_SOURCE_DIR}/qmaptool.desktop.in"
++ )
++endif()
++
++###############################################################################################
++# Build source file and include paths lists
++###############################################################################################
++set(MAININP
++ ${SRCS}
++ ${HDRS}
++ ${UI_HDRS}
++ ${RC_SRCS}
++ ${${APPLICATION_NAME}_QM_FILES}
++ ${${APPLICATION_NAME}_DESKTOP_FILES}
++)
++
++include_directories(
++ SYSTEM # this prevents warnings from non-QMS headers
++ ${CMAKE_BINARY_DIR}
++ ${GDAL_INCLUDE_DIRS}
++ ${PROJ4_INCLUDE_DIRS}
++)
++
++if(APPLE)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework)
++endif(APPLE)
++
++
++###############################################################################################
++# Build the executable and define necessary libraries.
++###############################################################################################
++add_executable(${APPLICATION_NAME} WIN32 ${MAININP})
++
++target_link_libraries(${APPLICATION_NAME}
++ Qt5::Widgets
++ Qt5::Network
++ ${GDAL_LIBRARIES}
++ ${PROJ4_LIBRARIES}
++)
++
++if(APPLE)
++ target_link_libraries(${APPLICATION_NAME}
++ ${Foundation_LIBRARY}
++ ${DiskArbitration_LIBRARY}
++ )
++endif(APPLE)
++
++
++###############################################################################################
++# Install target related stuff
++###############################################################################################
++install(TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR})
++
++if (UNIX AND NOT WIN32 AND NOT APPLE)
++ install(FILES ${${APPLICATION_NAME}_QM_FILES} DESTINATION ${DATA_INSTALL_PREFIX}/${APPLICATION_NAME}/translations)
++ install(FILES ${${APPLICATION_NAME}_DESKTOP_FILES} DESTINATION ${XDG_APPS_DIR})
++endif (UNIX AND NOT WIN32 AND NOT APPLE)
+diff --git a/src/qmaptool/CSingleInstanceProxy.cpp b/src/qmaptool/CSingleInstanceProxy.cpp
+new file mode 100644
+index 00000000..58cc933e
+--- /dev/null
++++ b/src/qmaptool/CSingleInstanceProxy.cpp
+@@ -0,0 +1,102 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "CSingleInstanceProxy.h"
++#include <QtNetwork>
++
++CSingleInstanceProxy::CSingleInstanceProxy(const QStringList filenames)
++{
++ serverName = CMainWindow::self().getUser();
++ if(serverName != "QMapTool")
++ {
++ serverName = "QMapTool-" + serverName;
++ }
++
++ QLocalSocket socket;
++ socket.connectToServer(serverName);
++ if(socket.waitForConnected(1000))
++ {
++ // if the connection is successful another instance
++ // is already running. In that case the list of files to
++ // open is sent to the primary instance. And this instance
++ // will be closed imediately.
++ QDataStream stream(&socket);
++ stream << filenames;
++ socket.waitForBytesWritten(3000);
++
++ // wait for confirmation
++ socket.waitForReadyRead(3000);
++ bool ok;
++ stream >> ok;
++ qDebug() << "Sent parameters to primary instance. Result" << ok;
++ qDebug() << "There can only be one. Exit.";
++ exit(0);
++ }
++
++ // Looks like we are the first instance.
++ // Create a server socket and wait for other instances to connect.
++ server = new QLocalServer(this);
++ connect(server, &QLocalServer::newConnection, this, &CSingleInstanceProxy::slotNewConnection);
++ server->removeServer(serverName);
++ if(!server->listen(serverName))
++ {
++ qDebug() << "CSingleInstanceProxy: Failed to start single instance server socket.";
++ }
++ else
++ {
++ qDebug() << "CSingleInstanceProxy: Single instance server socket listening to" << server->fullServerName();
++ }
++}
++
++CSingleInstanceProxy::~CSingleInstanceProxy()
++{
++ qDebug() << "CSingleInstanceProxy::~CSingleInstanceProxy()";
++}
++
++void CSingleInstanceProxy::slotNewConnection()
++{
++ QLocalSocket * socket = server->nextPendingConnection();
++ if(socket == nullptr)
++ {
++ return;
++ }
++
++ // Each secondary instance will send a QStringList with files to open
++ // The list can be empty.
++ if(socket->waitForReadyRead(3000))
++ {
++ QStringList filenames;
++ QDataStream stream(socket);
++ stream >> filenames;
++
++ CMainWindow& w = CMainWindow::self();
++ //w.loadGISData(filenames);
++
++ // confirm that files are loaded
++ stream << true;
++ socket->waitForBytesWritten(3000);
++
++ // raise the application window to top of desktop
++ w.raise();
++ QApplication::setActiveWindow(&w);
++ }
++
++ socket->close();
++ delete socket;
++}
+diff --git a/src/qmaptool/CSingleInstanceProxy.h b/src/qmaptool/CSingleInstanceProxy.h
+new file mode 100644
+index 00000000..c211c8cb
+--- /dev/null
++++ b/src/qmaptool/CSingleInstanceProxy.h
+@@ -0,0 +1,41 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CSINGLEINSTANCEPROXY_H
++#define CSINGLEINSTANCEPROXY_H
++
++#include <QObject>
++class QLocalServer;
++
++class CSingleInstanceProxy : public QObject
++{
++public:
++ CSingleInstanceProxy(const QStringList filenames);
++ virtual ~CSingleInstanceProxy();
++
++private slots:
++ void slotNewConnection();
++
++private:
++ QLocalServer * server = nullptr;
++
++ QString serverName;
++};
++
++#endif //CSINGLEINSTANCEPROXY_H
++
+diff --git a/src/qmaptool/GeoMath.cpp b/src/qmaptool/GeoMath.cpp
+new file mode 100644
+index 00000000..00596006
+--- /dev/null
++++ b/src/qmaptool/GeoMath.cpp
+@@ -0,0 +1,54 @@
++/**********************************************************************************************
++ Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++
++**********************************************************************************************/
++
++#include "GeoMath.h"
++
++#define PI M_PI
++#define TWOPI (2*PI)
++
++
++void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal &deg)
++{
++ deg = qAbs(d) + qreal(m) / 60.0 + s / 3600;
++ if(sign)
++ {
++ deg = -deg;
++ }
++}
++
++
++bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min)
++{
++ *deg = qAbs(v);
++ *min = (qAbs(v) - *deg) * 60.0;
++
++ return v < 0;
++}
++
++
++void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg)
++{
++ deg = qAbs(d) + m / 60.0;
++ if(sign)
++ {
++ deg = -deg;
++ }
++}
++
++
+diff --git a/src/qmaptool/GeoMath.h b/src/qmaptool/GeoMath.h
+new file mode 100644
+index 00000000..7f48a1fe
+--- /dev/null
++++ b/src/qmaptool/GeoMath.h
+@@ -0,0 +1,31 @@
++/**********************************************************************************************
++ Copyright (C) 2009 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++
++**********************************************************************************************/
++
++#ifndef GEOMATH_H
++#define GEOMATH_H
++
++#include <QtGlobal>
++#include <stdint.h>
++
++void GPS_Math_DegMin_To_Deg(bool sign, const qint32 d, const qreal m, qreal& deg);
++void GPS_Math_DegMinSec_To_Deg(bool sign, const qint32 d, const qint32 m, const qreal s, qreal& deg);
++bool GPS_Math_Deg_To_DegMin(qreal v, qint32 *deg, qreal *min);
++
++#endif //GEOMATH_H
++
+diff --git a/src/qmaptool/IAbout.ui b/src/qmaptool/IAbout.ui
+new file mode 100644
+index 00000000..17d509bd
+--- /dev/null
++++ b/src/qmaptool/IAbout.ui
+@@ -0,0 +1,164 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IAbout</class>
++ <widget class="QDialog" name="IAbout">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>418</width>
++ <height>407</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>About...</string>
++ </property>
++ <property name="windowIcon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/QMapTool.png</normaloff>:/icons/32x32/QMapTool.png</iconset>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>&lt;b&gt;QMapTool&lt;/b&gt;, Version</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelVersion">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="resources.qrc">:/icons/48x48/QMapTool.png</pixmap>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="Line" name="line">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QFormLayout" name="formLayout">
++ <property name="fieldGrowthPolicy">
++ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
++ </property>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label_5">
++ <property name="text">
++ <string>Qt</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="QLabel" name="labelQtVersion">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_6">
++ <property name="text">
++ <string>GDAL</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QLabel" name="labelGDALVersion">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="0">
++ <widget class="QLabel" name="label_7">
++ <property name="text">
++ <string>Proj4</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="1">
++ <widget class="QLabel" name="labelProj4Version">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="Line" name="line_2">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_35">
++ <property name="text">
++ <string>This software is licensed under GPL3 or any later version</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_36">
++ <property name="text">
++ <string>© 2017 Oliver Eichler (oliver.eichler@gmx.de)</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="resources.qrc">:/pic/splash.png</pixmap>
++ </property>
++ <property name="scaledContents">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/IMainWindow.ui b/src/qmaptool/IMainWindow.ui
+new file mode 100644
+index 00000000..6b11c3bb
+--- /dev/null
++++ b/src/qmaptool/IMainWindow.ui
+@@ -0,0 +1,208 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IMainWindow</class>
++ <widget class="QMainWindow" name="IMainWindow">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>800</width>
++ <height>600</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>MainWindow</string>
++ </property>
++ <property name="windowIcon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/48x48/QMapTool.png</normaloff>:/icons/48x48/QMapTool.png</iconset>
++ </property>
++ <widget class="CCanvas" name="canvas"/>
++ <widget class="QMenuBar" name="menubar">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>800</width>
++ <height>23</height>
++ </rect>
++ </property>
++ <widget class="QMenu" name="menuSetup">
++ <property name="title">
++ <string>Setup</string>
++ </property>
++ <addaction name="actionSetupExtTools"/>
++ <addaction name="actionSetupUnits"/>
++ <addaction name="actionSetupCoordFormat"/>
++ <addaction name="actionShowToolHelp"/>
++ </widget>
++ <widget class="QMenu" name="menuView">
++ <property name="title">
++ <string>View</string>
++ </property>
++ <addaction name="actionFlipMouseWheel"/>
++ </widget>
++ <widget class="QMenu" name="menuWindow">
++ <property name="title">
++ <string>Window</string>
++ </property>
++ </widget>
++ <widget class="QMenu" name="menu">
++ <property name="title">
++ <string>?</string>
++ </property>
++ <addaction name="actionAbout"/>
++ </widget>
++ <addaction name="menuSetup"/>
++ <addaction name="menuView"/>
++ <addaction name="menuWindow"/>
++ <addaction name="menu"/>
++ </widget>
++ <widget class="QStatusBar" name="statusbar"/>
++ <widget class="QDockWidget" name="dockTools">
++ <property name="features">
++ <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetVerticalTitleBar</set>
++ </property>
++ <property name="windowTitle">
++ <string>Tools</string>
++ </property>
++ <attribute name="dockWidgetArea">
++ <number>1</number>
++ </attribute>
++ <widget class="QWidget" name="dockWidgetContents">
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="spacing">
++ <number>0</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="CToolStack" name="toolStack"/>
++ </item>
++ </layout>
++ </widget>
++ </widget>
++ <widget class="QDockWidget" name="dockShell">
++ <property name="features">
++ <set>QDockWidget::DockWidgetFeatureMask</set>
++ </property>
++ <property name="windowTitle">
++ <string>Shell</string>
++ </property>
++ <attribute name="dockWidgetArea">
++ <number>8</number>
++ </attribute>
++ <widget class="QWidget" name="dockWidgetContents_3">
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <widget class="CShell" name="textBrowser"/>
++ </item>
++ </layout>
++ </widget>
++ </widget>
++ <action name="actionAbout">
++ <property name="icon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/Info.png</normaloff>:/icons/32x32/Info.png</iconset>
++ </property>
++ <property name="text">
++ <string>About</string>
++ </property>
++ </action>
++ <action name="actionSetupExtTools">
++ <property name="icon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ <property name="text">
++ <string>Ext. Tools</string>
++ </property>
++ <property name="toolTip">
++ <string>Setup paths to external tools, like gdalwarp etc.</string>
++ </property>
++ </action>
++ <action name="actionFlipMouseWheel">
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="icon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/MouseWheel.png</normaloff>:/icons/32x32/MouseWheel.png</iconset>
++ </property>
++ <property name="text">
++ <string>Flip Mouse Wheel</string>
++ </property>
++ <property name="toolTip">
++ <string>Flip Mouse Wheel</string>
++ </property>
++ </action>
++ <action name="actionSetupUnits">
++ <property name="icon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/UnitSetup.png</normaloff>:/icons/32x32/UnitSetup.png</iconset>
++ </property>
++ <property name="text">
++ <string>Setup Units</string>
++ </property>
++ <property name="toolTip">
++ <string>Setup Units</string>
++ </property>
++ </action>
++ <action name="actionSetupCoordFormat">
++ <property name="icon">
++ <iconset resource="resources.qrc">
++ <normaloff>:/icons/32x32/SetupCoordFormat.png</normaloff>:/icons/32x32/SetupCoordFormat.png</iconset>
++ </property>
++ <property name="text">
++ <string>Setup Coord. Format</string>
++ </property>
++ <property name="toolTip">
++ <string>Change the format coordinates are displayed</string>
++ </property>
++ </action>
++ <action name="actionShowToolHelp">
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ <property name="text">
++ <string>Show Tool Help</string>
++ </property>
++ </action>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CShell</class>
++ <extends>QTextBrowser</extends>
++ <header>shell/CShell.h</header>
++ </customwidget>
++ <customwidget>
++ <class>CCanvas</class>
++ <extends>QWidget</extends>
++ <header>canvas/CCanvas.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CToolStack</class>
++ <extends>QStackedWidget</extends>
++ <header>tool/CToolStack.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/README.md b/src/qmaptool/README.md
+new file mode 100644
+index 00000000..2db8ed98
+--- /dev/null
++++ b/src/qmaptool/README.md
+@@ -0,0 +1,7 @@
++# README #
++
++This is a sub-project of QMapShack and it's not supposed to compile on it's own. Please refere to
++
++https://bitbucket.org/maproom/qmapshack/overview
++
++to check out and compile this project.
+\ No newline at end of file
+diff --git a/src/qmaptool/canvas/CCanvas.cpp b/src/qmaptool/canvas/CCanvas.cpp
+new file mode 100644
+index 00000000..11b65e54
+--- /dev/null
++++ b/src/qmaptool/canvas/CCanvas.cpp
+@@ -0,0 +1,189 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CCanvas.h"
++#include "canvas/IDrawContext.h"
++#include "helpers/CDraw.h"
++
++
++#include <QtWidgets>
++
++CCanvas::CCanvas(QWidget *parent)
++ : QWidget(parent)
++{
++ setFocusPolicy(Qt::WheelFocus);
++ setMouseTracking(true);
++
++ loadIndicator1 = new QMovie("://animation/loader.gif", QByteArray(), this);
++ mapLoadIndicator = new QLabel(this);
++ mapLoadIndicator->setMovie(loadIndicator1);
++ loadIndicator1->start();
++ mapLoadIndicator->show();
++}
++
++void CCanvas::setOverrideCursor(const QCursor &cursor, const QString&)
++{
++// qDebug() << "setOverrideCursor" << src;
++ QApplication::setOverrideCursor(cursor);
++}
++
++void CCanvas::restoreOverrideCursor(const QString& src)
++{
++// qDebug() << "restoreOverrideCursor" << src;
++ QApplication::restoreOverrideCursor();
++}
++
++void CCanvas::changeOverrideCursor(const QCursor& cursor, const QString &src)
++{
++// qDebug() << "changeOverrideCursor" << src;
++ QApplication::changeOverrideCursor(cursor);
++}
++
++
++void CCanvas::resizeEvent(QResizeEvent *e)
++{
++ QMutexLocker lock(&mutex);
++
++ needsRedraw = eRedrawAll;
++
++ // move map loading indicator to new center of canvas
++ QPoint p1(mapLoadIndicator->width()>>1, mapLoadIndicator->height()>>1);
++ mapLoadIndicator->move(rect().center() - p1);
++
++ emit sigChangedSize(e->size());
++
++ QWidget::resizeEvent(e);
++}
++
++void CCanvas::paintEvent(QPaintEvent *e)
++{
++ QPainter p;
++ p.begin(this);
++ USE_ANTI_ALIASING(p,true);
++
++ // fill the background with default pattern
++ p.fillRect(rect(), backColor);
++
++ // ----- start to draw thread based content -----
++
++ mutex.lock();
++ if(!tool->drawFx(p,needsRedraw))
++ {
++ mutex.unlock();
++ slotHideLoadIndicator();
++ CDraw::text(tr("No map view available."), p, rect(), Qt::black);
++ mutex.lock();
++ }
++ mutex.unlock();
++ // ----- start to draw fast content -----
++ p.end();
++ needsRedraw = eRedrawNone;
++}
++
++void CCanvas::mousePressEvent(QMouseEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ tool->mousePressEventFx(e);
++ e->accept();
++}
++
++void CCanvas::mouseMoveEvent(QMouseEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ tool->mouseMoveEventFx(e);
++ e->accept();
++}
++
++void CCanvas::mouseReleaseEvent(QMouseEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ tool->mouseReleaseEventFx(e);
++ e->accept();
++}
++
++void CCanvas::mouseDoubleClickEvent(QMouseEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ tool->mouseDoubleClickEventFx(e);
++ e->accept();
++}
++
++void CCanvas::wheelEvent(QWheelEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ tool->wheelEventFx(e);
++}
++
++void CCanvas::enterEvent(QEvent *e)
++{
++ QMutexLocker lock(&mutex);
++
++ tool->enterEventFx(e);
++ CCanvas::setOverrideCursor(tool->getCursorFx(), "enterEvent");
++
++ setMouseTracking(true);
++}
++
++void CCanvas::leaveEvent(QEvent *e)
++{
++ QMutexLocker lock(&mutex);
++
++ tool->leaveEventFx(e);
++
++ // bad hack to stop bad number of override cursors.
++ while(QApplication::overrideCursor())
++ {
++ CCanvas::restoreOverrideCursor("leaveEvent");
++ }
++
++
++ setMouseTracking(false);
++}
++
++void CCanvas::keyPressEvent(QKeyEvent *e)
++{
++ QMutexLocker lock(&mutex);
++ if(!tool->keyPressEventFx(e))
++ {
++ e->ignore();
++ }
++}
++
++
++void CCanvas::slotTriggerCompleteUpdate(CCanvas::redraw_e flags)
++{
++ needsRedraw = (redraw_e)(needsRedraw | flags);
++ update();
++}
++
++void CCanvas::slotShowLoadIndicator()
++{
++ QMutexLocker lock(&mutex);
++ mapLoadIndicator->show();
++ mapLoadIndicatorCount++;
++}
++
++void CCanvas::slotHideLoadIndicator()
++{
++ QMutexLocker lock(&mutex);
++ if(--mapLoadIndicatorCount <= 0)
++ {
++ mapLoadIndicator->hide();
++ mapLoadIndicatorCount = 0;
++ }
++}
+diff --git a/src/qmaptool/canvas/CCanvas.h b/src/qmaptool/canvas/CCanvas.h
+new file mode 100644
+index 00000000..552085ea
+--- /dev/null
++++ b/src/qmaptool/canvas/CCanvas.h
+@@ -0,0 +1,92 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CCANVAS_H
++#define CCANVAS_H
++
++#include <QLabel>
++#include <QMovie>
++#include <QMutex>
++#include <QPointer>
++#include <QWidget>
++
++class ITool;
++class CMainWindow;
++class QStackedWidget;
++
++class CCanvas : public QWidget
++{
++ Q_OBJECT
++public:
++ CCanvas(QWidget *parent);
++ virtual ~CCanvas() = default;
++
++ static void setOverrideCursor(const QCursor &cursor, const QString&);
++ static void restoreOverrideCursor(const QString &src);
++ static void changeOverrideCursor(const QCursor& cursor, const QString &src);
++
++ enum redraw_e
++ {
++ eRedrawNone = 0
++ , eRedrawMap = 0x01
++ , eRedrawOverlay = 0x08
++ , eRedrawAll = 0xFFFFFFFF
++ };
++
++ void setToolInterface(ITool * t)
++ {
++ tool = t;
++ }
++
++signals:
++ void sigChangedSize(const QSize& size);
++
++public slots:
++ void slotTriggerCompleteUpdate(CCanvas::redraw_e flags);
++
++ void slotShowLoadIndicator();
++ void slotHideLoadIndicator();
++
++protected:
++ void resizeEvent(QResizeEvent *e) override;
++ void paintEvent(QPaintEvent *e) override;
++ void mousePressEvent(QMouseEvent *e) override;
++ void mouseMoveEvent(QMouseEvent *e) override;
++ void mouseReleaseEvent(QMouseEvent *e) override;
++ void mouseDoubleClickEvent(QMouseEvent *e) override;
++ void wheelEvent(QWheelEvent *e) override;
++ void enterEvent(QEvent *e) override;
++ void leaveEvent(QEvent *e) override;
++ void keyPressEvent(QKeyEvent *e) override;
++
++private:
++ mutable QMutex mutex {QMutex::Recursive};
++
++ QColor backColor = "#FFFFBF"; //< the background color used in case of missing map tiles
++ redraw_e needsRedraw = eRedrawAll; //< set true to initiate a complete redraw of the screen content
++
++ /// load indicator for maps
++ QMovie * loadIndicator1;
++ QLabel * mapLoadIndicator;
++ qint32 mapLoadIndicatorCount = 0;
++
++ ITool * tool = nullptr;
++};
++
++#endif //CCANVAS_H
++
+diff --git a/src/qmaptool/canvas/CDrawContextPixel.cpp b/src/qmaptool/canvas/CDrawContextPixel.cpp
+new file mode 100644
+index 00000000..a28c383e
+--- /dev/null
++++ b/src/qmaptool/canvas/CDrawContextPixel.cpp
+@@ -0,0 +1,168 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CDrawContextPixel.h"
++#include "helpers/CDraw.h"
++
++#include <gdal_priv.h>
++#include <ogr_spatialref.h>
++#include <QtWidgets>
++
++CDrawContextPixel::CDrawContextPixel(CCanvas *canvas, QObject * parent)
++ : IDrawContext(canvas, parent)
++{
++ scale = QPointF(1.0, 1.0);
++}
++
++CDrawContextPixel::~CDrawContextPixel()
++{
++ unload();
++}
++
++void CDrawContextPixel::convertMap2Coord(QPointF &pt) const
++{
++ pt = trFwd.map(pt);
++}
++
++void CDrawContextPixel::convertCoord2Map(QPointF &pt) const
++{
++ pt = trInv.map(pt);
++}
++
++
++void CDrawContextPixel::setSourceFile(const QString& filename, bool resetContext)
++{
++ unload();
++
++ if(resetContext)
++ {
++ focus = QPointF(0,0);
++ zoom(6);
++ }
++
++ if(filename.isEmpty())
++ {
++ return;
++ }
++
++ load(filename);
++
++ intNeedsRedraw = true;
++}
++
++void CDrawContextPixel::drawt(buffer_t& buf)
++{
++ QPainter p(&buf.image);
++
++ if(needsRedraw() || (dataset == nullptr) || (isValid == false))
++ {
++ CDraw::text(tr("Failed to load"), p, canvas->rect(), Qt::black);
++ return;
++ }
++
++ // calculate area to read from file
++ QPointF pt1 = buf.ref1;
++ QPointF pt2 = buf.ref2;
++ QPointF pt4 = buf.ref4;
++
++ pt1.rx() = qMax(pt1.x(), 0.0);
++ pt1.rx() = qMin(pt1.x(), xsize_px);
++
++ pt2.rx() = qMax(pt2.x(), 0.0);
++ pt2.rx() = qMin(pt2.x(), xsize_px);
++
++ pt1.ry() = qMax(pt1.y(), 0.0);
++ pt1.ry() = qMin(pt1.y(), ysize_px);
++
++ pt4.ry() = qMax(pt4.y(), 0.0);
++ pt4.ry() = qMin(pt4.y(), ysize_px);
++
++ qint32 mapWidth = qRound(pt2.x() - pt1.x());
++ qint32 mapHeight = qRound(pt4.y() - pt1.y());
++ QPointF mapOff = pt1;
++
++ convertMap2Screen(pt1);
++ convertMap2Screen(pt2);
++ convertMap2Screen(pt4);
++
++ qint32 screenWidth = qRound(pt2.x() - pt1.x()) & 0xFFFFFFFC;
++ qint32 screenHeight = qRound(pt4.y() - pt1.y());
++ QPointF screenOff = pt1;
++
++
++ // start to draw the map
++ QImage img;
++ QVector<quint8> buffer(screenWidth * screenHeight, 0);
++
++ CPLErr err = CE_Failure;
++
++ if(rasterBandCount == 1)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(1);
++
++ img = QImage(screenWidth,screenHeight,QImage::Format_Indexed8);
++ img.setColorTable(colortable);
++
++ mutex.lock();
++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, img.bits(), screenWidth, screenHeight, GDT_Byte, 0, 0);
++ mutex.unlock();
++ }
++ else
++ {
++ const QRgb testPix = qRgba(GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand);
++ img = QImage(screenWidth, screenHeight, QImage::Format_ARGB32);
++ // fill alpha channel of image buffer
++ img.fill(Qt::white);
++
++ // read map band by band and copy color values into the image buffer
++ for(int b = 1; b <= rasterBandCount; ++b)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(b);
++
++ mutex.lock();
++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, buffer.data(), screenWidth, screenHeight, GDT_Byte, 0, 0);
++ mutex.unlock();
++ if(err == CE_None)
++ {
++ int pbandColour = pBand->GetColorInterpretation();
++ unsigned int offset;
++
++ for (offset = 0; offset < sizeof(testPix) && *(((quint8 *)&testPix) + offset) != pbandColour; offset++)
++ {
++ }
++ if(offset < sizeof(testPix))
++ {
++ quint8 * pTar = img.bits() + offset;
++ quint8 * pSrc = buffer.data();
++ const int size = buffer.size();
++
++ for(int i = 0; i < size; ++i)
++ {
++ *pTar = *pSrc;
++ pTar += sizeof(testPix);
++ pSrc += 1;
++ }
++ }
++ }
++ }
++ }
++
++ p.drawImage(screenOff, img);
++}
+diff --git a/src/qmaptool/canvas/CDrawContextPixel.h b/src/qmaptool/canvas/CDrawContextPixel.h
+new file mode 100644
+index 00000000..7ebc598f
+--- /dev/null
++++ b/src/qmaptool/canvas/CDrawContextPixel.h
+@@ -0,0 +1,91 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CDRAWCONTEXTPIXEL_H
++#define CDRAWCONTEXTPIXEL_H
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CGdalFile.h"
++
++class GDALDataset;
++
++
++class CDrawContextPixel : public IDrawContext, public CGdalFile
++{
++ Q_OBJECT
++public:
++ CDrawContextPixel(CCanvas *canvas, QObject *parent);
++ virtual ~CDrawContextPixel();
++
++ void setSourceFile(const QString& filename, bool resetContext) override;
++
++ void unload() override
++ {
++ CGdalFile::unload();
++ }
++
++ bool getIsValid() const override
++ {
++ return isValid;
++ }
++
++ const QString& getProjection() const override
++ {
++ return proj4str;
++ }
++
++ const QTransform& getTrFwd() const override
++ {
++ return trFwd;
++ }
++
++ bool getNoData() const override
++ {
++ return hasNoData != -1;
++ }
++
++ int getRasterBandCount() const override
++ {
++ return rasterBandCount;
++ }
++
++ QString getInfo() const override
++ {
++ return CGdalFile::getInfo();
++ }
++
++ bool is32BitRgb() const override
++ {
++ return rasterBandCount >= 3;
++ }
++
++
++ QRectF getMapArea() const override
++ {
++ return QRectF(0,0, xsize_px, ysize_px);
++ }
++
++ void convertMap2Coord(QPointF &pt) const override;
++ void convertCoord2Map(QPointF &pt) const override;
++
++protected:
++ void drawt(buffer_t& buf) override;
++};
++
++#endif //CDRAWCONTEXTPIXEL_H
++
+diff --git a/src/qmaptool/canvas/CDrawContextProj.cpp b/src/qmaptool/canvas/CDrawContextProj.cpp
+new file mode 100644
+index 00000000..c2ac302a
+--- /dev/null
++++ b/src/qmaptool/canvas/CDrawContextProj.cpp
+@@ -0,0 +1,166 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CDrawContextProj.h"
++#include "helpers/CDraw.h"
++
++#include <gdal_priv.h>
++#include <QtWidgets>
++
++CDrawContextProj::CDrawContextProj(CCanvas *canvas, QObject *parent)
++ : IDrawContext(canvas, parent)
++{
++}
++
++void CDrawContextProj::setSourceFile(const QString& filename, bool resetContext)
++{
++ unload();
++
++ if(resetContext)
++ {
++ focus = QPointF(0,0);
++ zoom(6);
++ }
++
++ if(filename.isEmpty())
++ {
++ return;
++ }
++
++ load(filename);
++
++ if(resetContext)
++ {
++ convertMap2Coord(focus);
++ }
++
++ intNeedsRedraw = true;
++}
++
++void CDrawContextProj::convertMap2Coord(QPointF &pt) const
++{
++ pt = trFwd.map(pt);
++}
++
++void CDrawContextProj::convertCoord2Map(QPointF &pt) const
++{
++ pt = trInv.map(pt);
++}
++
++
++void CDrawContextProj::drawt(buffer_t& buf)
++{
++ QPainter p(&buf.image);
++
++ if(needsRedraw() || (dataset == nullptr) || (isValid == false))
++ {
++ CDraw::text(tr("Failed to load"), p, canvas->rect(), Qt::black);
++ return;
++ }
++
++ // calculate area to read from file
++ QPointF pt1 = buf.ref1;
++ QPointF pt3 = buf.ref3;
++
++ pt1.rx() = qMax(CGdalFile::ref1.x(), pt1.x());
++ pt1.rx() = qMin(CGdalFile::ref2.x(), pt1.x());
++
++ pt1.ry() = qMin(CGdalFile::ref1.y(), pt1.y());
++ pt1.ry() = qMax(CGdalFile::ref3.y(), pt1.y());
++
++ pt3.rx() = qMax(CGdalFile::ref1.x(), pt3.x());
++ pt3.rx() = qMin(CGdalFile::ref2.x(), pt3.x());
++
++ pt3.ry() = qMin(CGdalFile::ref1.y(), pt3.y());
++ pt3.ry() = qMax(CGdalFile::ref3.y(), pt3.y());
++
++ convertCoord2Map(pt1);
++ convertCoord2Map(pt3);
++
++ qint32 mapWidth = qRound(pt3.x() - pt1.x());
++ qint32 mapHeight = qRound(pt3.y() - pt1.y());
++ QPointF mapOff = pt1;
++
++ convertMap2Screen(pt1);
++ convertMap2Screen(pt3);
++
++ qint32 screenWidth = qRound(pt3.x() - pt1.x()) & 0xFFFFFFFC;
++ qint32 screenHeight = qRound(pt3.y() - pt1.y());
++ QPointF screenOff = pt1;
++
++ // start to draw the map
++ QImage img;
++ QVector<quint8> buffer(screenWidth * screenHeight, 0);
++
++ CPLErr err = CE_Failure;
++
++ if(rasterBandCount == 1)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(1);
++
++ img = QImage(screenWidth,screenHeight,QImage::Format_Indexed8);
++ img.setColorTable(colortable);
++
++ mutex.lock();
++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, img.bits(), screenWidth, screenHeight, GDT_Byte, 0, 0);
++ mutex.unlock();
++ }
++ else
++ {
++ const QRgb testPix = qRgba(GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand);
++ img = QImage(screenWidth, screenHeight, QImage::Format_ARGB32);
++ // fill alpha channel of image buffer
++ img.fill(Qt::white);
++
++ // read map band by band and copy color values into the image buffer
++ for(int b = 1; b <= rasterBandCount; ++b)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(b);
++
++ mutex.lock();
++ err = pBand->RasterIO(GF_Read, mapOff.x(), mapOff.y(), mapWidth, mapHeight, buffer.data(), screenWidth, screenHeight, GDT_Byte, 0, 0);
++ mutex.unlock();
++ if(err == CE_None)
++ {
++ int pbandColour = pBand->GetColorInterpretation();
++ unsigned int offset;
++
++ for (offset = 0; offset < sizeof(testPix) && *(((quint8 *)&testPix) + offset) != pbandColour; offset++)
++ {
++ }
++ if(offset < sizeof(testPix))
++ {
++ quint8 * pTar = img.bits() + offset;
++ quint8 * pSrc = buffer.data();
++ const int size = buffer.size();
++
++ for(int i = 0; i < size; ++i)
++ {
++ *pTar = *pSrc;
++ pTar += sizeof(testPix);
++ pSrc += 1;
++ }
++ }
++ }
++ }
++ }
++
++ p.drawImage(screenOff, img);
++}
+diff --git a/src/qmaptool/canvas/CDrawContextProj.h b/src/qmaptool/canvas/CDrawContextProj.h
+new file mode 100644
+index 00000000..ecb10f92
+--- /dev/null
++++ b/src/qmaptool/canvas/CDrawContextProj.h
+@@ -0,0 +1,89 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CDRAWCONTEXTPROJ_H
++#define CDRAWCONTEXTPROJ_H
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CGdalFile.h"
++
++#include <proj_api.h>
++
++class CDrawContextProj : public IDrawContext, public CGdalFile
++{
++ Q_OBJECT
++public:
++ CDrawContextProj(CCanvas *canvas, QObject *parent);
++ virtual ~CDrawContextProj() = default;
++
++ void setSourceFile(const QString& filename, bool resetContext) override;
++
++ void unload() override
++ {
++ CGdalFile::unload();
++ }
++
++ bool getIsValid() const override
++ {
++ return isValid;
++ }
++
++ const QString& getProjection() const override
++ {
++ return proj4str;
++ }
++
++ const QTransform& getTrFwd() const override
++ {
++ return trFwd;
++ }
++
++ bool getNoData() const override
++ {
++ return hasNoData != -1;
++ }
++
++ int getRasterBandCount() const override
++ {
++ return rasterBandCount;
++ }
++
++ QString getInfo() const override
++ {
++ return CGdalFile::getInfo();
++ }
++
++ bool is32BitRgb() const override
++ {
++ return rasterBandCount >= 3;
++ }
++
++
++ QRectF getMapArea() const override
++ {
++ return QRectF(0,0, xsize_px, ysize_px);
++ }
++
++ void convertMap2Coord(QPointF &pt) const override;
++ void convertCoord2Map(QPointF &pt) const override;
++
++ void drawt(buffer_t& buf) override;
++};
++
++#endif //CDRAWCONTEXTPROJ_H
++
+diff --git a/src/qmaptool/canvas/IDrawContext.cpp b/src/qmaptool/canvas/IDrawContext.cpp
+new file mode 100644
+index 00000000..ce960e24
+--- /dev/null
++++ b/src/qmaptool/canvas/IDrawContext.cpp
+@@ -0,0 +1,300 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++
++#include <QtWidgets>
++
++#define N_DEFAULT_ZOOM_LEVELS 31
++const qreal IDrawContext::scales[N_DEFAULT_ZOOM_LEVELS] =
++{
++ 0.10, 0.15, 0.20, 0.30, 0.50, 0.70, 1.0, 1.5, 2.0, 3.0,
++ 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 50.0, 70.0, 100.0, 150.0,
++ 200.0, 300.0, 500.0, 700.0, 1000.0, 1500.0, 2000.0, 3000.0, 5000.0, 7000.0,
++ 10000.0
++ //, 15000.0, 20000.0, 30000.0, 50000.0, 70000.0
++};
++
++QPointF operator*(const QPointF& p1, const QPointF& p2)
++{
++ return QPointF(p1.x() * p2.x(), p1.y() * p2.y());
++}
++
++QPointF operator/(const QPointF& p1, const QPointF& p2)
++{
++ return QPointF(p1.x() / p2.x(), p1.y() / p2.y());
++}
++
++QMutex IDrawContext::mutex(QMutex::Recursive);
++
++
++IDrawContext::IDrawContext(CCanvas * canvas, QObject * parent)
++ : QThread(parent)
++ , canvas(canvas)
++{
++ init();
++}
++
++void IDrawContext::init()
++{
++ connect(this, &IDrawContext::finished, canvas, static_cast<void (CCanvas::*)()>(&CCanvas::update));
++ connect(this, &IDrawContext::started, canvas, &CCanvas::slotShowLoadIndicator);
++ connect(this, &IDrawContext::finished, canvas, &CCanvas::slotHideLoadIndicator);
++ connect(canvas, &CCanvas::sigChangedSize, this, &IDrawContext::slotResize);
++
++ slotResize(canvas->size());
++}
++
++
++void IDrawContext::saveSettings(QSettings& cfg) const
++{
++ QMutexLocker lock(&mutex);
++
++ cfg.beginGroup("DrawContext");
++ cfg.setValue("focus", focus);
++ cfg.setValue("zoomFactorIdx", zoomFactorIdx);
++ cfg.endGroup();
++}
++
++void IDrawContext::loadSettings(QSettings& cfg)
++{
++ QMutexLocker lock(&mutex);
++
++ cfg.beginGroup("DrawContext");
++ focus = cfg.value("focus", focus).toPointF();
++ zoomFactorIdx = cfg.value("zoomFactorIdx", zoomFactorIdx).toInt();
++ cfg.endGroup();
++
++ zoom(zoomFactorIdx);
++}
++
++
++void IDrawContext::slotResize(const QSize& size)
++{
++ if(isRunning())
++ {
++ wait();
++ }
++
++ QMutexLocker lock(&mutex);
++ viewWidth = size.width();
++ viewHeight = size.height();
++
++ bufWidth = viewWidth;
++ bufHeight = viewHeight;
++
++ buffer[0].image = QImage(qRound(bufWidth), qRound(bufHeight), QImage::Format_ARGB32);
++ buffer[1].image = QImage(qRound(bufWidth), qRound(bufHeight), QImage::Format_ARGB32);
++}
++
++bool IDrawContext::needsRedraw() const
++{
++ mutex.lock(); // --------- start serialize with thread
++ bool res = intNeedsRedraw;
++ mutex.unlock(); // --------- stop serialize with thread
++ return res;
++}
++
++void IDrawContext::convertScreen2Map(QPointF& pt) const
++{
++ mutex.lock(); // --------- start serialize with thread
++
++ QPointF f = focus;
++ convertCoord2Map(f);
++
++ pt = f + pt * scale * zoomFactor;
++
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::convertMap2Screen(QPointF& pt) const
++{
++ mutex.lock(); // --------- start serialize with thread
++
++ QPointF f = focus;
++ convertCoord2Map(f);
++
++ pt = (pt - f) / (scale * zoomFactor);
++
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::convertMap2Screen(QPolygonF& line) const
++{
++ mutex.lock(); // --------- start serialize with thread
++
++ const int N = line.size();
++ for(int n = 0; n < N; n++)
++ {
++ line[n] = (line[n] - focus) / (scale * zoomFactor);
++ }
++
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::convertMap2Screen(QRectF& rect) const
++{
++ mutex.lock(); // --------- start serialize with thread
++
++ QPointF topLeft = rect.topLeft();
++ convertMap2Screen(topLeft);
++ rect.setTopLeft(topLeft);
++
++ QPointF bottomRight = rect.bottomRight();
++ convertMap2Screen(bottomRight);
++ rect.setBottomRight(bottomRight);
++
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++
++void IDrawContext::move(const QPointF& delta)
++{
++ mutex.lock(); // --------- start serialize with thread
++ QPointF f = focus;
++
++ convertCoord2Map(f);
++ convertMap2Screen(f);
++ f -= delta;
++ convertScreen2Map(f);
++ convertMap2Coord(f);
++
++ focus = f;
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::zoom(bool in, const QPointF& pt)
++{
++ mutex.lock(); // --------- start serialize with thread
++
++ QPointF pt2 = pt;
++
++ convertScreen2Map(pt2);
++ zoom(zoomFactorIdx + (in ? -1 : 1));
++ convertMap2Screen(pt2);
++
++ move(pt - pt2);
++
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::zoom(int idx)
++{
++ idx = qMax(idx, 0);
++ idx = qMin(idx, N_DEFAULT_ZOOM_LEVELS - 1);
++
++ mutex.lock(); // --------- start serialize with thread
++ if((zoomFactorIdx != idx) || (zoomFactor.x() != scales[idx]))
++ {
++ zoomFactorIdx = idx;
++ zoomFactor.rx() = scales[idx];
++ zoomFactor.ry() = scales[idx];
++ intNeedsRedraw = true;
++ }
++ mutex.unlock(); // --------- stop serialize with thread
++}
++
++void IDrawContext::draw(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ mutex.lock(); // --------- start serialize with thread
++ // derive map reference points for all corners coordinate of map buffer
++ ref1 = QPointF( 0, 0);
++ ref2 = QPointF( bufWidth, 0);
++ ref3 = QPointF( bufWidth, bufHeight);
++ ref4 = QPointF( 0, bufHeight);
++
++ convertScreen2Map(ref1);
++ convertScreen2Map(ref2);
++ convertScreen2Map(ref3);
++ convertScreen2Map(ref4);
++
++ convertMap2Coord(ref1);
++ convertMap2Coord(ref2);
++ convertMap2Coord(ref3);
++ convertMap2Coord(ref4);
++
++ // get current active buffer
++ const buffer_t& currentBuffer = buffer[bufIndex];
++
++ // calculate screen offset of current buffer
++ QPointF offset = currentBuffer.ref1;
++ convertCoord2Map(offset);
++ convertMap2Screen(offset);
++
++ p.save();
++ // add offset
++ p.translate(offset);
++ // scale image if current zoomfactor does not match buffer's zoomfactor
++ p.scale(currentBuffer.zoomFactor.x()/zoomFactor.x(), currentBuffer.zoomFactor.y()/zoomFactor.y());
++ // draw buffer to painter
++ p.drawImage(0,0, currentBuffer.image);
++ p.restore();
++
++ emit sigDraw(p);
++
++ // intNeedsRedraw is reset by the thread
++ if(needsRedraw & maskRedraw)
++ {
++ intNeedsRedraw = true;
++ }
++ mutex.unlock(); // --------- stop serialize with thread
++
++ if((needsRedraw & maskRedraw) && !isRunning())
++ {
++ start();
++ }
++}
++
++
++void IDrawContext::run()
++{
++ mutex.lock();
++
++ QTime t;
++ t.start();
++ qDebug() << "start thread" << objectName();
++
++ IDrawContext::buffer_t& currentBuffer = buffer[!bufIndex];
++ while(intNeedsRedraw)
++ {
++ // copy all projection information need by the
++ // map render objects to buffer structure
++ currentBuffer.zoomFactor = zoomFactor;
++ currentBuffer.scale = scale;
++ currentBuffer.ref1 = ref1;
++ currentBuffer.ref2 = ref2;
++ currentBuffer.ref3 = ref3;
++ currentBuffer.ref4 = ref4;
++ currentBuffer.focus = focus;
++ intNeedsRedraw = false;
++
++ mutex.unlock();
++ // ----- reset buffer -----
++ currentBuffer.image.fill(Qt::transparent);
++
++ drawt(currentBuffer);
++
++ mutex.lock();
++ }
++ // ----- switch buffer ------
++ bufIndex = !bufIndex;
++ qDebug() << "stop thread" << objectName() << "after" << t.elapsed() << "ms";
++
++ mutex.unlock();
++}
++
+diff --git a/src/qmaptool/canvas/IDrawContext.h b/src/qmaptool/canvas/IDrawContext.h
+new file mode 100644
+index 00000000..c87d4403
+--- /dev/null
++++ b/src/qmaptool/canvas/IDrawContext.h
+@@ -0,0 +1,164 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef IDRAWCONTEXT_H
++#define IDRAWCONTEXT_H
++
++#include "canvas/CCanvas.h"
++#include "units/IUnit.h"
++
++#include <QMutex>
++#include <QThread>
++class QPainter;
++class QSettings;
++
++class IDrawContext : public QThread
++{
++ Q_OBJECT
++public:
++ IDrawContext(CCanvas *canvas, QObject *parent);
++ virtual ~IDrawContext() = default;
++
++ virtual QString getInfo() const = 0;
++
++ virtual bool is32BitRgb() const = 0;
++
++ virtual int getRasterBandCount() const = 0;
++
++ virtual bool getNoData() const = 0;
++
++ virtual const QString& getProjection() const = 0;
++
++ virtual const QTransform& getTrFwd() const = 0;
++
++ virtual QRectF getMapArea() const = 0;
++
++ virtual void setSourceFile(const QString& filename, bool resetContext) = 0;
++
++ virtual void unload() = 0;
++
++ virtual bool getIsValid() const = 0;
++
++ virtual void saveSettings(QSettings& cfg) const;
++
++ virtual void loadSettings(QSettings& cfg);
++
++ void move(const QPointF& delta);
++
++ void zoom(bool in, const QPointF& pt);
++
++ bool needsRedraw() const;
++
++ void convertScreen2Map(QPointF &pt) const;
++ void convertMap2Screen(QPointF& pt) const;
++ void convertMap2Screen(QPolygonF& line) const;
++ void convertMap2Screen(QRectF &rect) const;
++
++ virtual void convertMap2Coord(QPointF &pt) const = 0;
++ virtual void convertCoord2Map(QPointF &pt) const = 0;
++
++ /**
++ @brief draw
++ @param p
++ @param needsRedraw
++ */
++ void draw(QPainter& p, CCanvas::redraw_e needsRedraw);
++
++ void triggerCompleteUpdate(CCanvas::redraw_e flags) const
++ {
++ canvas->slotTriggerCompleteUpdate(flags);
++ }
++
++ const CCanvas * getCanvas() const
++ {
++ return canvas;
++ }
++
++signals:
++ void sigDraw(QPainter& p);
++
++protected slots:
++ void slotResize(const QSize& size);
++
++protected:
++ CCanvas *canvas;
++
++ struct buffer_t
++ {
++ QImage image;
++
++ QPointF zoomFactor {1.0,1.0}; //< the zoomfactor used to draw the canvas
++ QPointF scale {1.0,1.0}; //< the scale of the global viewport
++
++ QPointF ref1; //< top left corner
++ QPointF ref2; //< top right corner
++ QPointF ref3; //< bottom right corner
++ QPointF ref4; //< bottom left corner
++ QPointF focus; //< point of focus
++ };
++
++ void run() override;
++
++ virtual void drawt(buffer_t& currentBuffer) = 0;
++
++ void zoom(int idx);
++
++ static QMutex mutex;
++
++ /// internal needs redraw flag
++ bool intNeedsRedraw = true;
++
++ const CCanvas::redraw_e maskRedraw = CCanvas::eRedrawMap;
++
++ /// map canvas twin buffer
++ buffer_t buffer[2];
++ /// the main threads currently used map canvas buffer
++ bool bufIndex = false;
++
++ qreal bufWidth = 100; //< buffer width [px]
++ qreal bufHeight = 100; //< buffer height [px]
++ qreal viewWidth = 100; //< the viewports width [px]
++ qreal viewHeight = 100; //< the viewports height [px]
++
++ QPointF focus {0, 0};
++
++ /// the basic scale of the map canvas
++ QPointF scale = QPoint(1.0, 1.0);
++
++private:
++ void init();
++
++ static const qreal scales[];
++ qint32 zoomFactorIdx = 6;
++
++ /// the actual used scaleFactor
++ QPointF zoomFactor {scales[zoomFactorIdx], scales[zoomFactorIdx]};
++
++ QPointF ref1; //< top left corner of next buffer
++ QPointF ref2; //< top right corner of next buffer
++ QPointF ref3; //< bottom right corner of next buffer
++ QPointF ref4; //< bottom left corner of next buffer
++};
++
++extern QPointF operator*(const QPointF& p1, const QPointF& p2);
++
++extern QPointF operator/(const QPointF& p1, const QPointF& p2);
++
++
++#endif //IDRAWCONTEXT_H
++
+diff --git a/src/qmaptool/helpers/CDraw.cpp b/src/qmaptool/helpers/CDraw.cpp
+new file mode 100644
+index 00000000..ef2367d7
+--- /dev/null
++++ b/src/qmaptool/helpers/CDraw.cpp
+@@ -0,0 +1,239 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++ Copyright (C) 2015 Christian Eichler code@christian-eichler.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CCanvas.h"
++#include "helpers/CDraw.h"
++
++#include <QDebug>
++#include <QImage>
++#include <QPointF>
++#include <QtMath>
++
++QPen CDraw::penBorderBlue(QColor(10,10,150,220),2);
++QPen CDraw::penBorderGray(Qt::lightGray,2);
++QPen CDraw::penBorderBlack(QColor(0,0,0,200),2);
++QBrush CDraw::brushBackWhite(QColor(255,255,255,255));
++QBrush CDraw::brushBackYellow(QColor(0xff, 0xff, 0xcc, 0xE0));
++
++
++QImage CDraw::createBasicArrow(const QBrush &brush, qreal scale)
++{
++ QImage arrow(21*scale, 16*scale, QImage::Format_ARGB32);
++ arrow.fill(qRgba(0, 0, 0, 0));
++
++ QPainter painter(&arrow);
++ USE_ANTI_ALIASING(painter, true);
++
++ // white background, same foreground as p
++ painter.setPen(QPen(Qt::white, 2));
++ painter.setBrush(brush);
++
++ QPointF arrowPoints[4] =
++ {
++ QPointF(20.0*scale, 7.0*scale), // front
++ QPointF( 0.0*scale, 0.0*scale), // upper tail
++ QPointF( 5.0*scale, 7.0*scale), // mid tail
++ QPointF( 0.0*scale, 15.0*scale) // lower tail
++ };
++ painter.drawPolygon(arrowPoints, 4);
++ painter.end();
++
++ return arrow;
++}
++
++/**
++ @brief Calculates the square distance between two points
++ @return (int) ( (x2 - x1)^2 + (y2 - y1)^2 )
++ */
++
++static inline int pointDistanceSquare(const QPointF &p1, const QPointF &p2)
++{
++ return (p2.x() - p1.x()) * (p2.x() - p1.x()) + (p2.y() - p1.y()) * (p2.y() - p1.y());
++}
++
++void CDraw::arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale)
++{
++ QImage arrow = createBasicArrow(p.brush(), scale);
++ qreal xoff = qCeil(arrow.width()/2.0);
++ qreal yoff = qFloor((arrow.height()-1)/2.0);
++
++ const qreal minArrowDistSquare = minArrowDist * minArrowDist;
++ const qreal minPointDistSquare = minPointDist * minPointDist;
++
++ QPointF prevArrow;
++ bool firstArrow = true;
++ for(int i = 1; i < line.size(); i++)
++ {
++ const QPointF &pt = line[i ];
++ const QPointF &prevPt = line[i - 1];
++
++ // ensure there is enough space between two line points
++ if( pointDistanceSquare(pt, prevPt) >= minPointDistSquare )
++ {
++ QPointF arrowPos = prevPt + (pt - prevPt)/2;
++
++ if( (viewport.contains(pt) || 0 == viewport.height()) // ensure the point is visible
++ && (firstArrow || pointDistanceSquare(prevArrow, arrowPos) >= minArrowDistSquare) )
++ {
++ p.save();
++
++ // rotate and draw the arrow (between bullets)
++ p.translate(arrowPos);
++ qreal direction = ( qAtan2((pt.y() - prevPt.y()), (pt.x() - prevPt.x())) * 180.) / M_PI;
++ p.rotate(direction);
++ p.drawImage(-xoff, -yoff, arrow);
++
++ p.restore();
++
++ prevArrow = arrowPos;
++ firstArrow = false;
++ }
++ }
++ }
++}
++
++void CDraw::text(const QString &str, QPainter &p, const QPoint &center, const QColor &color, const QFont &font)
++{
++ QFontMetrics fm(font);
++ QRect r = fm.boundingRect(str);
++
++ r.moveCenter(center);
++ p.setFont(font);
++
++ // draw the white `shadow`
++ p.setPen(Qt::white);
++ p.drawText(r.topLeft() - QPoint(-1, -1), str);
++ p.drawText(r.topLeft() - QPoint( 0, -1), str);
++ p.drawText(r.topLeft() - QPoint(+1, -1), str);
++
++ p.drawText(r.topLeft() - QPoint(-1, 0), str);
++ p.drawText(r.topLeft() - QPoint(+1, 0), str);
++
++ p.drawText(r.topLeft() - QPoint(-1, +1), str);
++ p.drawText(r.topLeft() - QPoint( 0, +1), str);
++ p.drawText(r.topLeft() - QPoint(+1, +1), str);
++
++ p.setPen(color);
++ p.drawText(r.topLeft(), str);
++}
++
++void CDraw::text(const QString &str, QPainter &p, const QRect &r, const QColor &color)
++{
++ p.setPen(Qt::white);
++ p.setFont(CMainWindow::self().getMapFont());
++
++ // draw the white `shadow`
++ p.drawText(r.adjusted(-1, -1, -1, -1), Qt::AlignCenter, str);
++ p.drawText(r.adjusted( 0, -1, 0, -1), Qt::AlignCenter, str);
++ p.drawText(r.adjusted(+1, -1, +1, -1), Qt::AlignCenter, str);
++
++ p.drawText(r.adjusted(-1, 0, -1, 0), Qt::AlignCenter, str);
++ p.drawText(r.adjusted(+1, 0, +1, 0), Qt::AlignCenter, str);
++
++ p.drawText(r.adjusted(-1, +1, -1, +1), Qt::AlignCenter, str);
++ p.drawText(r.adjusted( 0, +1, 0, +1), Qt::AlignCenter, str);
++ p.drawText(r.adjusted(+1, +1, +1, +1), Qt::AlignCenter, str);
++
++ p.setPen(color);
++ p.drawText(r, Qt::AlignCenter, str);
++}
++
++QPoint CDraw::bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth, float pointerBasePos)
++{
++ QPainterPath bubblePath;
++ bubblePath.addRoundedRect(contentRect, RECT_RADIUS, RECT_RADIUS);
++
++ // draw the arrow
++ int pointerBaseCenterX = (pointerBasePos <= 1)
++ ? contentRect.left() + (pointerBasePos * contentRect.width())
++ : contentRect.left() + (int) pointerBasePos;
++
++ int pointerHeight = 0;
++ if(pointerPos.y() < contentRect.top())
++ {
++ pointerHeight = contentRect.top() - pointerPos.y() + 1;
++ }
++ else if(pointerPos.y() > contentRect.bottom())
++ {
++ pointerHeight = contentRect.bottom() - pointerPos.y() - 1;
++ }
++ else
++ {
++ qDebug() << "cannot calculate pointerHeight/pointerBaseCenterX due to invalid parameters";
++ }
++
++ if(0 != pointerHeight)
++ {
++ QPolygonF pointerPoly;
++ pointerPoly << pointerPos
++ << QPointF(pointerBaseCenterX - pointerBaseWidth / 2, pointerPos.y() + pointerHeight)
++ << QPointF(pointerBaseCenterX + pointerBaseWidth / 2, pointerPos.y() + pointerHeight)
++ << pointerPos;
++
++ QPainterPath pointerPath;
++ pointerPath.addPolygon(pointerPoly);
++
++ bubblePath = bubblePath.united(pointerPath);
++ }
++
++ p.setPen (CDraw::penBorderGray);
++ p.setBrush(CDraw::brushBackWhite);
++
++ p.drawPolygon(bubblePath.toFillPolygon());
++
++ return contentRect.topLeft();
++}
++
++void CDraw::drawCrossHairDot(QPainter& p, const QPointF& pt)
++{
++ USE_ANTI_ALIASING(p, false);
++ p.setBrush(Qt::NoBrush);
++ QRectF dot2(0,0,7,7);
++ p.setPen(QPen(Qt::white, 3));
++ p.drawLine(pt.x(), pt.y() + 3, pt.x(), pt.y() + 20);
++ p.drawLine(pt.x(), pt.y() - 3, pt.x(), pt.y() - 20);
++ p.drawLine(pt.x() - 3, pt.y(), pt.x() - +20, pt.y());
++ p.drawLine(pt.x() + 3, pt.y(), pt.x() + 20, pt.y());
++ p.setPen(QPen(Qt::red, 1));
++ p.drawLine(pt.x(), pt.y() + 3, pt.x(), pt.y() + 20);
++ p.drawLine(pt.x(), pt.y() - 3, pt.x(), pt.y() - 20);
++ p.drawLine(pt.x() - 3, pt.y(), pt.x() - +20, pt.y());
++ p.drawLine(pt.x() + 3, pt.y(), pt.x() + 20, pt.y());
++
++ dot2.moveCenter(pt);
++ p.setPen(QPen(Qt::white, 3));
++ p.drawRect(dot2);
++ p.setPen(QPen(Qt::red, 1));
++ p.drawRect(dot2);
++ USE_ANTI_ALIASING(p, true);
++}
++
++void CDraw::drawRectangle(QPainter& p, const QRectF& rect, const QPen& pen, const QBrush& brush)
++{
++ p.setBrush(brush);
++ p.setPen(QPen(Qt::white, pen.width() + 2));
++ p.drawRect(rect);
++ p.setPen(pen);
++ p.drawRect(rect);
++}
++
++void CDraw::drawRectangle(QPainter& p, const QRectF& rect, const Qt::GlobalColor& pen, const Qt::GlobalColor& brush)
++{
++ drawRectangle(p,rect, QPen(pen), QBrush(brush));
++}
+diff --git a/src/qmaptool/helpers/CDraw.h b/src/qmaptool/helpers/CDraw.h
+new file mode 100644
+index 00000000..517d6baf
+--- /dev/null
++++ b/src/qmaptool/helpers/CDraw.h
+@@ -0,0 +1,96 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++ Copyright (C) 2015 Christian Eichler code@christian-eichler.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CPAINTER_H
++#define CPAINTER_H
++
++#include <QPainter>
++#include <QPolygonF>
++#include <QRectF>
++
++#include "CMainWindow.h"
++inline void USE_ANTI_ALIASING(QPainter& p, bool useAntiAliasing)
++{
++ p.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing|QPainter::SmoothPixmapTransform|QPainter::HighQualityAntialiasing, useAntiAliasing);
++}
++
++#define RECT_RADIUS 3
++#define PAINT_ROUNDED_RECT(p,r) p.drawRoundedRect(r,RECT_RADIUS,RECT_RADIUS)
++
++
++class CDraw
++{
++public:
++
++ static QPen penBorderBlue;
++ static QPen penBorderGray;
++ static QPen penBorderBlack;
++ static QBrush brushBackWhite;
++ static QBrush brushBackYellow;
++
++ /**
++ @brief Draw arrows along a line
++
++ An arrow is drawn if all the following requirements are met:
++ * the position the new arrow would have been drawn is within viewport
++ OR
++ `viewport.height() == 0`
++ * the two points have a distance of at least `minPointDist`
++ * the (potential) position of the new arrow has at least a distance of `minArrowDist` from the previous arrow
++
++ @param line The line to draw the arrows along
++ @param viewport Restrict drawing of arrows to this viewport (no limitation is applied if `viewport.height() == 0`)
++ @param minPointDist The minimum distance of two points (in px)
++ @param minArrowDist The minimum distance of two consecutive arrows (in px)
++ */
++ static void arrows(const QPolygonF &line, const QRectF &viewport, QPainter &p, int minPointDist, int minArrowDist, qreal scale);
++
++ static void text(const QString& str, QPainter &p, const QPoint &center, const QColor &color, const QFont &font = CMainWindow::self().getMapFont());
++ static void text(const QString& str, QPainter &p, const QRect &r, const QColor &color);
++
++ /**
++ @brief Draw a cartoon bubble
++
++ `pointerBasePos` denotes the position of the pointer's base, where 0 is `at the very left of the content`, and 1 is `at the very right`.
++ Be careful with small values (near 0) or large values (near 1) for pointerBasePos, this might lead to incorrect drawing,
++ especially if pointerBaseWidth is large.
++ If is larger than 1, a value in pixels is assumed.
++
++ @param p An active QPainter
++ @param contentRect The area the actual content will be in
++ @param pointerPos The position of the pointer's head
++ @param pointerBaseWidth The width of the pointer
++ @param pointerBasePos The (relative) location of the pointer (in percent / pixels)
++ */
++ static QPoint bubble(QPainter &p, const QRect &contentRect, const QPoint &pointerPos, int pointerBaseWidth = 20, float pointerBasePos = .5f);
++
++ static void drawCrossHairDot(QPainter& p, const QPointF& pt);
++
++ static void drawRectangle(QPainter& p, const QRectF& rect, const Qt::GlobalColor& pen, const Qt::GlobalColor& brush);
++ static void drawRectangle(QPainter& p, const QRectF& rect, const QPen& pen, const QBrush& brush);
++private:
++ /**
++ @brief Creates a new arrow using the brush specified
++ @return A QImage containing the arrow
++ */
++ static QImage createBasicArrow(const QBrush &brush, qreal scale);
++};
++
++#endif // CPAINTER_H
++
+diff --git a/src/qmaptool/helpers/CGdalFile.cpp b/src/qmaptool/helpers/CGdalFile.cpp
+new file mode 100644
+index 00000000..f1d875ec
+--- /dev/null
++++ b/src/qmaptool/helpers/CGdalFile.cpp
+@@ -0,0 +1,221 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CCanvas.h"
++#include "CMainWindow.h"
++#include "helpers/CGdalFile.h"
++
++#include <gdal_priv.h>
++#include <ogr_spatialref.h>
++
++#include <QtWidgets>
++
++CGdalFile::CGdalFile()
++{
++}
++
++
++void CGdalFile::unload()
++{
++ isValid = false;
++ if(dataset != nullptr)
++ {
++ GDALClose(dataset);
++ }
++ dataset = nullptr;
++}
++
++
++void CGdalFile::load(const QString& filename)
++{
++ qDebug() << filename;
++ CCanvas * canvas = CMainWindow::self().getCanvas();
++
++ dataset = (GDALDataset*)GDALOpenShared(filename.toUtf8(),GA_ReadOnly);
++
++ if(nullptr == dataset)
++ {
++ QMessageBox::warning(canvas, tr("Error..."), tr("Failed to load file: %1").arg(filename));
++ return;
++ }
++
++ char str[1025] = {0};
++ if(dataset->GetProjectionRef())
++ {
++ strncpy(str, dataset->GetProjectionRef(), sizeof(str) - 1);
++ }
++
++ {
++ OGRSpatialReference oSRS;
++ char *wkt = str;
++ oSRS.importFromWkt(&wkt);
++
++ char *proj4 = nullptr;
++ oSRS.exportToProj4(&proj4);
++ proj4str = proj4;
++ pjsrc = pj_init_plus(proj4);
++ free(proj4);
++ }
++
++ GDALRasterBand *pBand = dataset->GetRasterBand(1);
++
++ if(nullptr == pBand)
++ {
++ GDALClose(dataset);
++ dataset = nullptr;
++ QMessageBox::warning(canvas, tr("Error..."), tr("Failed to load file: %1").arg(filename));
++ return;
++ }
++ hasOverviews = pBand->GetOverviewCount();
++ qDebug() << "hasOverviews" << hasOverviews;
++
++ // ------- setup color table ---------
++ rasterBandCount = dataset->GetRasterCount();
++ if(rasterBandCount == 1)
++ {
++ if(pBand->GetColorInterpretation() == GCI_PaletteIndex )
++ {
++ GDALColorTable * pct = pBand->GetColorTable();
++ for(int i=0; i < pct->GetColorEntryCount(); ++i)
++ {
++ const GDALColorEntry& e = *pct->GetColorEntry(i);
++ colortable << qRgba(e.c1, e.c2, e.c3, e.c4);
++ }
++ }
++ else if(pBand->GetColorInterpretation() == GCI_GrayIndex )
++ {
++ for(int i=0; i < 256; ++i)
++ {
++ colortable << qRgba(i, i, i, 255);
++ }
++ }
++ else
++ {
++ GDALClose(dataset);
++ dataset = nullptr;
++ QMessageBox::warning(canvas, tr("Error..."), tr("File must be 8 bit palette or gray indexed."));
++ return;
++ }
++
++ int success = 0;
++ qreal idx = pBand->GetNoDataValue(&success);
++ if(success)
++ {
++ if((idx >= 0) && (idx < colortable.size()))
++ {
++ QColor tmp(colortable[idx]);
++ tmp.setAlpha(0);
++ colortable[idx] = tmp.rgba();
++ hasNoData = idx;
++ }
++ else
++ {
++ qDebug() << "Index for no data value is out of bound";
++ return;
++ }
++ }
++ }
++ qDebug() << "hasNoData" << hasNoData;
++
++ xsize_px = dataset->GetRasterXSize();
++ ysize_px = dataset->GetRasterYSize();
++
++ qreal adfGeoTransform[6];
++ dataset->GetGeoTransform( adfGeoTransform );
++
++ xscale = adfGeoTransform[1];
++ yscale = adfGeoTransform[5];
++ xrot = adfGeoTransform[4];
++ yrot = adfGeoTransform[2];
++
++ trFwd = QTransform();
++ trFwd.translate(adfGeoTransform[0], adfGeoTransform[3]);
++ trFwd.scale(adfGeoTransform[1], adfGeoTransform[5]);
++
++ if(adfGeoTransform[4] != 0.0)
++ {
++ trFwd.rotate(qAtan(adfGeoTransform[2]/adfGeoTransform[4]));
++ }
++
++ trInv = trFwd.inverted();
++
++ ref1 = trFwd.map(QPointF(0,0));
++ ref2 = trFwd.map(QPointF(xsize_px,0));
++ ref3 = trFwd.map(QPointF(xsize_px,ysize_px));
++ ref4 = trFwd.map(QPointF(0,ysize_px));
++
++ isValid = true;
++}
++
++QString CGdalFile::getProjection() const
++{
++ return proj4str;
++}
++
++QString CGdalFile::getInfo() const
++{
++ QString str;
++ QTextStream out(&str);
++
++ if(proj4str.isEmpty())
++ {
++ out << "no projection" << endl;
++ }
++ else
++ {
++ out << getProjection() << endl;
++ if(pj_is_latlong(pjsrc))
++ {
++ out << "xscale: " << xscale << "px/rad\tyscale: " << yscale << "px/rad" << endl;
++ }
++ else
++ {
++ out << "xscale: " << xscale << "px/m\tyscale: " << yscale << "px/m" << endl;
++ }
++ }
++
++ out << "num. bands:\t" << rasterBandCount << " ";
++ switch(rasterBandCount)
++ {
++ case 1:
++ out << tr("(color table)");
++ break;
++
++ case 3:
++ out << tr("(RGB)");
++ break;
++
++ case 4:
++ out << tr("(RGBA)");
++ break;
++
++ default:
++ out << tr("(unknown)");
++ }
++
++ out << endl;
++
++ out << "has overviews:\t" << hasOverviews << endl;
++
++ if((rasterBandCount != 4) && (hasNoData != -1))
++ {
++ out << "has no data:\t" << hasNoData << endl;
++ }
++
++ return str;
++}
+diff --git a/src/qmaptool/helpers/CGdalFile.h b/src/qmaptool/helpers/CGdalFile.h
+new file mode 100644
+index 00000000..49d77db2
+--- /dev/null
++++ b/src/qmaptool/helpers/CGdalFile.h
+@@ -0,0 +1,93 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CGDALFILE_H
++#define CGDALFILE_H
++
++
++#include <proj_api.h>
++#include <QCoreApplication>
++#include <QPointF>
++#include <QRgb>
++#include <QTransform>
++#include <QVector>
++
++class GDALDataset;
++
++class CGdalFile
++{
++ Q_DECLARE_TR_FUNCTIONS(CGdalFile)
++public:
++ CGdalFile();
++ virtual ~CGdalFile() = default;
++
++ bool getIsValid() const
++ {
++ return isValid;
++ }
++
++ QString getProjection() const;
++
++protected:
++ virtual QString getInfo() const;
++ virtual void load(const QString& filename);
++ virtual void unload();
++
++ GDALDataset * dataset = nullptr;
++
++ /// number of color bands used by the *vrt
++ int rasterBandCount = 0;
++ /// QT representation of the vrt's color table
++ QVector<QRgb> colortable;
++
++ // true if the map file has overviews
++ qint32 hasOverviews = -1;
++ qint32 hasNoData = -1;
++
++
++ /// true if the map file could be loaded
++ bool isValid = false;
++
++ /// width in number of px
++ qreal xsize_px = 0;
++ /// height in number of px
++ qreal ysize_px = 0;
++
++ /// scale [px/m]
++ qreal xscale = 0;
++ /// scale [px/m]
++ qreal yscale = 0;
++
++ qreal xrot = 0;
++ qreal yrot = 0;
++
++ QPointF ref1;
++ QPointF ref2;
++ QPointF ref3;
++ QPointF ref4;
++
++ QTransform trFwd;
++ QTransform trInv;
++
++ QString proj4str;
++
++ projPJ pjsrc = nullptr;
++};
++
++#endif //CGDALFILE_H
++
+diff --git a/src/qmaptool/helpers/CSettings.h b/src/qmaptool/helpers/CSettings.h
+new file mode 100644
+index 00000000..6abe4ecd
+--- /dev/null
++++ b/src/qmaptool/helpers/CSettings.h
+@@ -0,0 +1,54 @@
++/**********************************************************************************************
++ Copyright (C) 2012 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#ifndef CSETTINGS_H
++#define CSETTINGS_H
++
++#include "setup/CAppOpts.h"
++#include <QtCore>
++
++class CSettings : public QObject
++{
++public:
++ CSettings()
++ {
++ if(!qlOpts->configfile.isEmpty())
++ {
++ cfg = new QSettings(qlOpts->configfile, QSettings::IniFormat, this);
++ }
++ else
++ {
++ cfg = new QSettings(this);
++ }
++ }
++ ~CSettings()
++ {
++ }
++
++ QSettings& get()
++ {
++ return *cfg;
++ }
++
++private:
++ QSettings * cfg;
++};
++
++#define SETTINGS \
++ CSettings ccfg; \
++ QSettings& cfg = ccfg.get()
++#endif //CSETTINGS_H
+diff --git a/src/qmaptool/helpers/mitab.cpp b/src/qmaptool/helpers/mitab.cpp
+new file mode 100644
+index 00000000..4569a17d
+--- /dev/null
++++ b/src/qmaptool/helpers/mitab.cpp
+@@ -0,0 +1,260 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#include "mitab.h"
++
++const MapInfoDatumInfo asDatumInfoListQL[] =
++{
++ { // Datum ignore
++ 0, "", 29, 0, 0, 0, 0, 0, 0, 0, 0
++ },
++ {74, "North_American_Datum_1983", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {1, "Adindan", 6, -162, -12, 206, 0, 0, 0, 0, 0},
++ {2, "Afgooye", 3, -43, -163, 45, 0, 0, 0, 0, 0},
++ {3, "Ain_el_Abd_1970", 4, -150, -251, -2, 0, 0, 0, 0, 0},
++ {4, "Anna_1_Astro_1965", 2, -491, -22, 435, 0, 0, 0, 0, 0},
++ {5, "Arc_1950", 15,-143, -90, -294,0, 0, 0, 0, 0},
++ {6, "Arc_1960", 6, -160, -8, -300,0, 0, 0, 0, 0},
++ {7, "Ascension_Islands", 4, -207, 107, 52, 0, 0, 0, 0, 0},
++ {8, "Astro_Beacon_E", 4, 145, 75, -272,0, 0, 0, 0, 0},
++ {9, "Astro_B4_Sorol_Atoll", 4, 114, -116, -333,0, 0, 0, 0, 0},
++ {10, "Astro_Dos_71_4", 4, -320, 550, -494,0, 0, 0, 0, 0},
++ {11, "Astronomic_Station_1952", 4, 124, -234, -25, 0, 0, 0, 0, 0},
++ {12, "Australian_Geodetic_Datum_66",2, -133, -48, 148, 0, 0, 0, 0, 0},
++ {13, "Australian_Geodetic_Datum_84",2, -134, -48, 149, 0, 0, 0, 0, 0},
++ {14, "Bellevue_Ign", 4, -127, -769, 472, 0, 0, 0, 0, 0},
++ {15, "Bermuda_1957", 7, -73, 213, 296, 0, 0, 0, 0, 0},
++ {16, "Bogota", 4, 307, 304, -318,0, 0, 0, 0, 0},
++ {17, "Campo_Inchauspe", 4, -148, 136, 90, 0, 0, 0, 0, 0},
++ {18, "Canton_Astro_1966", 4, 298, -304, -375,0, 0, 0, 0, 0},
++ {19, "Cape", 6, -136, -108, -292,0, 0, 0, 0, 0},
++ {20, "Cape_Canaveral", 7, -2, 150, 181, 0, 0, 0, 0, 0},
++ {21, "Carthage", 6, -263, 6, 431, 0, 0, 0, 0, 0},
++ {22, "Chatham_1971", 4, 175, -38, 113, 0, 0, 0, 0, 0},
++ {23, "Chua", 4, -134, 229, -29, 0, 0, 0, 0, 0},
++ {24, "Corrego_Alegre", 4, -206, 172, -6, 0, 0, 0, 0, 0},
++ {25, "Batavia", 10,-377,681, -50, 0, 0, 0, 0, 0},
++ {26, "Dos_1968", 4, 230, -199, -752,0, 0, 0, 0, 0},
++ {27, "Easter_Island_1967", 4, 211, 147, 111, 0, 0, 0, 0, 0},
++ {28, "European_Datum_1950", 4, -87, -98, -121,0, 0, 0, 0, 0},
++ {29, "European_Datum_1979", 4, -86, -98, -119,0, 0, 0, 0, 0},
++ {30, "Gandajika_1970", 4, -133, -321, 50, 0, 0, 0, 0, 0},
++ {31, "New_Zealand_GD49", 4, 84, -22, 209, 0, 0, 0, 0, 0},
++ {32, "GRS_67", 21,0, 0, 0, 0, 0, 0, 0, 0},
++ {33, "GRS_80", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {34, "Guam_1963", 7, -100, -248, 259, 0, 0, 0, 0, 0},
++ {35, "Gux_1_Astro", 4, 252, -209, -751,0, 0, 0, 0, 0},
++ {36, "Hito_XVIII_1963", 4, 16, 196, 93, 0, 0, 0, 0, 0},
++ {37, "Hjorsey_1955", 4, -73, 46, -86, 0, 0, 0, 0, 0},
++ {38, "Hong_Kong_1963", 4, -156, -271, -189,0, 0, 0, 0, 0},
++ {39, "Hu_Tzu_Shan", 4, -634, -549, -201,0, 0, 0, 0, 0},
++ {40, "Indian_Thailand_Vietnam", 11,214, 836, 303, 0, 0, 0, 0, 0},
++ {41, "Indian_Bangladesh", 11,289, 734, 257, 0, 0, 0, 0, 0},
++ {42, "Ireland_1965", 13,506, -122, 611, 0, 0, 0, 0, 0},
++ {43, "ISTS_073_Astro_1969", 4, 208, -435, -229,0, 0, 0, 0, 0},
++ {44, "Johnston_Island_1961", 4, 191, -77, -204,0, 0, 0, 0, 0},
++ {45, "Kandawala", 11,-97, 787, 86, 0, 0, 0, 0, 0},
++ {46, "Kerguyelen_Island", 4, 145, -187, 103, 0, 0, 0, 0, 0},
++ {47, "Kertau", 17,-11, 851, 5, 0, 0, 0, 0, 0},
++ {48, "L_C_5_Astro", 7, 42, 124, 147, 0, 0, 0, 0, 0},
++ {49, "Liberia_1964", 6, -90, 40, 88, 0, 0, 0, 0, 0},
++ {50, "Luzon_Phillippines", 7, -133, -77, -51, 0, 0, 0, 0, 0},
++ {51, "Luzon_Mindanao_Island", 7, -133, -79, -72, 0, 0, 0, 0, 0},
++ {52, "Mahe_1971", 6, 41, -220, -134,0, 0, 0, 0, 0},
++ {53, "Marco_Astro", 4, -289, -124, 60, 0, 0, 0, 0, 0},
++ {54, "Massawa", 10,639, 405, 60, 0, 0, 0, 0, 0},
++ {55, "Merchich", 16,31, 146, 47, 0, 0, 0, 0, 0},
++ {56, "Midway_Astro_1961", 4, 912, -58, 1227,0, 0, 0, 0, 0},
++ {57, "Minna", 6, -92, -93, 122, 0, 0, 0, 0, 0},
++ {58, "Nahrwan_Masirah_Island", 6, -247, -148, 369, 0, 0, 0, 0, 0},
++ {59, "Nahrwan_Un_Arab_Emirates", 6, -249, -156, 381, 0, 0, 0, 0, 0},
++ {60, "Nahrwan_Saudi_Arabia", 6, -231, -196, 482, 0, 0, 0, 0, 0},
++ {61, "Naparima_1972", 4, -2, 374, 172, 0, 0, 0, 0, 0},
++ {62, "NAD_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
++ {62, "North_American_Datum_1927", 7, -8, 160, 176, 0, 0, 0, 0, 0},
++ {63, "NAD_27_Alaska", 7, -5, 135, 172, 0, 0, 0, 0, 0},
++ {64, "NAD_27_Bahamas", 7, -4, 154, 178, 0, 0, 0, 0, 0},
++ {65, "NAD_27_San_Salvador", 7, 1, 140, 165, 0, 0, 0, 0, 0},
++ {66, "NAD_27_Canada", 7, -10, 158, 187, 0, 0, 0, 0, 0},
++ {67, "NAD_27_Canal_Zone", 7, 0, 125, 201, 0, 0, 0, 0, 0},
++ {68, "NAD_27_Caribbean", 7, -7, 152, 178, 0, 0, 0, 0, 0},
++ {69, "NAD_27_Central_America", 7, 0, 125, 194, 0, 0, 0, 0, 0},
++ {70, "NAD_27_Cuba", 7, -9, 152, 178, 0, 0, 0, 0, 0},
++ {71, "NAD_27_Greenland", 7, 11, 114, 195, 0, 0, 0, 0, 0},
++ {72, "NAD_27_Mexico", 7, -12, 130, 190, 0, 0, 0, 0, 0},
++ {73, "NAD_27_Michigan", 8, -8, 160, 176, 0, 0, 0, 0, 0},
++ {75, "Observatorio_1966", 4, -425, -169, 81, 0, 0, 0, 0, 0},
++ {76, "Old_Egyptian", 22,-130, 110, -13, 0, 0, 0, 0, 0},
++ {77, "Old_Hawaiian", 7, 61, -285, -181,0, 0, 0, 0, 0},
++ {78, "Oman", 6, -346, -1, 224, 0, 0, 0, 0, 0},
++ {79, "OSGB_1936", 9, 375, -111, 431, 0, 0, 0, 0, 0},
++ {80, "Pico_De_Las_Nieves", 4, -307, -92, 127, 0, 0, 0, 0, 0},
++ {81, "Pitcairn_Astro_1967", 4, 185, 165, 42, 0, 0, 0, 0, 0},
++ {82, "Provisional_South_American", 4, -288, 175, -376,0, 0, 0, 0, 0},
++ {83, "Puerto_Rico", 7, 11, 72, -101,0, 0, 0, 0, 0},
++ {84, "Qatar_National", 4, -128, -283, 22, 0, 0, 0, 0, 0},
++ {85, "Qornoq", 4, 164, 138, -189, 0, 0, 0, 0, 0},
++ {86, "Reunion", 4, 94, -948,-1262,0, 0, 0, 0, 0},
++ {87, "Monte_Mario", 4, -225, -65, 9, 0, 0, 0, 0, 0},
++ {88, "Santo_Dos", 4, 170, 42, 84, 0, 0, 0, 0, 0},
++ {89, "Sao_Braz", 4, -203, 141, 53, 0, 0, 0, 0, 0},
++ {90, "Sapper_Hill_1943", 4, -355, 16, 74, 0, 0, 0, 0, 0},
++ {91, "Schwarzeck", 14,616, 97, -251, 0, 0, 0, 0, 0},
++ {92, "South_American_Datum_1969", 24,-57, 1, -41, 0, 0, 0, 0, 0},
++ {93, "South_Asia", 19,7, -10, -26, 0, 0, 0, 0, 0},
++ {94, "Southeast_Base", 4, -499, -249,314, 0, 0, 0, 0, 0},
++ {95, "Southwest_Base", 4, -104, 167, -38, 0, 0, 0, 0, 0},
++ {96, "Timbalai_1948", 11,-689, 691, -46, 0, 0, 0, 0, 0},
++ {97, "Tokyo", 10,-128, 481, 664, 0, 0, 0, 0, 0},
++ {98, "Tristan_Astro_1968", 4, -632, 438, -609, 0, 0, 0, 0, 0},
++ {99, "Viti_Levu_1916", 6, 51, 391, -36, 0, 0, 0, 0, 0},
++ {100, "Wake_Entiwetok_1960", 23,101, 52, -39, 0, 0, 0, 0, 0},
++ {101, "WGS_60", 26,0, 0, 0, 0, 0, 0, 0, 0},
++ {102, "WGS_66", 27,0, 0, 0, 0, 0, 0, 0, 0},
++ {103, "WGS_1972", 1, 0, 8, 10, 0, 0, 0, 0, 0},
++ {104, "WGS_1984", 28,0, 0, 0, 0, 0, 0, 0, 0},
++ {105, "Yacare", 4, -155, 171, 37, 0, 0, 0, 0, 0},
++ {106, "Zanderij", 4, -265, 120, -358, 0, 0, 0, 0, 0},
++ {107, "NTF", 30,-168, -60, 320, 0, 0, 0, 0, 0},
++ {108, "European_Datum_1987", 4, -83, -96, -113, 0, 0, 0, 0, 0},
++ {109, "Netherlands_Bessel", 10,593, 26, 478, 0, 0, 0, 0, 0},
++ {110, "Belgium_Hayford", 4, 81, 120, 129, 0, 0, 0, 0, 0},
++ {111, "NWGL_10", 1, -1, 15, 1, 0, 0, 0, 0, 0},
++ {112, "Rikets_koordinatsystem_1990",10,498, -36, 568, 0, 0, 0, 0, 0},
++ {113, "Lisboa_DLX", 4, -303, -62, 105, 0, 0, 0, 0, 0},
++ {114, "Melrica_1973_D73", 4, -223, 110, 37, 0, 0, 0, 0, 0},
++ {115, "Euref_98", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {116, "GDA94", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {117, "NZGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {118, "America_Samoa", 7, -115, 118, 426, 0, 0, 0, 0, 0},
++ {119, "Antigua_Astro_1965", 6, -270, 13, 62, 0, 0, 0, 0, 0},
++ {120, "Ayabelle_Lighthouse", 6, -79, -129, 145, 0, 0, 0, 0, 0},
++ {121, "Bukit_Rimpah", 10,-384, 664, -48, 0, 0, 0, 0, 0},
++ {122, "Estonia_1937", 10,374, 150, 588, 0, 0, 0, 0, 0},
++ {123, "Dabola", 6, -83, 37, 124, 0, 0, 0, 0, 0},
++ {124, "Deception_Island", 6, 260, 12, -147, 0, 0, 0, 0, 0},
++ {125, "Fort_Thomas_1955", 6, -7, 215, 225, 0, 0, 0, 0, 0},
++ {126, "Graciosa_base_1948", 4, -104, 167, -38, 0, 0, 0, 0, 0},
++ {127, "Herat_North", 4, -333, -222,114, 0, 0, 0, 0, 0},
++ {128, "Hermanns_Kogel", 10,682, -203, 480, 0, 0, 0, 0, 0},
++ {129, "Indian", 50,283, 682, 231, 0, 0, 0, 0, 0},
++ {130, "Indian_1954", 11,217, 823, 299, 0, 0, 0, 0, 0},
++ {131, "Indian_1960", 11,198, 881, 317, 0, 0, 0, 0, 0},
++ {132, "Indian_1975", 11,210, 814, 289, 0, 0, 0, 0, 0},
++ {133, "Indonesian_Datum_1974", 4, -24, -15, 5, 0, 0, 0, 0, 0},
++ {134, "ISTS061_Astro_1968", 4, -794, 119, -298, 0, 0, 0, 0, 0},
++ {135, "Kusaie_Astro_1951", 4, 647, 1777, -1124,0, 0, 0, 0, 0},
++ {136, "Leigon", 6, -130, 29, 364, 0, 0, 0, 0, 0},
++ {137, "Montserrat_Astro_1958", 6, 174, 359, 365, 0, 0, 0, 0, 0},
++ {138, "Mporaloko", 6, -74, -130, 42, 0, 0, 0, 0, 0},
++ {139, "North_Sahara_1959", 6, -186, -93, 310, 0, 0, 0, 0, 0},
++ {140, "Observatorio_Met_1939", 4, -425, -169,81, 0, 0, 0, 0, 0},
++ {141, "Point_58", 6, -106, -129,165, 0, 0, 0, 0, 0},
++ {142, "Pointe_Noire", 6, -148, 51, -291, 0, 0, 0, 0, 0},
++ {143, "Porto_Santo_1936", 4, -499, -249,314, 0, 0, 0, 0, 0},
++ {144, "Selvagem_Grande_1938", 4, -289, -124,60, 0, 0, 0, 0, 0},
++ {145, "Sierra_Leone_1960", 6, -88, 4, 101, 0, 0, 0, 0, 0},
++ {146, "S_JTSK_Ferro", 10, 589, 76, 480, 0, 0, 0, 0, 0},
++ {147, "Tananarive_1925", 4, -189, -242,-91, 0, 0, 0, 0, 0},
++ {148, "Voirol_1874", 6, -73, -247,227, 0, 0, 0, 0, 0},
++ {149, "Virol_1960", 6, -123, -206,219, 0, 0, 0, 0, 0},
++ {150, "Hartebeesthoek94", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {151, "ATS77", 51, 0, 0, 0, 0, 0, 0, 0, 0},
++ {152, "JGD2000", 0, 0, 0, 0, 0, 0, 0, 0, 0},
++ {1000,"DHDN_Potsdam_Rauenberg", 10,582, 105, 414, -1.04, -0.35, 3.08, 8.3, 0},
++ {1001,"Pulkovo_1942", 3, 24, -123, -94, -0.02, 0.25, 0.13, 1.1, 0},
++ {1002,"NTF_Paris_Meridian", 30,-168, -60, 320, 0, 0, 0, 0, 2.337229166667},
++ {1003,"Switzerland_CH_1903", 10,660.077,13.551, 369.344, 0.804816, 0.577692, 0.952236, 5.66,0},
++ {1004,"Hungarian_Datum_1972", 21,-56, 75.77, 15.31, -0.37, -0.2, -0.21, -1.01, 0},
++ {1005,"Cape_7_Parameter", 28,-134.73,-110.92, -292.66, 0, 0, 0, 1, 0},
++ {1006,"AGD84_7_Param_Aust", 2, -117.763,-51.51, 139.061, -0.292, -0.443, -0.277, -0.191, 0},
++ {1007,"AGD66_7_Param_ACT", 2, -129.193,-41.212, 130.73, -0.246, -0.374, -0.329, -2.955, 0},
++ {1008,"AGD66_7_Param_TAS", 2, -120.271,-64.543, 161.632, -0.2175, 0.0672, 0.1291, 2.4985, 0},
++ {1009,"AGD66_7_Param_VIC_NSW", 2, -119.353,-48.301, 139.484, -0.415, -0.26, -0.437, -0.613, 0},
++ {1010,"NZGD_7_Param_49", 4, 59.47, -5.04, 187.44, -0.47, 0.1, -1.024, -4.5993, 0},
++ {1011,"Rikets_Tri_7_Param_1990", 10,419.3836, 99.3335, 591.3451, -0.850389, -1.817277, 7.862238, -0.99496, 0},
++ {1012,"Russia_PZ90", 52, -1.08,-0.27,-0.9,0, 0, -0.16,-0.12, 0},
++ {1013,"Russia_SK42", 52, 23.92,-141.27,-80.9, 0, -0.35,-0.82, -0.12, 0},
++ {1014,"Russia_SK95", 52, 24.82,-131.21,-82.66,0,0,-0.16,-0.12, 0},
++ {1015,"Tokyo", 10, -146.414, 507.337, 680.507,0,0,0,0,0},
++ {1016,"Finnish_KKJ", 4, -96.062, -82.428, -121.754, -4.801, -0.345, 1.376, 1.496, 0},
++
++ {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
++};
++
++/* -------------------------------------------------------------------- */
++/* This table was hand entered from Appendix I of the mapinfo 6 */
++/* manuals. */
++/* -------------------------------------------------------------------- */
++
++const MapInfoSpheroidInfo asSpheroidInfoList[] =
++{
++ { 9,"Airy 1930", 6377563.396, 299.3249646},
++ {13,"Airy 1930 (modified for Ireland 1965", 6377340.189, 299.3249646},
++ {51,"ATS77 (Average Terrestrial System 1977)", 6378135, 298.257},
++ { 2,"Australian", 6378160.0, 298.25},
++ {10,"Bessel 1841", 6377397.155, 299.1528128},
++ {35,"Bessel 1841 (modified for NGO 1948)", 6377492.0176, 299.15281},
++ {14,"Bessel 1841 (modified for Schwarzeck)", 6377483.865, 299.1528128},
++ {36,"Clarke 1858", 6378293.639, 294.26068},
++ { 7,"Clarke 1866", 6378206.4, 294.9786982},
++ { 8,"Clarke 1866 (modified for Michigan)", 6378450.047484481,294.9786982},
++ { 6,"Clarke 1880", 6378249.145, 293.465},
++ {15,"Clarke 1880 (modified for Arc 1950)", 6378249.145326, 293.4663076},
++ {30,"Clarke 1880 (modified for IGN)", 6378249.2, 293.4660213},
++ {37,"Clarke 1880 (modified for Jamaica)", 6378249.136, 293.46631},
++ {16,"Clarke 1880 (modified for Merchich)", 6378249.2, 293.46598},
++ {38,"Clarke 1880 (modified for Palestine)", 6378300.79, 293.46623},
++ {39,"Everest (Brunei and East Malaysia)", 6377298.556, 300.8017},
++ {11,"Everest (India 1830)", 6377276.345, 300.8017},
++ {40,"Everest (India 1956)", 6377301.243, 300.80174},
++ {50,"Everest (Pakistan)", 6377309.613, 300.8017},
++ {17,"Everest (W. Malaysia and Singapore 1948)", 6377304.063, 300.8017},
++ {48,"Everest (West Malaysia 1969)", 6377304.063, 300.8017},
++ {18,"Fischer 1960", 6378166.0, 298.3},
++ {19,"Fischer 1960 (modified for South Asia)", 6378155.0, 298.3},
++ {20,"Fischer 1968", 6378150.0, 298.3},
++ {21,"GRS 67", 6378160.0, 298.247167427},
++ { 0,"GRS 80", 6378137.0, 298.257222101},
++ { 5,"Hayford", 6378388.0, 297.0},
++ {22,"Helmert 1906", 6378200.0, 298.3},
++ {23,"Hough", 6378270.0, 297.0},
++ {31,"IAG 75", 6378140.0, 298.257222},
++ {41,"Indonesian", 6378160.0, 298.247},
++ { 4,"International 1924", 6378388.0, 297.0},
++ {49,"Irish (WOFO)", 6377542.178, 299.325},
++ { 3,"Krassovsky", 6378245.0, 298.3},
++ {32,"MERIT 83", 6378137.0, 298.257},
++ {33,"New International 1967", 6378157.5, 298.25},
++ {42,"NWL 9D", 6378145.0, 298.25},
++ {43,"NWL 10D", 6378135.0, 298.26},
++ {44,"OSU86F", 6378136.2, 298.25722},
++ {45,"OSU91A", 6378136.3, 298.25722},
++ {46,"Plessis 1817", 6376523.0, 308.64},
++ {52,"PZ90", 6378136.0, 298.257839303},
++ {24,"South American", 6378160.0, 298.25},
++ {12,"Sphere", 6370997.0, 0.0},
++ {47,"Struve 1860", 6378297.0, 294.73},
++ {34,"Walbeck", 6376896.0, 302.78},
++ {25,"War Office", 6378300.583, 296.0},
++ {26,"WGS 60", 6378165.0, 298.3},
++ {27,"WGS 66", 6378145.0, 298.25},
++ { 1,"WGS 72", 6378135.0, 298.26},
++ {28,"WGS 84", 6378137.0, 298.257223563},
++ {29,"WGS 84 (MAPINFO Datum 0)", 6378137.01, 298.257223563},
++ {-1,0, 0.0, 0.0}
++};
+diff --git a/src/qmaptool/helpers/mitab.h b/src/qmaptool/helpers/mitab.h
+new file mode 100644
+index 00000000..6229b557
+--- /dev/null
++++ b/src/qmaptool/helpers/mitab.h
+@@ -0,0 +1,46 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#ifndef MITAB_H
++#define MITAB_H
++
++struct MapInfoDatumInfo
++{
++ int nMapInfoDatumID;
++ const char *pszOGCDatumName;
++ int nEllipsoid;
++ double dfShiftX;
++ double dfShiftY;
++ double dfShiftZ;
++ double dfDatumParm0; /* RotX */
++ double dfDatumParm1; /* RotY */
++ double dfDatumParm2; /* RotZ */
++ double dfDatumParm3; /* Scale Factor */
++ double dfDatumParm4; /* Prime Meridian */
++};
++
++struct MapInfoSpheroidInfo
++{
++ int nMapInfoId;
++ const char *pszMapinfoName;
++ double dfA; /* semi major axis in meters */
++ double dfInvFlattening; /* Inverse flattening */
++};
++
++extern const MapInfoDatumInfo asDatumInfoListQL[];
++extern const MapInfoSpheroidInfo asSpheroidInfoList[];
++#endif //MITAB_H
+diff --git a/src/qmaptool/items/CItemCutMap.cpp b/src/qmaptool/items/CItemCutMap.cpp
+new file mode 100644
+index 00000000..197b81b2
+--- /dev/null
++++ b/src/qmaptool/items/CItemCutMap.cpp
+@@ -0,0 +1,97 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "items/CItemCutMap.h"
++#include "overlay/COverlayCutMap.h"
++
++#include <QtWidgets>
++
++CItemCutMap::CItemCutMap(const QString &filename, QStackedWidget *stackedWidget, QListWidget *parent)
++ : CItemFile(filename, parent)
++{
++ overlay = new COverlayCutMap(this, stackedWidget);
++ connect(overlay, &COverlayCutMap::sigChanged, this, &CItemCutMap::sigChanged);
++}
++
++CItemCutMap::~CItemCutMap()
++{
++ overlay->deleteLater();
++}
++
++void CItemCutMap::saveSettings(QSettings& cfg)
++{
++ CItemFile::saveSettings(cfg);
++ overlay->saveSettings(cfg);
++}
++
++void CItemCutMap::loadSettings(QSettings& cfg)
++{
++ CItemFile::loadSettings(cfg);
++ overlay->loadSettings(cfg);
++}
++
++void CItemCutMap::toFront()
++{
++ overlay->toFront();
++}
++
++bool CItemCutMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ CItemFile::drawFx(p, needsRedraw);
++ overlay->drawFx(p, needsRedraw);
++ return true;
++}
++
++void CItemCutMap::mouseMoveEventFx(QMouseEvent *e)
++{
++ CItemFile::mouseMoveEventFx(e);
++ if(!mapIsMoving)
++ {
++ overlay->mouseMoveEventFx(e);
++ }
++}
++
++void CItemCutMap::mouseReleaseEventFx(QMouseEvent *e)
++{
++ if(!mapDidMove)
++ {
++ overlay->mouseReleaseEventFx(e);
++ }
++ CItemFile::mouseReleaseEventFx(e);
++}
++
++void CItemCutMap::leaveEventFx(QEvent *e)
++{
++ CItemFile::leaveEventFx(e);
++ overlay->abortStep();
++}
++
++QCursor CItemCutMap::getCursorFx()
++{
++ return overlay->getCursorFx();
++}
++
++void CItemCutMap::saveShape(const QString& filename) const
++{
++ overlay->saveShape(filename);
++}
++
++bool CItemCutMap::isOk() const
++{
++ return overlay->isOk();
++}
+diff --git a/src/qmaptool/items/CItemCutMap.h b/src/qmaptool/items/CItemCutMap.h
+new file mode 100644
+index 00000000..851589b3
+--- /dev/null
++++ b/src/qmaptool/items/CItemCutMap.h
+@@ -0,0 +1,52 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMCUTMAP_H
++#define CITEMCUTMAP_H
++
++#include "items/CItemFile.h"
++
++class COverlayCutMap;
++
++class CItemCutMap : public CItemFile
++{
++public:
++ CItemCutMap(const QString& filename, QStackedWidget * stackedWidget, QListWidget *parent);
++ virtual ~CItemCutMap();
++
++ void saveSettings(QSettings& cfg) override;
++ void loadSettings(QSettings& cfg) override;
++
++ void toFront() override;
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override;
++ void mouseMoveEventFx(QMouseEvent *e) override;
++ void mouseReleaseEventFx(QMouseEvent *e) override;
++ void leaveEventFx(QEvent *e) override;
++ QCursor getCursorFx() override;
++
++ void saveShape(const QString& filename) const;
++
++ bool isOk() const override;
++
++private:
++ COverlayCutMap * overlay;
++};
++
++#endif //CITEMCUTMAP_H
++
+diff --git a/src/qmaptool/items/CItemFile.cpp b/src/qmaptool/items/CItemFile.cpp
+new file mode 100644
+index 00000000..3aeff434
+--- /dev/null
++++ b/src/qmaptool/items/CItemFile.cpp
+@@ -0,0 +1,37 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CDrawContextPixel.h"
++#include "CMainWindow.h"
++#include "items/CItemFile.h"
++
++CItemFile::CItemFile(const QString &filename, QListWidget *parent)
++ : IItem(filename)
++ , QListWidgetItem(parent)
++{
++ setText(QFileInfo(filename).completeBaseName());
++ drawContext = new CDrawContextPixel(CMainWindow::self().getCanvas(), this);
++ reload();
++}
++
++
++void CItemFile::reload()
++{
++ IItem::reload();
++ setToolTip(filename + "\n" + drawContext->getInfo());
++}
+diff --git a/src/qmaptool/items/CItemFile.h b/src/qmaptool/items/CItemFile.h
+new file mode 100644
+index 00000000..66b31321
+--- /dev/null
++++ b/src/qmaptool/items/CItemFile.h
+@@ -0,0 +1,38 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMFILE_H
++#define CITEMFILE_H
++
++#include "items/IItem.h"
++
++#include <QListWidgetItem>
++
++class CItemFile : public IItem, public QListWidgetItem
++{
++public:
++ CItemFile(const QString& filename, QListWidget *parent);
++ virtual ~CItemFile() = default;
++
++ void setupChanged() override {}
++
++ void reload() override;
++};
++
++#endif //CITEMFILE_H
++
+diff --git a/src/qmaptool/items/CItemListWidget.cpp b/src/qmaptool/items/CItemListWidget.cpp
+new file mode 100644
+index 00000000..5776be22
+--- /dev/null
++++ b/src/qmaptool/items/CItemListWidget.cpp
+@@ -0,0 +1,157 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "helpers/CSettings.h"
++#include "items/CItemListWidget.h"
++#include "items/IItem.h"
++
++
++#include <QtWidgets>
++
++CItemListWidget::CItemListWidget(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++
++ connect(toolFiles, &QToolButton::clicked, this, &CItemListWidget::slotFiles);
++ connect(toolDelFile, &QToolButton::clicked, this, &CItemListWidget::slotDeleteFile);
++ connect(toolDelFiles, &QToolButton::clicked, this, &CItemListWidget::slotDeleteFiles);
++ connect(toolReloadFile, &QToolButton::clicked, this, &CItemListWidget::slotLoadCurrentMap);
++ connect(listFiles, &QListWidget::itemSelectionChanged, this, &CItemListWidget::slotSelectionChanged);
++}
++
++void CItemListWidget::saveSettings(QSettings& cfg)
++{
++ QStringList files;
++ const int N = listFiles->count();
++ for(int n = 0; n < N; n++)
++ {
++ IItem * item = dynamic_cast<IItem*>(listFiles->item(n));
++ if(item != nullptr)
++ {
++ files << item->getFilename();
++ cfg.beginGroup(QString("%1").arg(n));
++ item->saveSettings(cfg);
++ cfg.endGroup();
++ }
++ }
++ cfg.setValue("files", files);
++ cfg.setValue("lastFile", listFiles->currentRow());
++}
++
++void CItemListWidget::loadSettings(QSettings& cfg)
++{
++ QStringList files = cfg.value("files", QStringList()).toStringList();
++ addFiles(files);
++
++ const int N = listFiles->count();
++ for(int n = 0; n < N; n++)
++ {
++ IItem * item = dynamic_cast<IItem*>(listFiles->item(n));
++ if(item != nullptr)
++ {
++ cfg.beginGroup(QString("%1").arg(n));
++ item->loadSettings(cfg);
++ cfg.endGroup();
++ }
++ }
++
++ listFiles->setCurrentRow(cfg.value("lastFile",0).toInt());
++}
++
++IItem * CItemListWidget::currentItem()
++{
++ return dynamic_cast<IItem*>(listFiles->currentItem());
++}
++
++IItem * CItemListWidget::item(int n)
++{
++ return dynamic_cast<IItem*>(listFiles->item(n));
++}
++
++void CItemListWidget::addFiles(const QStringList& files)
++{
++ for(const QString& file : files)
++ {
++ emit sigAddItem(file, listFiles);
++ }
++
++ listFiles->setCurrentRow(listFiles->count() - 1);
++ slotSelectionChanged();
++}
++
++void CItemListWidget::slotFiles()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString();
++
++ const QStringList& files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path);
++ if(files.isEmpty())
++ {
++ return;
++ }
++
++ cfg.setValue("Path/mapInput", QFileInfo(files.first()).absolutePath());
++ addFiles(files);
++
++ if(listFiles->count() && (listFiles->currentItem() ==nullptr))
++ {
++ listFiles->setCurrentRow(0);
++ }
++}
++
++void CItemListWidget::slotLoadCurrentMap()
++{
++ IItem * item = dynamic_cast<IItem*>(listFiles->currentItem());
++ if(item != nullptr)
++ {
++ item->reload();
++ }
++}
++
++void CItemListWidget::slotDeleteFiles()
++{
++ listFiles->clear();
++ slotSelectionChanged();
++}
++
++void CItemListWidget::slotDeleteFile()
++{
++ QListWidgetItem * item = listFiles->takeItem(listFiles->currentRow());
++ delete item;
++ slotSelectionChanged();
++}
++
++void CItemListWidget::slotSelectionChanged()
++{
++ IItem * item = dynamic_cast<IItem*>(listFiles->currentItem());
++ if(item != nullptr)
++ {
++ item->toFront();
++ }
++
++ bool isNotEmpty = listFiles->count() != 0;
++ int row = listFiles->currentRow();
++
++ toolDelFile->setEnabled(row != -1);
++ toolDelFiles->setEnabled(isNotEmpty);
++ toolReloadFile->setEnabled(row != -1);
++
++ emit sigSelectionChanged();
++}
++
+diff --git a/src/qmaptool/items/CItemListWidget.h b/src/qmaptool/items/CItemListWidget.h
+new file mode 100644
+index 00000000..ad5123b1
+--- /dev/null
++++ b/src/qmaptool/items/CItemListWidget.h
+@@ -0,0 +1,84 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMLISTWIDGET_H
++#define CITEMLISTWIDGET_H
++
++#include "ui_IItemListWidget.h"
++
++class QSettings;
++class IItem;
++
++class CItemListWidget : public QWidget, private Ui::IItemListWidget
++{
++ Q_OBJECT
++public:
++ CItemListWidget(QWidget * parent);
++ virtual ~CItemListWidget() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ IItem * currentItem();
++ IItem * item(int n);
++
++ qint32 count() const
++ {
++ return listFiles->count();
++ }
++
++ template< typename LessThan>
++ void sort(LessThan lessThan)
++ {
++ listFiles->blockSignals(true);
++
++ QList<QListWidgetItem*> items;
++ while(listFiles->count() != 0)
++ {
++ items << listFiles->takeItem(0);
++ }
++
++ qSort(items.begin(), items.end(), lessThan);
++
++ for(QListWidgetItem* item : items)
++ {
++ listFiles->addItem(item);
++ }
++
++ listFiles->blockSignals(false);
++ }
++
++
++signals:
++ void sigAddItem(const QString& filename, QListWidget * list);
++ void sigSelectionChanged();
++ void sigChanged();
++
++protected slots:
++ void slotFiles();
++ void slotLoadCurrentMap();
++ void slotDeleteFiles();
++ void slotDeleteFile();
++ void slotSelectionChanged();
++
++protected:
++ void addFiles(const QStringList& files);
++};
++
++#endif //CITEMLISTWIDGET_H
++
+diff --git a/src/qmaptool/items/CItemMap.cpp b/src/qmaptool/items/CItemMap.cpp
+new file mode 100644
+index 00000000..db007897
+--- /dev/null
++++ b/src/qmaptool/items/CItemMap.cpp
+@@ -0,0 +1,82 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CCanvas.h"
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "items/CItemMap.h"
++#include "items/CItemMapLayer.h"
++#include "items/CItemTreeWidget.h"
++
++#include <QtWidgets>
++
++CItemMap::CItemMap(const QString &filename)
++ : IItem(filename)
++{
++ setText(CItemTreeWidget::eColumnName, QFileInfo(filename).completeBaseName());
++ setIcon(CItemTreeWidget::eColumnName, QIcon("://icons/32x32/FolderMap.png"));
++
++ reload();
++}
++
++CItemMap::~CItemMap()
++{
++ unload();
++}
++
++QPointF CItemMap::getScale() const
++{
++ return QPointF(xscale, yscale);
++}
++
++void CItemMap::reload()
++{
++ load(filename);
++ setToolTip(CItemTreeWidget::eColumnName,filename + "\n" + getInfo());
++
++ QFile f(filename);
++ f.open(QIODevice::ReadOnly);
++ QCryptographicHash md5(QCryptographicHash::Md5);
++ md5.addData(f.read(1024));
++ hash = md5.result().toHex();
++ f.close();
++}
++
++void CItemMap::drawBoundingBox(QPainter& p, IDrawContext * dc)
++{
++ QPointF pt1 = ref1;
++ QPointF pt2 = ref2;
++ QPointF pt3 = ref3;
++ QPointF pt4 = ref4;
++
++ dc->convertCoord2Map(pt1);
++ dc->convertCoord2Map(pt2);
++ dc->convertCoord2Map(pt3);
++ dc->convertCoord2Map(pt4);
++
++ dc->convertMap2Screen(pt1);
++ dc->convertMap2Screen(pt2);
++ dc->convertMap2Screen(pt3);
++ dc->convertMap2Screen(pt4);
++
++ p.setPen(QPen(Qt::red, 2));
++ QPolygonF line;
++ line << pt1 << pt2 << pt3 << pt4 << pt1;
++ p.drawPolyline(line);
++
++}
+diff --git a/src/qmaptool/items/CItemMap.h b/src/qmaptool/items/CItemMap.h
+new file mode 100644
+index 00000000..b0b8ca84
+--- /dev/null
++++ b/src/qmaptool/items/CItemMap.h
+@@ -0,0 +1,54 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMMAP_H
++#define CITEMMAP_H
++
++#include "helpers/CGdalFile.h"
++#include "items/IItem.h"
++
++#include <QTreeWidgetItem>
++
++class GDALDataset;
++class CItemMapLayer;
++
++class CItemMap : public CGdalFile, public IItem, public QTreeWidgetItem
++{
++public:
++ CItemMap(const QString& filename);
++ virtual ~CItemMap();
++
++ void setupChanged() override {}
++
++ QPointF getScale() const;
++
++ const QString& getHash() const
++ {
++ return hash;
++ }
++
++ void reload() override;
++
++ void drawBoundingBox(QPainter& p, IDrawContext *dc);
++
++private:
++ QString hash;
++};
++
++#endif //CITEMMAP_H
++
+diff --git a/src/qmaptool/items/CItemMapLayer.cpp b/src/qmaptool/items/CItemMapLayer.cpp
+new file mode 100644
+index 00000000..a72a81a3
+--- /dev/null
++++ b/src/qmaptool/items/CItemMapLayer.cpp
+@@ -0,0 +1,119 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CDrawContextProj.h"
++#include "CMainWindow.h"
++#include "items/CItemMap.h"
++#include "items/CItemMapLayer.h"
++#include "items/CItemTreeWidget.h"
++
++#include <QtWidgets>
++
++CItemMapLayer::CItemMapLayer(QTreeWidget *parent)
++ : IItem("")
++ , QTreeWidgetItem(parent)
++ , vrt(QDir::temp().absoluteFilePath("QMapTool_XXXXXX.vrt"))
++{
++ drawContext = new CDrawContextProj(CMainWindow::self().getCanvas(), parent);
++
++ setText(CItemTreeWidget::eColumnName, tr("Layer"));
++ setIcon(CItemTreeWidget::eColumnName, QIcon("://icons/32x32/MapLayer.png"));
++
++ // this is needed to create a filename
++ vrt.open();
++ vrt.close();
++}
++
++
++const QString& CItemMapLayer::getProjection() const
++{
++ return drawContext->getProjection();
++}
++
++bool CItemMapLayer::addMap(CItemMap *map)
++{
++ const QPointF& mapScale = map->getScale();
++
++ const QTransform& trFwd = drawContext->getTrFwd();
++
++ if(trFwd.isScaling())
++ {
++ if((qAbs((mapScale.x() - trFwd.m11())/trFwd.m11()) > 0.2) || (qAbs((mapScale.y() - trFwd.m22())/trFwd.m22()) > 0.2))
++ {
++ return false;
++ }
++ }
++
++ addChild(map);
++ updateLayer();
++
++ return drawContext->getIsValid();
++}
++
++void CItemMapLayer::updateLayer()
++{
++ drawContext->unload();
++ setToolTip(CItemTreeWidget::eColumnName, "");
++
++ const int N = childCount();
++ if(N == 0)
++ {
++ return;
++ }
++
++ QStringList args;
++ args << vrt.fileName();
++
++ for(int n = 0; n < N; n++)
++ {
++ CItemMap * map = dynamic_cast<CItemMap*>(child(n));
++ if(map != nullptr)
++ {
++ args << map->getFilename();
++ }
++ }
++
++ QProcess proc;
++ proc.start(IAppSetup::self().getGdalbuildvrt(), args);
++ proc.waitForStarted();
++ proc.waitForFinished();
++
++ drawContext->setSourceFile(vrt.fileName(), true);
++ setToolTip(CItemTreeWidget::eColumnName, drawContext->getInfo());
++}
++
++bool CItemMapLayer::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ drawContext->draw(p, needsRedraw);
++ return true;
++}
++
++void CItemMapLayer::drawBoundingBoxes(QPainter& p, IDrawContext * dc)
++{
++ const int N = childCount();
++ for(int n = 0; n < N; n++)
++ {
++ CItemMap * map = dynamic_cast<CItemMap*>(child(n));
++ if(map == nullptr)
++ {
++ continue;
++ }
++
++ map->drawBoundingBox(p, dc);
++ }
++}
+diff --git a/src/qmaptool/items/CItemMapLayer.h b/src/qmaptool/items/CItemMapLayer.h
+new file mode 100644
+index 00000000..1165c529
+--- /dev/null
++++ b/src/qmaptool/items/CItemMapLayer.h
+@@ -0,0 +1,57 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMMAPLAYER_H
++#define CITEMMAPLAYER_H
++
++#include "items/IItem.h"
++
++#include <QCoreApplication>
++#include <QTemporaryFile>
++#include <QTreeWidgetItem>
++
++class CItemMap;
++class CDrawContextProj;
++
++class CItemMapLayer : public IItem, public QTreeWidgetItem
++{
++ Q_OBJECT
++public:
++ CItemMapLayer(QTreeWidget * parent);
++ virtual ~CItemMapLayer() = default;
++
++ bool addMap(CItemMap * map);
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override;
++
++ void drawBoundingBoxes(QPainter& p, IDrawContext *dc);
++
++ void setupChanged() override {}
++
++ const QString& getProjection() const;
++
++protected:
++ friend bool sortByScale(QTreeWidgetItem * item1, QTreeWidgetItem * item2);
++
++ void updateLayer();
++
++ QTemporaryFile vrt;
++};
++
++#endif //CITEMMAPLAYER_H
++
+diff --git a/src/qmaptool/items/CItemRefMap.cpp b/src/qmaptool/items/CItemRefMap.cpp
+new file mode 100644
+index 00000000..1bbcad76
+--- /dev/null
++++ b/src/qmaptool/items/CItemRefMap.cpp
+@@ -0,0 +1,114 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "items/CItemRefMap.h"
++#include "overlay/COverlayRefMap.h"
++#include "overlay/refmap/COverlayRefMapPoint.h"
++
++#include <QtWidgets>
++
++CItemRefMap::CItemRefMap(const QString &filename, QStackedWidget *stackedWidget, QListWidget *parent)
++ : CItemFile(filename, parent)
++{
++ overlay = new COverlayRefMap(this, stackedWidget);
++ connect(overlay, &COverlayRefMap::sigChanged, this, &CItemRefMap::sigChanged);
++}
++
++CItemRefMap::~CItemRefMap()
++{
++ overlay->deleteLater();
++}
++
++void CItemRefMap::saveSettings(QSettings& cfg)
++{
++ CItemFile::saveSettings(cfg);
++ overlay->saveSettings(cfg);
++}
++
++void CItemRefMap::loadSettings(QSettings& cfg)
++{
++ CItemFile::loadSettings(cfg);
++ overlay->loadSettings(cfg);
++}
++
++void CItemRefMap::addRefPoints(QList<COverlayRefMapPoint*>& points)
++{
++ overlay->addRefPoints(points);
++}
++
++QString CItemRefMap::getMapProjection() const
++{
++ return overlay->getMapProjection();
++}
++
++const QList<COverlayRefMapPoint *> CItemRefMap::getRefPoints() const
++{
++ return overlay->getRefPoints();
++}
++
++
++void CItemRefMap::toFront()
++{
++ overlay->toFront();
++}
++
++bool CItemRefMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ CItemFile::drawFx(p, needsRedraw);
++ overlay->drawFx(p, needsRedraw);
++ return true;
++}
++
++void CItemRefMap::mouseMoveEventFx(QMouseEvent *e)
++{
++ CItemFile::mouseMoveEventFx(e);
++ if(!mapIsMoving)
++ {
++ overlay->mouseMoveEventFx(e);
++ }
++}
++
++void CItemRefMap::mouseReleaseEventFx(QMouseEvent *e)
++{
++ if(!mapDidMove)
++ {
++ overlay->mouseReleaseEventFx(e);
++ }
++ CItemFile::mouseReleaseEventFx(e);
++}
++
++bool CItemRefMap::keyPressEventFx(QKeyEvent *e)
++{
++ return overlay->keyPressEventFx(e);
++}
++
++void CItemRefMap::leaveEventFx(QEvent *e)
++{
++ CItemFile::leaveEventFx(e);
++ overlay->abortStep();
++}
++
++QCursor CItemRefMap::getCursorFx()
++{
++ return overlay->getCursorFx();
++}
++
++bool CItemRefMap::isOk() const
++{
++ return overlay->isOk();
++}
+diff --git a/src/qmaptool/items/CItemRefMap.h b/src/qmaptool/items/CItemRefMap.h
+new file mode 100644
+index 00000000..5e74e8bf
+--- /dev/null
++++ b/src/qmaptool/items/CItemRefMap.h
+@@ -0,0 +1,56 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMREFMAP_H
++#define CITEMREFMAP_H
++
++#include "items/CItemFile.h"
++
++class COverlayRefMap;
++class COverlayRefMapPoint;
++
++class CItemRefMap : public CItemFile
++{
++public:
++ CItemRefMap(const QString& filename, QStackedWidget * stackedWidget, QListWidget *parent);
++ virtual ~CItemRefMap();
++
++ void saveSettings(QSettings& cfg) override;
++ void loadSettings(QSettings& cfg) override;
++
++ void addRefPoints(QList<COverlayRefMapPoint *> &points);
++ QString getMapProjection() const;
++ const QList<COverlayRefMapPoint*> getRefPoints() const;
++
++ void toFront() override;
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override;
++ void mouseMoveEventFx(QMouseEvent *e) override;
++ void mouseReleaseEventFx(QMouseEvent *e) override;
++ void leaveEventFx(QEvent *e) override;
++ bool keyPressEventFx(QKeyEvent *e) override;
++ QCursor getCursorFx() override;
++
++ bool isOk() const override;
++
++private:
++ COverlayRefMap * overlay;
++};
++
++#endif //CITEMREFMAP_H
++
+diff --git a/src/qmaptool/items/CItemTreeWidget.cpp b/src/qmaptool/items/CItemTreeWidget.cpp
+new file mode 100644
+index 00000000..9a68beaf
+--- /dev/null
++++ b/src/qmaptool/items/CItemTreeWidget.cpp
+@@ -0,0 +1,317 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/CDrawContextProj.h"
++#include "helpers/CDraw.h"
++#include "helpers/CSettings.h"
++#include "items/CItemMap.h"
++#include "items/CItemMapLayer.h"
++#include "items/CItemTreeWidget.h"
++
++#include <QtWidgets>
++
++CItemTreeWidget::CItemTreeWidget(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++
++ connect(toolFiles, &QToolButton::clicked, this, &CItemTreeWidget::slotFiles);
++ connect(toolDelFile, &QToolButton::clicked, this, &CItemTreeWidget::slotDeleteFile);
++ connect(toolDelFiles, &QToolButton::clicked, this, &CItemTreeWidget::slotDeleteFiles);
++ connect(treeFiles, &QTreeWidget::itemSelectionChanged, this, &CItemTreeWidget::slotSelectionChanged);
++}
++
++void CItemTreeWidget::saveSettings(QSettings& cfg)
++{
++ QStringList files;
++ const int N = treeFiles->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++
++ const int M = layer->childCount();
++ for(int m = 0; m < M; m++)
++ {
++ CItemMap * map = dynamic_cast<CItemMap*>(layer->child(m));
++ if(map != nullptr)
++ {
++ files << map->getFilename();
++ cfg.beginGroup(QString("%1_%2").arg(n).arg(m));
++ map->saveSettings(cfg);
++ cfg.endGroup();
++ }
++ }
++ }
++
++ cfg.setValue("files", files);
++}
++
++void CItemTreeWidget::loadSettings(QSettings& cfg)
++{
++ QStringList files = cfg.value("files", QStringList()).toStringList();
++ addFiles(files);
++
++ const int N = treeFiles->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++
++ const int M = layer->childCount();
++ for(int m = 0; m < M; m++)
++ {
++ CItemMap * map = dynamic_cast<CItemMap*>(layer->child(m));
++ if(map != nullptr)
++ {
++ cfg.beginGroup(QString("%1_%2").arg(n).arg(m));
++ map->loadSettings(cfg);
++ cfg.endGroup();
++ }
++ }
++ }
++}
++
++ITool * CItemTreeWidget::currentItem()
++{
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->currentItem());
++ if(layer != nullptr)
++ {
++ return layer;
++ }
++
++ CItemMap * map = dynamic_cast<CItemMap*>(treeFiles->currentItem());
++ if(map != nullptr)
++ {
++ return dynamic_cast<CItemMapLayer*>(map->QTreeWidgetItem::parent());
++ }
++
++ return nullptr;
++}
++
++bool sortByScale(QTreeWidgetItem * item1, QTreeWidgetItem * item2)
++{
++ CItemMapLayer * layer1 = dynamic_cast<CItemMapLayer*>(item1);
++ CItemMapLayer * layer2 = dynamic_cast<CItemMapLayer*>(item2);
++ if(layer1 == nullptr || layer2 == nullptr)
++ {
++ return false;
++ }
++
++ return layer1->drawContext->getTrFwd().m11() < layer2->drawContext->getTrFwd().m11();
++}
++
++
++void CItemTreeWidget::addFiles(const QStringList& files)
++{
++ QString projstr;
++
++ // preset projstr if there is already a layer with a projection.
++ if(treeFiles->topLevelItemCount() != 0)
++ {
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(0));
++ if(layer != nullptr)
++ {
++ projstr = layer->getProjection();
++ }
++ }
++
++
++ for(const QString& file : files)
++ {
++ CItemMap * map = new CItemMap(file);
++
++ // if something failed simply go on.
++ if(!map->getIsValid())
++ {
++ delete map;
++ continue;
++ }
++
++ // setup/test for common projection
++ if(projstr.isEmpty())
++ {
++ projstr = map->getProjection();
++ }
++ else if(map->getProjection() != projstr)
++ {
++ const QString msg = tr("<p>The current map <i>'%1'</i> does not match the projection of previous loaded maps. "
++ "All map files need to have the same projection.</p>"
++ "<p><b>This file</b>: %2</p>"
++ "<p><b>Expected</b>: %3</p>"
++ ).arg(file).arg(map->getProjection()).arg(projstr);
++ QMessageBox::warning(this, tr("Error..."), msg, QMessageBox::Abort);
++ delete map;
++ continue;
++ }
++
++ // if the map is already in the list simply go on
++ if(findMapByHash(map->getHash()) != nullptr)
++ {
++ delete map;
++ continue;
++ }
++
++ CItemMapLayer * layer = nullptr;
++ const int N = treeFiles->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++
++ if(layer->addMap(map))
++ {
++ break;
++ }
++ layer = nullptr;
++ }
++
++ if(layer == nullptr)
++ {
++ layer = new CItemMapLayer(treeFiles);
++ layer->addMap(map);
++ }
++ } // for(const QString& file : files)
++
++ sort(sortByScale);
++ treeFiles->expandAll();
++ slotSelectionChanged();
++}
++
++CItemMap * CItemTreeWidget::findMapByHash(const QString& hash)
++{
++ const int N = treeFiles->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++
++ const int M = layer->childCount();
++ for(int m = 0; m < M; m++)
++ {
++ CItemMap * map = dynamic_cast<CItemMap*>(layer->child(m));
++ if((map != nullptr) && (map->getHash() == hash))
++ {
++ return map;
++ }
++ }
++ }
++
++ return nullptr;
++}
++
++void CItemTreeWidget::slotFiles()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString();
++
++ const QStringList& files = QFileDialog::getOpenFileNames(this, tr("Select files..."), path);
++ if(files.isEmpty())
++ {
++ return;
++ }
++
++ cfg.setValue("Path/mapInput", QFileInfo(files.first()).absolutePath());
++ addFiles(files);
++}
++
++void CItemTreeWidget::slotDeleteFiles()
++{
++ treeFiles->clear();
++ slotSelectionChanged();
++}
++
++void CItemTreeWidget::slotDeleteFile()
++{
++ CItemMap * map = dynamic_cast<CItemMap*>(treeFiles->currentItem());
++ if(map != nullptr)
++ {
++ QTreeWidgetItem * layer = map->QTreeWidgetItem::parent();
++ delete map;
++ if(layer->childCount() == 0)
++ {
++ delete layer;
++ }
++ slotSelectionChanged();
++ return;
++ }
++
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->currentItem());
++ if(layer != nullptr)
++ {
++ delete layer;
++ slotSelectionChanged();
++ return;
++ }
++}
++
++void CItemTreeWidget::slotSelectionChanged()
++{
++ bool isNotEmpty = treeFiles->topLevelItemCount() != 0;
++ bool isSelected = !treeFiles->selectedItems().isEmpty();
++
++ toolDelFile->setEnabled(isSelected);
++ toolDelFiles->setEnabled(isNotEmpty);
++ toolReloadFile->setEnabled(isSelected);
++
++ emit sigSelectionChanged();
++}
++
++bool CItemTreeWidget::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ bool res = false;
++
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(currentItem());
++ if(layer != nullptr)
++ {
++ res = layer->drawFx(p, needsRedraw);
++
++ IDrawContext * dc = layer->getDrawContext();
++
++ if(dc == nullptr)
++ {
++ return res;
++ }
++
++ const int N = treeFiles->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(treeFiles->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++
++ layer->drawBoundingBoxes(p, dc);
++ }
++ }
++
++ return res;
++}
+diff --git a/src/qmaptool/items/CItemTreeWidget.h b/src/qmaptool/items/CItemTreeWidget.h
+new file mode 100644
+index 00000000..25d87935
+--- /dev/null
++++ b/src/qmaptool/items/CItemTreeWidget.h
+@@ -0,0 +1,94 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CITEMTREEWIDGET_H
++#define CITEMTREEWIDGET_H
++
++#include "ui_IItemTreeWidget.h"
++
++class QSettings;
++class ITool;
++class CItemMap;
++
++class CItemTreeWidget : public QWidget, private Ui::IItemTreeWidget
++{
++ Q_OBJECT
++public:
++ enum column_e
++ {
++ eColumnName
++ };
++
++ CItemTreeWidget(QWidget * parent);
++ virtual ~CItemTreeWidget() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ ITool *currentItem();
++
++ template< typename LessThan>
++ void sort(LessThan lessThan)
++ {
++ treeFiles->blockSignals(true);
++
++ QList<QTreeWidgetItem*> items;
++ while(treeFiles->topLevelItemCount() != 0)
++ {
++ items << treeFiles->takeTopLevelItem(0);
++ }
++
++ qSort(items.begin(), items.end(), lessThan);
++
++ for(QTreeWidgetItem* item : items)
++ {
++ treeFiles->addTopLevelItem(item);
++ }
++
++ treeFiles->blockSignals(false);
++ }
++
++ qint32 topLevelItemCount() const
++ {
++ return treeFiles->topLevelItemCount();
++ }
++
++ QTreeWidgetItem * topLevelItem(int n)
++ {
++ return treeFiles->topLevelItem(n);
++ }
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++
++signals:
++ void sigSelectionChanged();
++ void sigChanged();
++
++protected slots:
++ void slotFiles();
++ void slotDeleteFiles();
++ void slotDeleteFile();
++ void slotSelectionChanged();
++
++protected:
++ void addFiles(const QStringList& files);
++ CItemMap *findMapByHash(const QString& hash);
++};
++
++#endif //CITEMTREEWIDGET_H
++
+diff --git a/src/qmaptool/items/IItem.cpp b/src/qmaptool/items/IItem.cpp
+new file mode 100644
+index 00000000..9e8e636f
+--- /dev/null
++++ b/src/qmaptool/items/IItem.cpp
+@@ -0,0 +1,141 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "items/IItem.h"
++
++#include <QtWidgets>
++
++IItem::IItem(const QString &filename)
++ : filename(filename)
++{
++}
++
++void IItem::saveSettings(QSettings& cfg)
++{
++ if(nullptr != drawContext)
++ {
++ drawContext->saveSettings(cfg);
++ }
++}
++
++void IItem::loadSettings(QSettings& cfg)
++{
++ if(nullptr != drawContext)
++ {
++ drawContext->loadSettings(cfg);
++ }
++}
++
++void IItem::reload()
++{
++ if(nullptr == drawContext)
++ {
++ return;
++ }
++ drawContext->setSourceFile(filename, false);
++}
++
++bool IItem::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ if(nullptr == drawContext)
++ {
++ return false;
++ }
++
++ drawContext->draw(p, needsRedraw);
++ return true;
++}
++
++void IItem::mousePressEventFx(QMouseEvent *e)
++{
++ if(nullptr == drawContext)
++ {
++ return;
++ }
++
++ if(e->button() == Qt::LeftButton)
++ {
++ lastPos = e->pos();
++ firstPos = lastPos;
++ mapIsMoving = true;
++ mapDidMove = false;
++ }
++}
++
++void IItem::mouseMoveEventFx(QMouseEvent *e)
++{
++ if(nullptr == drawContext)
++ {
++ return;
++ }
++
++ const QPoint& point = e->pos();
++ if(mapIsMoving)
++ {
++ if((point - firstPos).manhattanLength() >= 4)
++ {
++ drawContext->move(point - lastPos);
++
++ lastPos = point;
++ mapDidMove = true;
++
++ drawContext->triggerCompleteUpdate(CCanvas::eRedrawMap);
++ }
++ }
++}
++
++void IItem::mouseReleaseEventFx(QMouseEvent *e)
++{
++ if(nullptr == drawContext)
++ {
++ return;
++ }
++
++ if(e->button() == Qt::LeftButton)
++ {
++ lastPos = e->pos();
++ mapIsMoving = false;
++ mapDidMove = false;
++ }
++}
++
++void IItem::wheelEventFx(QWheelEvent *e)
++{
++ if(nullptr == drawContext)
++ {
++ return;
++ }
++
++ // angleDelta() returns the eighths of a degree
++ // of the mousewheel
++ // -> zoom in/out every 15 degress = every 120 eights
++ const int EIGHTS_ZOOM = 15 * 8;
++ zoomAngleDelta += e->angleDelta().y();
++ if(abs(zoomAngleDelta) < EIGHTS_ZOOM)
++ {
++ return;
++ }
++
++ zoomAngleDelta = 0;
++
++ drawContext->zoom(CMainWindow::self().flipMouseWheel() ? (e->delta() < 0) : (e->delta() > 0), e->posF());
++ drawContext->triggerCompleteUpdate(CCanvas::eRedrawAll);
++}
++
+diff --git a/src/qmaptool/items/IItem.h b/src/qmaptool/items/IItem.h
+new file mode 100644
+index 00000000..59697d2c
+--- /dev/null
++++ b/src/qmaptool/items/IItem.h
+@@ -0,0 +1,97 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef IITEM_H
++#define IITEM_H
++
++
++#include "tool/ITool.h"
++#include <QObject>
++
++class QSettings;
++class IDrawContext;
++
++class IItem : public QObject, public ITool
++{
++ Q_OBJECT
++public:
++ IItem(const QString& filename);
++ virtual ~IItem() = default;
++
++ virtual void saveSettings(QSettings& cfg);
++ virtual void loadSettings(QSettings& cfg);
++
++ const QString& getFilename() const
++ {
++ return filename;
++ }
++
++ IDrawContext* getDrawContext() const
++ {
++ return drawContext;
++ }
++
++ bool getMapDidMove() const
++ {
++ return mapDidMove;
++ }
++
++ bool getMapIsMoving() const
++ {
++ return mapIsMoving;
++ }
++
++ /// reload file into draw context
++ virtual void reload();
++ /// item has been selected, bring everything to front (to be displayed)
++ virtual void toFront(){}
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override;
++ void mousePressEventFx(QMouseEvent *e) override;
++ void mouseMoveEventFx(QMouseEvent *e) override;
++ void mouseReleaseEventFx(QMouseEvent *e) override;
++ void wheelEventFx(QWheelEvent *e) override;
++
++ virtual bool isOk() const
++ {
++ return false;
++ }
++
++signals:
++ void sigChanged();
++
++protected:
++ QString filename;
++ IDrawContext * drawContext = nullptr;
++
++ /// true while left mouse button is pressed down
++ bool mapIsMoving = false;
++ /// true if map actually moved, if not it's a single click
++ bool mapDidMove = false;
++
++ /// last mouse position
++ QPoint lastPos;
++ /// mouse position when left button was pressed
++ QPoint firstPos;
++
++ /// current accumulated angleDelta, used/required for zooming on track pads
++ int zoomAngleDelta = 0;
++};
++
++#endif //IITEM_H
++
+diff --git a/src/qmaptool/items/IItemListWidget.ui b/src/qmaptool/items/IItemListWidget.ui
+new file mode 100644
+index 00000000..ae057f1a
+--- /dev/null
++++ b/src/qmaptool/items/IItemListWidget.ui
+@@ -0,0 +1,127 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IItemListWidget</class>
++ <widget class="QWidget" name="IItemListWidget">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>258</width>
++ <height>152</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_3">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QToolButton" name="toolFiles">
++ <property name="toolTip">
++ <string>Add map files to list</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolDelFile">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove selected file from the list.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/DeleteOne.png</normaloff>:/icons/32x32/DeleteOne.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolDelFiles">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Clear complete list of map files.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/DeleteMultiple.png</normaloff>:/icons/32x32/DeleteMultiple.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolReloadFile">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Reload the currently selected map.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Reload.png</normaloff>:/icons/32x32/Reload.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer_3">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QListWidget" name="listFiles"/>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../../qmapshack/resources.qrc"/>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/items/IItemTreeWidget.ui b/src/qmaptool/items/IItemTreeWidget.ui
+new file mode 100644
+index 00000000..cbe6fd8e
+--- /dev/null
++++ b/src/qmaptool/items/IItemTreeWidget.ui
+@@ -0,0 +1,135 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IItemTreeWidget</class>
++ <widget class="QWidget" name="IItemTreeWidget">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>258</width>
++ <height>152</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
++ <property name="spacing">
++ <number>0</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_3">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QToolButton" name="toolFiles">
++ <property name="toolTip">
++ <string>Add map files to list</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolDelFile">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove selected file from the list.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/DeleteOne.png</normaloff>:/icons/32x32/DeleteOne.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolDelFiles">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Clear complete list of map files.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/DeleteMultiple.png</normaloff>:/icons/32x32/DeleteMultiple.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolReloadFile">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Reload the currently selected map.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Reload.png</normaloff>:/icons/32x32/Reload.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer_3">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QTreeWidget" name="treeFiles">
++ <attribute name="headerVisible">
++ <bool>false</bool>
++ </attribute>
++ <column>
++ <property name="text">
++ <string notr="true">1</string>
++ </property>
++ </column>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/locale/qmaptool.ts b/src/qmaptool/locale/qmaptool.ts
+new file mode 100644
+index 00000000..025b1390
+--- /dev/null
++++ b/src/qmaptool/locale/qmaptool.ts
+@@ -0,0 +1,1675 @@
++<?xml version="1.0" encoding="utf-8"?>
++<!DOCTYPE TS>
++<TS version="2.1">
++<context>
++ <name>CCanvas</name>
++ <message>
++ <location filename="../canvas/CCanvas.cpp" line="89"/>
++ <source>No map view available.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CCommandProcessor</name>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="31"/>
++ <source>Print debug output to console.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="34"/>
++ <source>Print debug output to logfile (temp. path).</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="37"/>
++ <source>Do not show splash screen.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>File with QMapTool configuration.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>file</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="39"/>
++ <source>bad coordinate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Error</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <source>Bad value for X pixel.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Bad value for Y pixel.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CDrawContextPixel</name>
++ <message>
++ <location filename="../canvas/CDrawContextPixel.cpp" line="73"/>
++ <source>Failed to load</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CGdalFile</name>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>Error...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <source>Failed to load file: %1</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>File must be 8 bit palette or gray indexed.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="179"/>
++ <source>(color table)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="183"/>
++ <source>(RGB)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="187"/>
++ <source>(RGBA)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="191"/>
++ <source>(unknown)</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="34"/>
++ <source>Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="160"/>
++ <source>Point 1 - not set</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="164"/>
++ <source>Point 1 - ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="169"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="174"/>
++ <source>Point 1 - bad</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="185"/>
++ <source>Point 2 - ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="190"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="195"/>
++ <source>Point 2 - bad</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="207"/>
++ <source>Point 3 - ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="212"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="217"/>
++ <source>Point 3 - bad</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="229"/>
++ <source>Point 4 - ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="234"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="239"/>
++ <source>Point 4 - bad</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="181"/>
++ <source>Point 2 - not set</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="203"/>
++ <source>Point 3 - not set</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="225"/>
++ <source>Point 4 - not set</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSelArea.cpp" line="30"/>
++ <source>Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSetRef.cpp" line="37"/>
++ <source>Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. &quot;48.2&quot; or &quot;12.4&quot;. For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CItemListWidget</name>
++ <message>
++ <location filename="../items/CItemListWidget.cpp" line="103"/>
++ <source>Select files...</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>COverlayCutMap</name>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Delete mask...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Are you sure to delete complete mask?</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="239"/>
++ <source>Save mask...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="287"/>
++ <source>Load mask...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Failed...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Not a shape file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>COverlayGridTool</name>
++ <message>
++ <location filename="../overlay/COverlayGridTool.cpp" line="34"/>
++ <source>Before you proceed with &apos;ok&apos;:
++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it&apos;s much more effort to set additional points in case you miss some. When you are done press &apos;ok&apos; to transfer the derived reference points to the Reference Tool.
++
++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMap</name>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="42"/>
++ <source>If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task.
++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list.
++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="614"/>
++ <source>Save reference points...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="653"/>
++ <source>Load reference points...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Delete all reference points...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Are you sure to delete all reference points in the list?</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete all selected reference points?</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMapPoint</name>
++ <message>
++ <location filename="../overlay/refmap/COverlayRefMapPoint.cpp" line="43"/>
++ <source>bad coordinate</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="62"/>
++ <source>north</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="63"/>
++ <source>south</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>Error...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>The value
++&apos;%1&apos;
++is not a valid coordinate system definition:
++%2</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CSetupExtTools</name>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="63"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="64"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="65"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="66"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="67"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="68"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="80"/>
++ <source>Select %1 binary...</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CShell</name>
++ <message>
++ <location filename="../shell/CShell.cpp" line="41"/>
++ <source>Execution of external program `%1` failed: </source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="45"/>
++ <source>Process cannot be started.
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="46"/>
++ <source>Make sure the required packages are installed, `%1` exists and is executable.
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="50"/>
++ <source>External process crashed.
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="54"/>
++ <source>An unknown error occurred.
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="146"/>
++ <source>!!! failed !!!
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="161"/>
++ <source>
++Canceled by user&apos;s request.
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="191"/>
++ <source>!!! done !!!
++</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolAddOverview</name>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="30"/>
++ <source>Add Overviews</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="32"/>
++ <source>Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it&apos;s size will remain large. If you do not like that use the external option.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolCutMap</name>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="30"/>
++ <source>Cut Map</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="32"/>
++ <source>Paper maps usually have a border you don&apos;t want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolExport</name>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="30"/>
++ <source>Export Maps</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="33"/>
++ <source>To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="41"/>
++ <source>Note: This tool will use all files in the list as a input. This will only work if all files have the same projection.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="136"/>
++ <source>Select filename...</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolGrid</name>
++ <message>
++ <location filename="../tool/CToolGrid.cpp" line="37"/>
++ <source>By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolPalettize</name>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="30"/>
++ <source>Add Color Palette</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="34"/>
++ <source>Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="46"/>
++ <source>Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="109"/>
++ <source>Select filename...</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>CToolRefMap</name>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="34"/>
++ <source>Reference Map</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="36"/>
++ <source>A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IAbout</name>
++ <message>
++ <location filename="../IAbout.ui" line="14"/>
++ <source>About...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="26"/>
++ <source>&lt;b&gt;QMapTool&lt;/b&gt;, Version</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="39"/>
++ <location filename="../IAbout.ui" line="77"/>
++ <location filename="../IAbout.ui" line="91"/>
++ <location filename="../IAbout.ui" line="105"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="70"/>
++ <source>Qt</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="84"/>
++ <source>GDAL</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="98"/>
++ <source>Proj4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="121"/>
++ <source>This software is licensed under GPL3 or any later version</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="128"/>
++ <source>© 2017 Oliver Eichler (oliver.eichler@gmx.de)</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>ICoordFormatSetup</name>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="14"/>
++ <source>Coordinate Format...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="24"/>
++ <source>N48° 53&apos; 39.6&quot; E13° 31&apos; 6.78&quot;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="31"/>
++ <source>N48.8943° E013.51855°</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="38"/>
++ <source>N48° 53.660 E013° 31.113</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="14"/>
++ <source>Dialog</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="25"/>
++ <source>Coord. Map File [pixel]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="32"/>
++ <source>x</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="42"/>
++ <source>y</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="49"/>
++ <source>Coord. lat/lon WGS84 [°]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="59"/>
++ <source>Bad position format. Must be:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++or
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="150"/>
++ <source>Reset</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="224"/>
++ <source>Set Area</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="35"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="35"/>
++ <source>Grid Projection:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="47"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="60"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="72"/>
++ <source>Easting</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="82"/>
++ <source>Horiz. Spacing</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="92"/>
++ <source>Northing</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="102"/>
++ <source>Vert. Spacing</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IItemListWidget</name>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="40"/>
++ <source>Add map files to list</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="43"/>
++ <location filename="../items/IItemListWidget.ui" line="60"/>
++ <location filename="../items/IItemListWidget.ui" line="77"/>
++ <location filename="../items/IItemListWidget.ui" line="94"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="57"/>
++ <source>Remove selected file from the list.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="74"/>
++ <source>Clear complete list of map files.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="91"/>
++ <source>Reload the currently selected map.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IMainWindow</name>
++ <message>
++ <location filename="../IMainWindow.ui" line="14"/>
++ <source>MainWindow</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="32"/>
++ <source>Setup</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="41"/>
++ <source>View</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="47"/>
++ <source>Window</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="52"/>
++ <source>?</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="67"/>
++ <source>Tools</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="100"/>
++ <source>Shell</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="119"/>
++ <source>About</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="128"/>
++ <source>Ext. Tools</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="131"/>
++ <source>Setup paths to external tools, like gdalwarp etc.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="143"/>
++ <location filename="../IMainWindow.ui" line="146"/>
++ <source>Flip Mouse Wheel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="155"/>
++ <location filename="../IMainWindow.ui" line="158"/>
++ <source>Setup Units</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="167"/>
++ <source>Setup Coord. Format</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="170"/>
++ <source>Change the format coordinates are displayed</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="181"/>
++ <source>Show Tool Help</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayCutMap</name>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="35"/>
++ <source>Just move the map and zoom.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="58"/>
++ <source>Add point to mask.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="61"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="84"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="107"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="137"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="158"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="175"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="81"/>
++ <source>Move point of mask.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="104"/>
++ <source>Remove point from mask.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="134"/>
++ <source>Remove complete cut mask.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="155"/>
++ <source>Load cut mask from shape file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="172"/>
++ <source>Save cut mask to shape file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayGridTool</name>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="145"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayRefMap</name>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="40"/>
++ <source>Just move the map and zoom.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="63"/>
++ <source>Add reference point.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="66"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="89"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="112"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="135"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="165"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="179"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="200"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="217"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="244"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="326"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="86"/>
++ <source>Move reference point.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="109"/>
++ <source>Remove single reference point.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="132"/>
++ <source>Move reference points with auto mode. This will pickup the next point after you moved a reference point.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="162"/>
++ <source>Remove all reference points.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="176"/>
++ <source>Switch to the Grid Tool.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="197"/>
++ <source>Load reference points from GCP file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="214"/>
++ <source>Save reference points into GCP file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="241"/>
++ <source>Sort list of reference points.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="281"/>
++ <source>(x, y)[pixel]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="286"/>
++ <source>(lat, lon)[°]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="294"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="304"/>
++ <source>Final Map Projection:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="316"/>
++ <source>Enter a valid projection string. Valid strings are &quot;+proj...&quot; or &quot;+init=epsg:...&quot;.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="323"/>
++ <source>Start projection wizard.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="343"/>
++ <source>Delete</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="14"/>
++ <source>Proj4 Wizard</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="29"/>
++ <source>Mercator</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="38"/>
++ <source>UTM</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="45"/>
++ <source>zone</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="82"/>
++ <source>user defined</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="94"/>
++ <source>Datum</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="104"/>
++ <source>World Mercator (OSM)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="124"/>
++ <source>Result:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="138"/>
++ <source>UPS North (North Pole)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="145"/>
++ <source>UPS South (South Pole)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="152"/>
++ <source>Projection</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>ISetupExtTools</name>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="14"/>
++ <source>Setup Ext. Tools</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="22"/>
++ <location filename="../setup/ISetupExtTools.ui" line="64"/>
++ <location filename="../setup/ISetupExtTools.ui" line="99"/>
++ <location filename="../setup/ISetupExtTools.ui" line="173"/>
++ <location filename="../setup/ISetupExtTools.ui" line="194"/>
++ <location filename="../setup/ISetupExtTools.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="32"/>
++ <location filename="../setup/ISetupExtTools.ui" line="53"/>
++ <location filename="../setup/ISetupExtTools.ui" line="74"/>
++ <location filename="../setup/ISetupExtTools.ui" line="88"/>
++ <location filename="../setup/ISetupExtTools.ui" line="135"/>
++ <location filename="../setup/ISetupExtTools.ui" line="149"/>
++ <location filename="../setup/ISetupExtTools.ui" line="183"/>
++ <location filename="../setup/ISetupExtTools.ui" line="211"/>
++ <location filename="../setup/ISetupExtTools.ui" line="225"/>
++ <location filename="../setup/ISetupExtTools.ui" line="239"/>
++ <location filename="../setup/ISetupExtTools.ui" line="264"/>
++ <location filename="../setup/ISetupExtTools.ui" line="275"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="112"/>
++ <source>gdal_translate:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="43"/>
++ <source>gdalbuildvrt</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="166"/>
++ <source>gdaladdo:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="125"/>
++ <source>gdalwarp:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="29"/>
++ <location filename="../setup/ISetupExtTools.ui" line="132"/>
++ <location filename="../setup/ISetupExtTools.ui" line="180"/>
++ <location filename="../setup/ISetupExtTools.ui" line="208"/>
++ <location filename="../setup/ISetupExtTools.ui" line="222"/>
++ <source>Setup user defined path.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="201"/>
++ <source>qmt_rgb2pct</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="50"/>
++ <location filename="../setup/ISetupExtTools.ui" line="71"/>
++ <location filename="../setup/ISetupExtTools.ui" line="85"/>
++ <location filename="../setup/ISetupExtTools.ui" line="146"/>
++ <location filename="../setup/ISetupExtTools.ui" line="236"/>
++ <source>Reset user defined path setup.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="250"/>
++ <source>qmt_map2jnx</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="288"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; Usually QMapTool should detect all external tools by itself. If it does not, it&apos;s a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it&apos;s not setup properly you might get results but these can be off grid.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>ITimeZoneSetup</name>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="14"/>
++ <source>Setup Time Zone ...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="22"/>
++ <source>UTC</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="32"/>
++ <source>Local</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="42"/>
++ <source>Automatic</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="75"/>
++ <source>Print date/time in </source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="82"/>
++ <source>long format, or</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="92"/>
++ <source>short format</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolAddOverview</name>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="59"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="119"/>
++ <source>:2</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="126"/>
++ <source>:4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="133"/>
++ <source>:8</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="140"/>
++ <source>:16</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="147"/>
++ <source>:32</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="154"/>
++ <source>:64</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="164"/>
++ <source>Remove all overview levels from map file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="167"/>
++ <source>Remove</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="174"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="177"/>
++ <source>Overview as external file</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="207"/>
++ <source>Start</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="221"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="232"/>
++ <source>For all files</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolCutMap</name>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="114"/>
++ <source>Output filename suffix</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="133"/>
++ <source>_cut</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="148"/>
++ <source>Create overviews for result.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="176"/>
++ <source>Start</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="190"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="201"/>
++ <source>For all files</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="226"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="236"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolExport</name>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="59"/>
++ <location filename="../tool/IToolExport.ui" line="72"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="83"/>
++ <source>Garmin BirdsEye (*.jnx)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="88"/>
++ <source>TwoNav Raster (*.rmap)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="101"/>
++ <source>not implemented yet</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="112"/>
++ <source>Target File</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="130"/>
++ <source>Start</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="144"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="173"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_map2jnx&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="184"/>
++ <source>Target Filename</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolExportJnx</name>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="35"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="81"/>
++ <source>BirdsEye</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="50"/>
++ <source>Product ID</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="57"/>
++ <source>Copyright notice</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="64"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="95"/>
++ <source>None</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="71"/>
++ <source>Product name</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="88"/>
++ <source>Description</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="105"/>
++ <source>JPEG</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="133"/>
++ <source>Quality</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="140"/>
++ <source>Chroma subsampling</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="148"/>
++ <source>411</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="153"/>
++ <source>422</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="158"/>
++ <source>444</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="169"/>
++ <source>Device</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="184"/>
++ <source>Z-Order</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolGrid</name>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="56"/>
++ <source>Grid Tool</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="65"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="99"/>
++ <source>Ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="110"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="134"/>
++ <source>Reset</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolOverviewGroupBox</name>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="14"/>
++ <source>GroupBox</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="71"/>
++ <source>:2</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="78"/>
++ <source>:4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="85"/>
++ <source>:8</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="92"/>
++ <source>:16</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="99"/>
++ <source>:32</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="106"/>
++ <source>:64</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="119"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="122"/>
++ <source>Overview as external file</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolPalettize</name>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="65"/>
++ <location filename="../tool/IToolPalettize.ui" line="78"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="96"/>
++ <source>Single files, filename suffix</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="109"/>
++ <source>_8bit</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="123"/>
++ <source>Combined file, filename:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="135"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="142"/>
++ <source>Create overviews for result.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="170"/>
++ <source>Start</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="184"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="213"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="223"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="233"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_rgb2pct&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="247"/>
++ <source>Select filename</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolRefMap</name>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="113"/>
++ <source>Output filename suffix</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="132"/>
++ <source>_ref</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="144"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="151"/>
++ <source>Create overviews for result.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="179"/>
++ <source>Start</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="193"/>
++ <source>Cancel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="204"/>
++ <source>For all files</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="229"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="239"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="249"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IUnit</name>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Error</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <source>Bad position format. Must be: &quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot; or &quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Position values out of bounds. </source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IUnitsSetup</name>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="14"/>
++ <source>Setup units...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="24"/>
++ <source>Nautical</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="31"/>
++ <source>Imperial</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="38"/>
++ <source>Metric</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++</TS>
+diff --git a/src/qmaptool/locale/qmaptool_de.ts b/src/qmaptool/locale/qmaptool_de.ts
+new file mode 100644
+index 00000000..b3a43ef9
+--- /dev/null
++++ b/src/qmaptool/locale/qmaptool_de.ts
+@@ -0,0 +1,1712 @@
++<?xml version="1.0" encoding="utf-8"?>
++<!DOCTYPE TS>
++<TS version="2.0" language="de_DE">
++<context>
++ <name>CCanvas</name>
++ <message>
++ <location filename="../canvas/CCanvas.cpp" line="89"/>
++ <source>No map view available.</source>
++ <translation>Keine Kartenansicht verfügbar.</translation>
++ </message>
++</context>
++<context>
++ <name>CCommandProcessor</name>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="31"/>
++ <source>Print debug output to console.</source>
++ <translation>Debuginformation in der Konsole ausgeben.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="34"/>
++ <source>Print debug output to logfile (temp. path).</source>
++ <translation>Debuginformation in eine Datei schreiben (temp. Pfad).</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="37"/>
++ <source>Do not show splash screen.</source>
++ <translation>Das Anfangsbild nicht zeigen.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>File with QMapTool configuration.</source>
++ <translation>Eine Datei mit einer QMapTool-Konfiguration.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>file</source>
++ <translation>Datei</translation>
++ </message>
++</context>
++<context>
++ <name>CDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="39"/>
++ <source>bad coordinate</source>
++ <translation>ungültige Koordinate</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Error</source>
++ <translation>Fehler</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <source>Bad value for X pixel.</source>
++ <translation>Ungültiger Wert fur den X Wert des Bildpunktes.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Bad value for Y pixel.</source>
++ <translation>Ungültiger Wert fur den Y Wert des Bildpunktes.</translation>
++ </message>
++</context>
++<context>
++ <name>CDrawContextPixel</name>
++ <message>
++ <source>Error...</source>
++ <translation>Fehler...</translation>
++ </message>
++ <message>
++ <source>Failed to load file: %1</source>
++ <translation>Datei laden fehlgeschlagen: %1</translation>
++ </message>
++ <message>
++ <source>File must be 8 bit palette or gray indexed.</source>
++ <translation>Die Datei muss eine 8 Bit Farbpalette haben oder einen Graustufenindex.</translation>
++ </message>
++ <message>
++ <source>(color table)</source>
++ <translation>(Farbtabelle)</translation>
++ </message>
++ <message>
++ <source>(unknown)</source>
++ <translation>(unbekannt)</translation>
++ </message>
++ <message>
++ <location filename="../canvas/CDrawContextPixel.cpp" line="73"/>
++ <source>Failed to load</source>
++ <translation>Datei laden fehlgeschlagen</translation>
++ </message>
++</context>
++<context>
++ <name>CGdalFile</name>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>Error...</source>
++ <translation>Fehler...</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <source>Failed to load file: %1</source>
++ <translation>Datei laden fehlgeschlagen: %1</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>File must be 8 bit palette or gray indexed.</source>
++ <translation>Die Datei muss eine 8 Bit Farbpalette haben oder einen Graustufenindex.</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="179"/>
++ <source>(color table)</source>
++ <translation>(Farbtabelle)</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="183"/>
++ <source>(RGB)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="187"/>
++ <source>(RGBA)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="191"/>
++ <source>(unknown)</source>
++ <translation>(unbekannt)</translation>
++ </message>
++</context>
++<context>
++ <name>CGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="34"/>
++ <source>Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed.</source>
++ <translation>Wählen Sie eine Ecke aus und platzieren Sie die Markierung auf dem jeweiligen Gitterpunkt der Karte. Alle 4 Ecken müssen gesetzt werden.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="160"/>
++ <source>Point 1 - not set</source>
++ <translation>Punkt 1 - nicht gesetzt</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="164"/>
++ <source>Point 1 - ok</source>
++ <translation>Punkt 1 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="169"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="174"/>
++ <source>Point 1 - bad</source>
++ <translation>Punkt 1 - falsch</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="185"/>
++ <source>Point 2 - ok</source>
++ <translation>Punkt 2 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="190"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="195"/>
++ <source>Point 2 - bad</source>
++ <translation>Punkt 2 - falsch</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="207"/>
++ <source>Point 3 - ok</source>
++ <translation>Punkt 3 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="212"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="217"/>
++ <source>Point 3 - bad</source>
++ <translation>Punkt 3 - falsch</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="229"/>
++ <source>Point 4 - ok</source>
++ <translation>Punkt 4 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="234"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="239"/>
++ <source>Point 4 - bad</source>
++ <translation>Punkt 4 - falsch</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="181"/>
++ <source>Point 2 - not set</source>
++ <translation>Punkt 2 - nicht gesetzt</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="203"/>
++ <source>Point 3 - not set</source>
++ <translation>Punkt 3 - nicht gesetzt</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="225"/>
++ <source>Point 4 - not set</source>
++ <translation>Punkt 4 - nicht gesetzt</translation>
++ </message>
++</context>
++<context>
++ <name>CGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSelArea.cpp" line="30"/>
++ <source>Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click.</source>
++ <translation>Wählen Sie das Gebiet aus, für das Referenzpunkte berechnet werden sollen. Klicken Sie dazu einfach auf die Ecken des Auswahlrechtecks mit der linken Maustaste und platzieren die Ecke wo Sie wollen mit einem zweiten Klick.</translation>
++ </message>
++</context>
++<context>
++ <name>CGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSetRef.cpp" line="37"/>
++ <source>Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. &quot;48.2&quot; or &quot;12.4&quot;. For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red.</source>
++ <translation>Gültige Koordinatenformate: Wenn die Projektion lat/lon Werte benötigt, müssen alle Eingaben in Grad sein, z.B. &quot;48.2&quot; oder &quot;12.4&quot;. Für alle anderen Projektionen sind die Eingaben entweder in Meter oder in Fuß. Wenn etwas falsch ist, werden die Eingabefelder rot.</translation>
++ </message>
++</context>
++<context>
++ <name>CItemListWidget</name>
++ <message>
++ <location filename="../items/CItemListWidget.cpp" line="103"/>
++ <source>Select files...</source>
++ <translation>Dateien auswählen...</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayCutMap</name>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Delete mask...</source>
++ <translation>Maske löschen...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Are you sure to delete complete mask?</source>
++ <translation>Wollen Sie wirklich die gesamte Maske löschen?</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="239"/>
++ <source>Save mask...</source>
++ <translation>Maske speichern...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="287"/>
++ <source>Load mask...</source>
++ <translation>Maske laden...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Failed...</source>
++ <translation>Fehlgeschlagen...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Not a shape file.</source>
++ <translation>Keine Shape-Datei.</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayGridTool</name>
++ <message>
++ <location filename="../overlay/COverlayGridTool.cpp" line="34"/>
++ <source>Before you proceed with &apos;ok&apos;:
++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it&apos;s much more effort to set additional points in case you miss some. When you are done press &apos;ok&apos; to transfer the derived reference points to the Reference Tool.
++
++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map.</source>
++ <translation>Bevor Sie mit &apos;ok&apos; fortfahren:
++Bitte überprüfen Sie alle Eingaben erneut. Ein falsche Referenzkoordinate ruiniert die ganze Arbeit. Überprüfen Sie bitte auch, ob das ausgewählte Gebiet an den Grenzen so viele Referenzpunkte wie möglich beinhaltet. Punkte außerhalb der Karte lassen sich recht einfach löschen. Neue Punkte hinzufügen, sollten welche fehlen, ist wesentlich aufwändiger. Wenn Sie fertig sind drücken Sie &apos;ok&apos;, um die berechneten Punkte in das Referenzwerkzeug zu übertragen.
++
++Im nächsten Schritte benutzen Sie das Referenzwerkzeug, um die Positionen von allen Referenzpunkten auf die tatsächlichen Gitterpunkte der Karte zu verschieben. </translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMap</name>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="42"/>
++ <source>If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task.
++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list.
++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points.</source>
++ <translation>Wenn Sie das Gitterwerkzeug benutzt haben, müssen Sie die Punkte noch justieren, indem Sie sie auf die Gitterpunkte verschieben. Seien Sie sich bewusst, dass wenn Sie besonders nahe heranzoomen, die Punkte auf Grund von Rundungseffekten springen können. Seien sie beim Positionieren exakt, aber machen Sie daraus keine Religion.
++
++Wenn ihr Mausfokus auf der Karte ist, können Sie die N und B Tasten benützen, um sich in der Referenzpunktliste vor und zurück zu bewegen.
++Es gibt außerdem die Option, die Referenzpunkte im Automode zu justieren. In diesem Modus wird der nächste Referenzpunkt automatisch ausgewählt, nachdem Sie den aktuellen Punkt platziert haben. Diese Funktion ist sehr praktisch, wenn Sie eine große Anzahl an Punkten bearbeiten wollen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="614"/>
++ <source>Save reference points...</source>
++ <translation>Referenzpunkte speichern...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="653"/>
++ <source>Load reference points...</source>
++ <translation>Referenzpunkte laden...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Delete all reference points...</source>
++ <translation>Alle Referenzpunkte löschen...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Are you sure to delete all reference points in the list?</source>
++ <translation>Sind Sie sicher, dass Sie alle Referenzpunkte aus der Liste löschen wollen?</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete...</source>
++ <translation>Löschen...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete all selected reference points?</source>
++ <translation>Alle ausgewählten Referenzpunkte löschen?</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMapPoint</name>
++ <message>
++ <location filename="../overlay/refmap/COverlayRefMapPoint.cpp" line="43"/>
++ <source>bad coordinate</source>
++ <translation>ungültige Koordinate</translation>
++ </message>
++</context>
++<context>
++ <name>CProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="62"/>
++ <source>north</source>
++ <translation>Nord</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="63"/>
++ <source>south</source>
++ <translation>Süd</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>Error...</source>
++ <translation>Fehler...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>The value
++&apos;%1&apos;
++is not a valid coordinate system definition:
++%2</source>
++ <translation>Die Eingabe
++&apos;%1&apos;
++ist keine gültige Koordinatensystemdefinition:
++%2</translation>
++ </message>
++</context>
++<context>
++ <name>CSetupExtTools</name>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="63"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="64"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="65"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="66"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="67"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="68"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;nicht gefunden&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="80"/>
++ <source>Select %1 binary...</source>
++ <translation>Programm %1 auswählen...</translation>
++ </message>
++</context>
++<context>
++ <name>CShell</name>
++ <message>
++ <location filename="../shell/CShell.cpp" line="41"/>
++ <source>Execution of external program `%1` failed: </source>
++ <translation>Ausführen der externen Anwendung &apos;%1&apos; fehlgeschlagen:</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="45"/>
++ <source>Process cannot be started.
++</source>
++ <translation>Der Prozess kann nicht gestartet werden.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="46"/>
++ <source>Make sure the required packages are installed, `%1` exists and is executable.
++</source>
++ <translation>Stellen Sie sicher, dass alle benötigten Pakete installiert sind, &apos;%1&apos; vorhanden und ausführbar ist.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="50"/>
++ <source>External process crashed.
++</source>
++ <translation>Der externe Prozess ist abgestürzt.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="54"/>
++ <source>An unknown error occurred.
++</source>
++ <translation>Ein unbekannter Fehler ist aufgetreten.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="146"/>
++ <source>!!! failed !!!
++</source>
++ <translation>!!! fehlgeschlagen !!!</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="161"/>
++ <source>
++Canceled by user&apos;s request.
++</source>
++ <translation>
++Durch den Benutzer abgebrochen.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="191"/>
++ <source>!!! done !!!
++</source>
++ <translation>!!! fertig !!!</translation>
++ </message>
++</context>
++<context>
++ <name>CToolAddOverview</name>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="30"/>
++ <source>Add Overviews</source>
++ <translation>Übersichten hinzufügen</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="32"/>
++ <source>Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it&apos;s size will remain large. If you do not like that use the external option.</source>
++ <translation>Rasterkarten benötigen recht viel Speicher, wenn ein größeres Gebiet angezeigt werden soll. Vorberechnete Übersichtsebenen helfen dabei, die Karte schnell zu laden und anzuzeigen. Diese Übersichtsebenen können in der Kartendatei oder als externe Datei gespeichert werden. GDAL kann zwar interne Übersichtsebenen entfernen, gibt dabei aber leider den Speicher nicht frei. Deswegen wird die Datei groß bleiben. Wenn Sie das nicht wünschen, dann sollten Sie die Option zur Erstellung einer externen Datei verwenden.</translation>
++ </message>
++</context>
++<context>
++ <name>CToolCutMap</name>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="30"/>
++ <source>Cut Map</source>
++ <translation>Karte freistellen</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="32"/>
++ <source>Paper maps usually have a border you don&apos;t want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map.</source>
++ <translation>Papierkarten haben üblicherweise einen Rand, den man nicht dabei haben will. Um Karten blattschnittfrei zu kombinieren, muss man diesen Rand ausschneiden und durch transparente Bildpunkte ersetzen. Dieses Werkzeug ermöglicht es Ihnen, eine Schnittmaske zu erstellen, um damit einen Alphakanal mit den transparenten Bildpunkten zu erstellen. </translation>
++ </message>
++</context>
++<context>
++ <name>CToolExport</name>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="30"/>
++ <source>Export Maps</source>
++ <translation>Karten exportieren</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="33"/>
++ <source>To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale.</source>
++ <translation>Wenn Sie die Karten auf ihrem Gerät benützen wollen, müssen Sie diese in das jeweilige geschlossene Format. welches vom Gerät verwendet wird, exportieren. Abhängig vom Gerät kann das eine Karte mit einer einzelnen Auflösungsbene sein, oder eine mit mehreren Ebenen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="41"/>
++ <source>Note: This tool will use all files in the list as a input. This will only work if all files have the same projection.</source>
++ <translation>Hinweis: Dieses Werkzeug verwendet alle Dateien in der Liste als Eingabe. Das funktioniert nur, wenn alle Karten die selbe Projektion verwenden.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="136"/>
++ <source>Select filename...</source>
++ <translation>Dateinamen auswählen...</translation>
++ </message>
++</context>
++<context>
++ <name>CToolGrid</name>
++ <message>
++ <location filename="../tool/CToolGrid.cpp" line="37"/>
++ <source>By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated.</source>
++ <translation>Indem Sie 4 Referenzpunkte in den Ecken eines Gitterquadrates setzen und diese über die obere linke Ecke und die Breite und Höhe referenzieren, können alle anderen Gitterpunkte ungefähr berechnet werden.</translation>
++ </message>
++</context>
++<context>
++ <name>CToolPalettize</name>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="30"/>
++ <source>Add Color Palette</source>
++ <translation>Farbtabelle erzeugen</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="34"/>
++ <source>Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette.</source>
++ <translation>Üblicherweise benützt man RGBA Farben während man eine Karte referenziert, weil der große Farbraum einem erlaubt, die Karte ohne Qualitätseinbuße zu drehen und zu skalieren. Leider wird deswegen auch die Datei sehr groß. Die Größe kann optimiert werden, wenn man eine Farbpalette anstelle von RGBA verwendet. Die Qualitätseinbußen sind gering, solange man die Karte nicht drehen oder skalieren möchte. Wenn Sie mehrer Karten zusammenfügen wolle, müssen alle dieselbe Palette benützen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="46"/>
++ <source>Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale.</source>
++ <translation>Anmerkung: Dieses Werkzeug benützt alle Dateien in der Liste als gemeinsame Eingabe, um eine optimale Palette zu berechnen. Das kann nur funktionieren, wenn alle Dateien die gleiche Projektion und Skalierung haben.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="109"/>
++ <source>Select filename...</source>
++ <translation>Dateinamen auswählen...</translation>
++ </message>
++</context>
++<context>
++ <name>CToolRefMap</name>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="34"/>
++ <source>Reference Map</source>
++ <translation>Karte referenzieren</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="36"/>
++ <source>A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool.</source>
++ <translation>Eine gescannte Papierkarte kann in eine referenzierte Rasterkarte umgewandelt werden, indem Sie mindestens 3 Referenzpunkte auf der Karte angeben. Je mehr Punkte Sie setzen, desto besser. Wenn ihre Karte eine Gitter besitzt, können Sie Punkte auf dem Gitter mit dem Gitterwerkzeug setzen.</translation>
++ </message>
++</context>
++<context>
++ <name>IAbout</name>
++ <message>
++ <location filename="../IAbout.ui" line="14"/>
++ <source>About...</source>
++ <translation>Über...</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="26"/>
++ <source>&lt;b&gt;QMapTool&lt;/b&gt;, Version</source>
++ <translation>&lt;b&gt;QMapTool&lt;/b&gt;, Version</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="39"/>
++ <location filename="../IAbout.ui" line="77"/>
++ <location filename="../IAbout.ui" line="91"/>
++ <location filename="../IAbout.ui" line="105"/>
++ <source>TextLabel</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="70"/>
++ <source>Qt</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="84"/>
++ <source>GDAL</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="98"/>
++ <source>Proj4</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="121"/>
++ <source>This software is licensed under GPL3 or any later version</source>
++ <translation>Diese Software steht unter der GPL3 Lizenz, oder einer neueren Version</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="128"/>
++ <source>© 2017 Oliver Eichler (oliver.eichler@gmx.de)</source>
++ <translation></translation>
++ </message>
++</context>
++<context>
++ <name>ICoordFormatSetup</name>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="14"/>
++ <source>Coordinate Format...</source>
++ <translation>Koordinatenformat...</translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="24"/>
++ <source>N48° 53&apos; 39.6&quot; E13° 31&apos; 6.78&quot;</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="31"/>
++ <source>N48.8943° E013.51855°</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="38"/>
++ <source>N48° 53.660 E013° 31.113</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation>&lt;b&gt;Anmerkung:&lt;/b&gt; Bei einigen GUI Elementen wird die Änderung erst mit einem Neustart von QMapTool übernommen.</translation>
++ </message>
++</context>
++<context>
++ <name>IDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="14"/>
++ <source>Dialog</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="25"/>
++ <source>Coord. Map File [pixel]</source>
++ <translation>Koord. Karte [pixel]</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="32"/>
++ <source>x</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="42"/>
++ <source>y</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="49"/>
++ <source>Coord. lat/lon WGS84 [°]</source>
++ <translation>Koord. lat/lon WGS84 [°]</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="59"/>
++ <source>Bad position format. Must be:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++or
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation>Falsches Format. Entweder:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++oder
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</translation>
++ </message>
++</context>
++<context>
++ <name>IGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="150"/>
++ <source>Reset</source>
++ <translation>Zurücksetzen</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="224"/>
++ <source>Set Area</source>
++ <translation>Abdeckung</translation>
++ </message>
++</context>
++<context>
++ <name>IGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="35"/>
++ <source>TextLabel</source>
++ <translation></translation>
++ </message>
++</context>
++<context>
++ <name>IGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="35"/>
++ <source>Grid Projection:</source>
++ <translation>Gitterprojektion:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="47"/>
++ <source>...</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="60"/>
++ <source>TextLabel</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="72"/>
++ <source>Easting</source>
++ <translation>Ostwert</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="82"/>
++ <source>Horiz. Spacing</source>
++ <translation>horiz. Abstand</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="92"/>
++ <source>Northing</source>
++ <translation>Nordwert</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="102"/>
++ <source>Vert. Spacing</source>
++ <translation>vert. Abstand</translation>
++ </message>
++</context>
++<context>
++ <name>IItemListWidget</name>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="40"/>
++ <source>Add map files to list</source>
++ <translation>Kartendateien zur Liste hinzufügen</translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="43"/>
++ <location filename="../items/IItemListWidget.ui" line="60"/>
++ <location filename="../items/IItemListWidget.ui" line="77"/>
++ <location filename="../items/IItemListWidget.ui" line="94"/>
++ <source>...</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="57"/>
++ <source>Remove selected file from the list.</source>
++ <translation>Ausgewählte Dateien aus der Liste entfernen.</translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="74"/>
++ <source>Clear complete list of map files.</source>
++ <translation>Die komplette Kartendateiliste löschen. </translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="91"/>
++ <source>Reload the currently selected map.</source>
++ <translation>Die aktuell ausgewählte Karte erneut laden.</translation>
++ </message>
++</context>
++<context>
++ <name>IMainWindow</name>
++ <message>
++ <location filename="../IMainWindow.ui" line="14"/>
++ <source>MainWindow</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="32"/>
++ <source>Setup</source>
++ <translation>Einrichten</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="41"/>
++ <source>View</source>
++ <translation>Ansicht</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="47"/>
++ <source>Window</source>
++ <translation>Fenster</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="52"/>
++ <source>?</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="67"/>
++ <source>Tools</source>
++ <translation>Werkzeuge</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="100"/>
++ <source>Shell</source>
++ <translation>Shell</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="119"/>
++ <source>About</source>
++ <translation>Über</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="128"/>
++ <source>Ext. Tools</source>
++ <translation>Ext. Werkzeuge</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="131"/>
++ <source>Setup paths to external tools, like gdalwarp etc.</source>
++ <translation>Pfade zu den externen Werkzeugen, wie z.B. gdalwarp, einrichten.</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="143"/>
++ <location filename="../IMainWindow.ui" line="146"/>
++ <source>Flip Mouse Wheel</source>
++ <translation>Mausrad umdrehen</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="155"/>
++ <location filename="../IMainWindow.ui" line="158"/>
++ <source>Setup Units</source>
++ <translation>Einheiten einrichten</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="167"/>
++ <source>Setup Coord. Format</source>
++ <translation>Koordinatenformat einrichten</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="170"/>
++ <source>Change the format coordinates are displayed</source>
++ <translation>Das Format, in dem die Koordinaten angezeigt werden, ändern</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="181"/>
++ <source>Show Tool Help</source>
++ <translation>Hilfstexte anzeigen</translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayCutMap</name>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="35"/>
++ <source>Just move the map and zoom.</source>
++ <translation>Die Karte verschieben und zoomen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="58"/>
++ <source>Add point to mask.</source>
++ <translation>Punkte zur Maske hinzufügen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="61"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="84"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="107"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="137"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="158"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="175"/>
++ <source>...</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="81"/>
++ <source>Move point of mask.</source>
++ <translation>Maskenpunkte verschieben.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="104"/>
++ <source>Remove point from mask.</source>
++ <translation>Punkte aus der Maske entfernen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="134"/>
++ <source>Remove complete cut mask.</source>
++ <translation>Die komplette Freistellmaske entfernen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="155"/>
++ <source>Load cut mask from shape file.</source>
++ <translation>Freistellmaske aus einer Shapedatei laden.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="172"/>
++ <source>Save cut mask to shape file.</source>
++ <translation>Freistellmaske in einer Shapedatei speichern.</translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayGridTool</name>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="145"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayRefMap</name>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="40"/>
++ <source>Just move the map and zoom.</source>
++ <translation>Die Karte verschieben und zoomen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="63"/>
++ <source>Add reference point.</source>
++ <translation>Referenzpunkte hinzufügen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="66"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="89"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="112"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="135"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="165"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="179"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="200"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="217"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="244"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="326"/>
++ <source>...</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="86"/>
++ <source>Move reference point.</source>
++ <translation>Referenzpunkte verschieben.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="109"/>
++ <source>Remove single reference point.</source>
++ <translation>Referenzpunkte löschen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="132"/>
++ <source>Move reference points with auto mode. This will pickup the next point after you moved a reference point.</source>
++ <translation>Referenzpunkte im Automode verschieben. Nachdem der aktuelle Punkt verschoben wurde, wird automatisch der Nächste genommen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="162"/>
++ <source>Remove all reference points.</source>
++ <translation>Alle Referenzpunkte löschen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="176"/>
++ <source>Switch to the Grid Tool.</source>
++ <translation>Auf das Gitterwerkzeug umschalten.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="197"/>
++ <source>Load reference points from GCP file.</source>
++ <translation>Referenzpunkte aus einer GCP Datei lesen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="214"/>
++ <source>Save reference points into GCP file.</source>
++ <translation>Referenzpunkte in eine GCP Datei speichern.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="241"/>
++ <source>Sort list of reference points.</source>
++ <translation>Die Liste der Referenzpunkte sortieren.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="281"/>
++ <source>(x, y)[pixel]</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="286"/>
++ <source>(lat, lon)[°]</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="294"/>
++ <source>TextLabel</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="304"/>
++ <source>Final Map Projection:</source>
++ <translation>Endgültige Kartenprojektion:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="316"/>
++ <source>Enter a valid projection string. Valid strings are &quot;+proj...&quot; or &quot;+init=epsg:...&quot;.</source>
++ <translation>Geben Sie einen gültigen Projektionstext ein. Gültige Formen sind &quot;+proj=...&quot; oder &quot;+init=...&quot;.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="323"/>
++ <source>Start projection wizard.</source>
++ <translation>Den Projektionsassistenten öffnen.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="343"/>
++ <source>Delete</source>
++ <translation>Löschen</translation>
++ </message>
++</context>
++<context>
++ <name>IProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="14"/>
++ <source>Proj4 Wizard</source>
++ <translation>Proj4 Assistent</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="29"/>
++ <source>Mercator</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="38"/>
++ <source>UTM</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="45"/>
++ <source>zone</source>
++ <translation>Zone</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="82"/>
++ <source>user defined</source>
++ <translation>benutzerdefiniert</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="94"/>
++ <source>Datum</source>
++ <translation>Datum</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="104"/>
++ <source>World Mercator (OSM)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="124"/>
++ <source>Result:</source>
++ <translation>Ergebnis:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="138"/>
++ <source>UPS North (North Pole)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="145"/>
++ <source>UPS South (South Pole)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="152"/>
++ <source>Projection</source>
++ <translation>Projektion</translation>
++ </message>
++</context>
++<context>
++ <name>ISetupExtTools</name>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="14"/>
++ <source>Setup Ext. Tools</source>
++ <translation>Externe Werkzeuge einstellen</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="22"/>
++ <location filename="../setup/ISetupExtTools.ui" line="64"/>
++ <location filename="../setup/ISetupExtTools.ui" line="99"/>
++ <location filename="../setup/ISetupExtTools.ui" line="173"/>
++ <location filename="../setup/ISetupExtTools.ui" line="194"/>
++ <location filename="../setup/ISetupExtTools.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;nicht gefunden&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="32"/>
++ <location filename="../setup/ISetupExtTools.ui" line="53"/>
++ <location filename="../setup/ISetupExtTools.ui" line="74"/>
++ <location filename="../setup/ISetupExtTools.ui" line="88"/>
++ <location filename="../setup/ISetupExtTools.ui" line="135"/>
++ <location filename="../setup/ISetupExtTools.ui" line="149"/>
++ <location filename="../setup/ISetupExtTools.ui" line="183"/>
++ <location filename="../setup/ISetupExtTools.ui" line="211"/>
++ <location filename="../setup/ISetupExtTools.ui" line="225"/>
++ <location filename="../setup/ISetupExtTools.ui" line="239"/>
++ <location filename="../setup/ISetupExtTools.ui" line="264"/>
++ <location filename="../setup/ISetupExtTools.ui" line="275"/>
++ <source>...</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="112"/>
++ <source>gdal_translate:</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="43"/>
++ <source>gdalbuildvrt</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="166"/>
++ <source>gdaladdo:</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="125"/>
++ <source>gdalwarp:</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="29"/>
++ <location filename="../setup/ISetupExtTools.ui" line="132"/>
++ <location filename="../setup/ISetupExtTools.ui" line="180"/>
++ <location filename="../setup/ISetupExtTools.ui" line="208"/>
++ <location filename="../setup/ISetupExtTools.ui" line="222"/>
++ <source>Setup user defined path.</source>
++ <translation>Benutzerdefinierten Pfad einstellen.</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="201"/>
++ <source>qmt_rgb2pct</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="50"/>
++ <location filename="../setup/ISetupExtTools.ui" line="71"/>
++ <location filename="../setup/ISetupExtTools.ui" line="85"/>
++ <location filename="../setup/ISetupExtTools.ui" line="146"/>
++ <location filename="../setup/ISetupExtTools.ui" line="236"/>
++ <source>Reset user defined path setup.</source>
++ <translation>Benutzerdefinierten Pfad zurücksetzen.</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="250"/>
++ <source>qmt_map2jnx</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="288"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; Usually QMapTool should detect all external tools by itself. If it does not, it&apos;s a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it&apos;s not setup properly you might get results but these can be off grid.</source>
++ <translation>&lt;b&gt;Anmerkung:&lt;/b&gt; Normalerweise sollte QMapTool alle externen Werkzeuge selber finden. Wenn das nicht gelingt, liegt es in der Regel an einer schlechten Einstellung und Sie sollten die PATH Variable ihres Systems überprüfen. Man kann die Werkzeugpfade auch selber setzen. Vorausgesetzt, man weiß was man macht. Bitte bedenken Sie, dass GDAL eine ordentlich aufgesetzte Umgebung benötigt, um fachgerecht zu funktionieren. Wenn dem nicht so ist, können durchaus Ergebnisse erzielt werden, diese können aber verschoben sein.</translation>
++ </message>
++</context>
++<context>
++ <name>ITimeZoneSetup</name>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="14"/>
++ <source>Setup Time Zone ...</source>
++ <translation>Zeitzone einstellen...</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="22"/>
++ <source>UTC</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="32"/>
++ <source>Local</source>
++ <translation>Lokal</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="42"/>
++ <source>Automatic</source>
++ <translation>Automatisch</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="75"/>
++ <source>Print date/time in </source>
++ <translation>Datum/Zeit anzeigen im</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="82"/>
++ <source>long format, or</source>
++ <translation>langen Format</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="92"/>
++ <source>short format</source>
++ <translation>kurzen Format</translation>
++ </message>
++</context>
++<context>
++ <name>IToolAddOverview</name>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="59"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="119"/>
++ <source>:2</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="126"/>
++ <source>:4</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="133"/>
++ <source>:8</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="140"/>
++ <source>:16</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="147"/>
++ <source>:32</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="154"/>
++ <source>:64</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="164"/>
++ <source>Remove all overview levels from map file.</source>
++ <translation>Alle Übersichten aus der Kartendatei entfernen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="167"/>
++ <source>Remove</source>
++ <translation>Löschen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="174"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation>Die Übersichten nicht in der Datei selbst anlegen. Als extra Datei hinzufügen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="177"/>
++ <source>Overview as external file</source>
++ <translation>Übersichten als externe Datei</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="207"/>
++ <source>Start</source>
++ <translation>Start</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="221"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="232"/>
++ <source>For all files</source>
++ <translation>Für alle Dateien</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdaladdo&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IToolCutMap</name>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="114"/>
++ <source>Output filename suffix</source>
++ <translation>Suffix der Ausgabedatei</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="133"/>
++ <source>_cut</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="148"/>
++ <source>Create overviews for result.</source>
++ <translation>Übersichten für das Ergebnis erzeugen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="176"/>
++ <source>Start</source>
++ <translation>Start</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="190"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="201"/>
++ <source>For all files</source>
++ <translation>Für alle Dateien</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="226"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdalwarp&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="236"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdaladdo&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IToolExport</name>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="59"/>
++ <location filename="../tool/IToolExport.ui" line="72"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="83"/>
++ <source>Garmin BirdsEye (*.jnx)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="88"/>
++ <source>TwoNav Raster (*.rmap)</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="101"/>
++ <source>not implemented yet</source>
++ <translation>noch nicht eingebaut</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="112"/>
++ <source>Target File</source>
++ <translation>Zieldatei</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="130"/>
++ <source>Start</source>
++ <translation>Start</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="144"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="173"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_map2jnx&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;qmt_map2jnx&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="184"/>
++ <source>Target Filename</source>
++ <translation>Dateiname der Zieldatei</translation>
++ </message>
++</context>
++<context>
++ <name>IToolExportJnx</name>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="35"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="81"/>
++ <source>BirdsEye</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="50"/>
++ <source>Product ID</source>
++ <translation>Produkt ID</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="57"/>
++ <source>Copyright notice</source>
++ <translation>Urheberhinweis</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="64"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="95"/>
++ <source>None</source>
++ <translation>Nichts</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="71"/>
++ <source>Product name</source>
++ <translation>Produktname</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="88"/>
++ <source>Description</source>
++ <translation>Beschreibung</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="105"/>
++ <source>JPEG</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="133"/>
++ <source>Quality</source>
++ <translation>Qualität
++</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="140"/>
++ <source>Chroma subsampling</source>
++ <translation>Halbttonunterabtastung</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="148"/>
++ <source>411</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="153"/>
++ <source>422</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="158"/>
++ <source>444</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="169"/>
++ <source>Device</source>
++ <translation>Gerät</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="184"/>
++ <source>Z-Order</source>
++ <translation>Reihenfolge (Z-Achse)</translation>
++ </message>
++</context>
++<context>
++ <name>IToolGrid</name>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="56"/>
++ <source>Grid Tool</source>
++ <translation>Gitterwerkzeug</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="65"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="99"/>
++ <source>Ok</source>
++ <translation>OK</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="110"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="134"/>
++ <source>Reset</source>
++ <translation>Zurücksetzen</translation>
++ </message>
++</context>
++<context>
++ <name>IToolOverviewGroupBox</name>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="14"/>
++ <source>GroupBox</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="71"/>
++ <source>:2</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="78"/>
++ <source>:4</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="85"/>
++ <source>:8</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="92"/>
++ <source>:16</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="99"/>
++ <source>:32</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="106"/>
++ <source>:64</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="119"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation>Die Übersichten nicht in der Datei selber anlegen. Als extra Datei hinzufügen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="122"/>
++ <source>Overview as external file</source>
++ <translation>Übersichten als externe Datei</translation>
++ </message>
++</context>
++<context>
++ <name>IToolPalettize</name>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="65"/>
++ <location filename="../tool/IToolPalettize.ui" line="78"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="96"/>
++ <source>Single files, filename suffix</source>
++ <translation>Einzelne Dateien, Dateinamensuffix</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="109"/>
++ <source>_8bit</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="123"/>
++ <source>Combined file, filename:</source>
++ <translation>In einer Datei zusammenfassen, Dateiname:</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="135"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation>Ergebnis in eine *.vrt Datei einbetten.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="142"/>
++ <source>Create overviews for result.</source>
++ <translation>Übersichten für das Ergebnis erzeugen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="170"/>
++ <source>Start</source>
++ <translation>Start</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="184"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="213"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdaladdo&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="223"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdal_translate&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="233"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_rgb2pct&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;qmt_rgb2pct&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="247"/>
++ <source>Select filename</source>
++ <translation>Dateinamen auswählen</translation>
++ </message>
++</context>
++<context>
++ <name>IToolRefMap</name>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="113"/>
++ <source>Output filename suffix</source>
++ <translation>Suffix der Ausgabedatei</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="132"/>
++ <source>_ref</source>
++ <translation></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="144"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation>Ergebnis in eine *.vrt Datei einbetten.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="151"/>
++ <source>Create overviews for result.</source>
++ <translation>Übersichten für das Ergebnis erzeugen.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="179"/>
++ <source>Start</source>
++ <translation>Start</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="193"/>
++ <source>Cancel</source>
++ <translation>Abbrechen</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="204"/>
++ <source>For all files</source>
++ <translation>Für alle Dateien</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="229"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdalwarp&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="239"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdal_translate&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="249"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;gdaladdo&quot;nicht gefunden. Bitte überprüfen Sie die Einstellungen!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IUnit</name>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Error</source>
++ <translation>Fehler</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <source>Bad position format. Must be: &quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot; or &quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation>Falsches Format. Entweder:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++oder
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Position values out of bounds. </source>
++ <translation>Positionswerte außerhalb der Grenzen. </translation>
++ </message>
++</context>
++<context>
++ <name>IUnitsSetup</name>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="14"/>
++ <source>Setup units...</source>
++ <translation>Einheiten einrichten...</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="24"/>
++ <source>Nautical</source>
++ <translation>nautisch</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="31"/>
++ <source>Imperial</source>
++ <translation>imperial</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="38"/>
++ <source>Metric</source>
++ <translation>metrisch</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation>&lt;b&gt;Anmerkung:&lt;/b&gt; Bei einigen GUI Elementen wird die Änderung erst mit einem Neustart von QMapTool übernommen.</translation>
++ </message>
++</context>
++</TS>
+diff --git a/src/qmaptool/locale/qmaptool_es.ts b/src/qmaptool/locale/qmaptool_es.ts
+new file mode 100644
+index 00000000..4b6a5cb3
+--- /dev/null
++++ b/src/qmaptool/locale/qmaptool_es.ts
+@@ -0,0 +1,1715 @@
++<?xml version="1.0" encoding="utf-8"?>
++<!DOCTYPE TS>
++<TS version="2.1">
++<context>
++ <name>CCanvas</name>
++ <message>
++ <location filename="../canvas/CCanvas.cpp" line="89"/>
++ <source>No map view available.</source>
++ <translation>Vista de mapa no disponible.</translation>
++ </message>
++</context>
++<context>
++ <name>CCommandProcessor</name>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="31"/>
++ <source>Print debug output to console.</source>
++ <translation>Mostrar salida de depuración en la consola.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="34"/>
++ <source>Print debug output to logfile (temp. path).</source>
++ <translation>Mostrar salida de depuración en archivo log (Carpeta temporal).</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="37"/>
++ <source>Do not show splash screen.</source>
++ <translation>No mostrar pantalla de bienvenida.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>File with QMapTool configuration.</source>
++ <translation>Archivo con la configuración de QMapTool.</translation>
++ </message>
++ <message>
++ <location filename="../setup/CCommandProcessor.cpp" line="40"/>
++ <source>file</source>
++ <translation>archivo</translation>
++ </message>
++</context>
++<context>
++ <name>CDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="39"/>
++ <source>bad coordinate</source>
++ <translation>Coordenada incorrecta</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Error</source>
++ <translation>Error</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="58"/>
++ <source>Bad value for X pixel.</source>
++ <translation>Valor incorrecto para el pixel X.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CDialogRefPoint.cpp" line="64"/>
++ <source>Bad value for Y pixel.</source>
++ <translation>Valor incorrecto para el pixel Y.</translation>
++ </message>
++</context>
++<context>
++ <name>CDrawContextPixel</name>
++ <message>
++ <source>Error...</source>
++ <translation type="vanished">Error...</translation>
++ </message>
++ <message>
++ <source>Failed to load file: %1</source>
++ <translation type="vanished">Fallo al cargar el archivo: %1</translation>
++ </message>
++ <message>
++ <source>File must be 8 bit palette or gray indexed.</source>
++ <translation type="vanished">El archivo debe de tener una paleta superior a 8 bits o gris indexado.</translation>
++ </message>
++ <message>
++ <source>(color table)</source>
++ <translation type="vanished">(tabla de color)</translation>
++ </message>
++ <message>
++ <source>(RGB)</source>
++ <translation type="vanished">(RGB)</translation>
++ </message>
++ <message>
++ <source>(RGBA)</source>
++ <translation type="vanished">(RGBA)</translation>
++ </message>
++ <message>
++ <source>(unknown)</source>
++ <translation type="obsolete">(desconocido)</translation>
++ </message>
++ <message>
++ <location filename="../canvas/CDrawContextPixel.cpp" line="73"/>
++ <source>Failed to load</source>
++ <translation>Fallo al cargar</translation>
++ </message>
++</context>
++<context>
++ <name>CGdalFile</name>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>Error...</source>
++ <translation type="unfinished">Error...</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="52"/>
++ <location filename="../helpers/CGdalFile.cpp" line="65"/>
++ <source>Failed to load file: %1</source>
++ <translation type="unfinished">Fallo al cargar el archivo: %1</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="95"/>
++ <source>File must be 8 bit palette or gray indexed.</source>
++ <translation type="unfinished">El archivo debe de tener una paleta superior a 8 bits o gris indexado.</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="179"/>
++ <source>(color table)</source>
++ <translation type="unfinished">(tabla de color)</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="183"/>
++ <source>(RGB)</source>
++ <translation type="unfinished">(RGB)</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="187"/>
++ <source>(RGBA)</source>
++ <translation type="unfinished">(RGBA)</translation>
++ </message>
++ <message>
++ <location filename="../helpers/CGdalFile.cpp" line="191"/>
++ <source>(unknown)</source>
++ <translation type="unfinished">(desconocido)</translation>
++ </message>
++</context>
++<context>
++ <name>CGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="34"/>
++ <source>Select one of the corners and place the marker at the corresponding grid crossing on the map. All 4 corners have to be placed.</source>
++ <translation>Seleccionar una de las esquinas y colocar el marcador en el cruce de cuadrícula correspondiente en el mapa. Las 4 esquinas deben de estar colocadas.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="160"/>
++ <source>Point 1 - not set</source>
++ <translation>Punto 1 - no establecido</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="164"/>
++ <source>Point 1 - ok</source>
++ <translation>Punto 1 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="169"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="174"/>
++ <source>Point 1 - bad</source>
++ <translation>Punto 1 - error</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="185"/>
++ <source>Point 2 - ok</source>
++ <translation>Punto 2 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="190"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="195"/>
++ <source>Point 2 - bad</source>
++ <translation>Punto 2 - error</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="207"/>
++ <source>Point 3 - ok</source>
++ <translation>Punto 3 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="212"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="217"/>
++ <source>Point 3 - bad</source>
++ <translation>Punto 3 - error</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="229"/>
++ <source>Point 4 - ok</source>
++ <translation>Punto 4 - ok</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="234"/>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="239"/>
++ <source>Point 4 - bad</source>
++ <translation>Punto 4 - error</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="181"/>
++ <source>Point 2 - not set</source>
++ <translation>Punto 2 - no establecido</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="203"/>
++ <source>Point 3 - not set</source>
++ <translation>Punto 3 - no establecido</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/CGridPlacer.cpp" line="225"/>
++ <source>Point 4 - not set</source>
++ <translation>Punto 4 - no establecido</translation>
++ </message>
++</context>
++<context>
++ <name>CGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSelArea.cpp" line="30"/>
++ <source>Select the area to be covered by the calculated reference points. Simply grab the corners of the selection rectangle with a left click and place them where you want with a second click.</source>
++ <translation>Seleccionar el área cubierta por los puntos de referencia calculados. Coger las esquinas de la selección rectangular con un clic izquierdo y soltarlas en el nuevo emplazamiento con un segundo clic.</translation>
++ </message>
++</context>
++<context>
++ <name>CGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/CGridSetRef.cpp" line="37"/>
++ <source>Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. &quot;48.2&quot; or &quot;12.4&quot;. For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field will turn red.</source>
++ <translation>Formatos de coordenadas válidos: si la proyección es lat / lon, todos los valores deben estar en grados, p. &quot;48,2&quot; o &quot;12,4&quot;. Para el resto de las proyecciones, los valores están en múltiplos de metro o pies. Si te equivocas, el campo de entrada se pone rojo.</translation>
++ </message>
++</context>
++<context>
++ <name>CItemListWidget</name>
++ <message>
++ <location filename="../items/CItemListWidget.cpp" line="103"/>
++ <source>Select files...</source>
++ <translation>Seleccionar archivos...</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayCutMap</name>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Delete mask...</source>
++ <translation>Borrar máscara...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="222"/>
++ <source>Are you sure to delete complete mask?</source>
++ <translation>¿Estás seguro de eliminar la máscara completa?</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="239"/>
++ <source>Save mask...</source>
++ <translation>Guardar máscara...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="287"/>
++ <source>Load mask...</source>
++ <translation>Cargar máscara...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Failed...</source>
++ <translation>Fallo...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayCutMap.cpp" line="301"/>
++ <source>Not a shape file.</source>
++ <translation>No es un archivo shape.</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayGridTool</name>
++ <message>
++ <location filename="../overlay/COverlayGridTool.cpp" line="34"/>
++ <source>Before you proceed with &apos;ok&apos;:
++Please cross check all data once again. A bad reference coordinate will ruin all the work. Also cross check if the selected area contains as many reference points as possible at the border. You can easily delete points outside the map in the Reference Tool. But it&apos;s much more effort to set additional points in case you miss some. When you are done press &apos;ok&apos; to transfer the derived reference points to the Reference Tool.
++
++The next step will be to use the Reference Tool to adjust the position of all reference points to the real grid position on the map.</source>
++ <translation>Antes de continuar pulsando &apos;ok&apos;:
++Verificar los datos una vez más. Una coordenada errónea en la referencia arruinará todo el trabajo. Verificar también si el área seleccionada contiene tantos puntos como sea posible en el borde. Puedes eliminar puntos fácilmente fuera del mapa en la Herramienta de Referencia, pero es mas trabajoso establecer puntos adicionales en caso de que se pierda alguno. Cuando hayas terminado, pulsar &apos;ok&apos; para transferir los puntos a la Herramienta de Referencia.
++
++El siguiente paso será usar la herramienta de referencia para ajustar la posición de todos los puntos a la posición de la cuadrícula real del mapa.</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMap</name>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="42"/>
++ <source>If you used the Grid Tool you have to fine tune the reference points by placing them as much as possible on the grid crossing. Be aware that if you over scale you get jumping points by rounding effects. Be precise but do not make religion out of the task.
++If your mouse focus is on the map you can use the N and B keys to jump forward an backward in the reference point list.
++The is also the option to fine tune the reference points in auto-mode. In this mode the next reference point is selected automatically right after you placed the current one. This is very convenient for a large number of reference points.</source>
++ <translation>Si se utilizó la Herramienta de Cuadrícula, hay que ajustar los puntos de referencia colocándolos en el cruce de la cuadrícula lo máximo posible. Ten en cuenta que si sobre escalas obtendrás puntos con valores redondeados, se necesita precisión, pero tampoco es necesario exagerar.
++Si el mapa esta en el primer plano del foco del ratón, puedes usar las teclas N y B para avanzar y retroceder en la lista de puntos de referencia.
++También es la opción para ajustar los puntos de referencia en modo automático. En este modo, el siguiente punto de referencia se selecciona automáticamente justo después de que coloques el actual, muy conveniente cuando los puntos son muchos.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="614"/>
++ <source>Save reference points...</source>
++ <translation>Guardar puntos de referencia...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="653"/>
++ <source>Load reference points...</source>
++ <translation>Cargar puntos de referencia...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Delete all reference points...</source>
++ <translation>Borrar todos los puntos de referencia...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="694"/>
++ <source>Are you sure to delete all reference points in the list?</source>
++ <translation>¿Estás seguro de borrar todos los puntos de la lista?</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete...</source>
++ <translation>Borrar...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/COverlayRefMap.cpp" line="729"/>
++ <source>Delete all selected reference points?</source>
++ <translation>¿Borrar los puntos seleccionados?</translation>
++ </message>
++</context>
++<context>
++ <name>COverlayRefMapPoint</name>
++ <message>
++ <location filename="../overlay/refmap/COverlayRefMapPoint.cpp" line="43"/>
++ <source>bad coordinate</source>
++ <translation>Coordenada errónea</translation>
++ </message>
++</context>
++<context>
++ <name>CProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="62"/>
++ <source>north</source>
++ <translation>Norte</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="63"/>
++ <source>south</source>
++ <translation>Sur</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>Error...</source>
++ <translation>Error...</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/CProjWizard.cpp" line="227"/>
++ <source>The value
++&apos;%1&apos;
++is not a valid coordinate system definition:
++%2</source>
++ <translation>El valor
++&apos;%1&apos;
++No es una definición válida del sistema de coordenadas:
++%2</translation>
++ </message>
++</context>
++<context>
++ <name>CSetupExtTools</name>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="63"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="64"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="65"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="66"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="67"/>
++ <location filename="../setup/CSetupExtTools.cpp" line="68"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;no encontrado&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../setup/CSetupExtTools.cpp" line="80"/>
++ <source>Select %1 binary...</source>
++ <translation>Seleccionar %1 binario</translation>
++ </message>
++</context>
++<context>
++ <name>CShell</name>
++ <message>
++ <location filename="../shell/CShell.cpp" line="41"/>
++ <source>Execution of external program `%1` failed: </source>
++ <translation>La ejecución del programa externo `%1` falló:</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="45"/>
++ <source>Process cannot be started.
++</source>
++ <translation>El proceso no se puede iniciar.
++</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="46"/>
++ <source>Make sure the required packages are installed, `%1` exists and is executable.
++</source>
++ <translation>Asegúrate de que los paquetes requeridos están instalados, `%1` existe y es ejecutable.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="50"/>
++ <source>External process crashed.
++</source>
++ <translation>Proceso externo bloqueado.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="54"/>
++ <source>An unknown error occurred.
++</source>
++ <translation>Ha ocurrido un error desconocido</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="146"/>
++ <source>!!! failed !!!
++</source>
++ <translation>!!! falló !!!</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="161"/>
++ <source>
++Canceled by user&apos;s request.
++</source>
++ <translation>Cancelado por el usuario.</translation>
++ </message>
++ <message>
++ <location filename="../shell/CShell.cpp" line="191"/>
++ <source>!!! done !!!
++</source>
++ <translation>¡¡¡ hecho !!!</translation>
++ </message>
++</context>
++<context>
++ <name>CToolAddOverview</name>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="30"/>
++ <source>Add Overviews</source>
++ <translation>Añadir niveles de zoom</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolAddOverview.cpp" line="32"/>
++ <source>Raster map files consume quite some memory if a larger area is displayed. Pre-calculated overview levels help to speed up loading and displaying the map. These overviews can be stored within the map file as well as an external file. GDAL can remove internally stored overviews, however it will not free the used space in the file. Therefore it&apos;s size will remain large. If you do not like that use the external option.</source>
++ <translation>Cuando el área es muy grande los archivos de los mapas raster son muy pesados. Los distintos niveles de zoom aceleran la carga y visualización. Se pueden almacenar en el mismo archivo que el mapa o en otro distinto. GDAL puede eliminar los niveles de zoom almacenados internamente pero el tamaño del archivo seguirá siendo el mismo, no así cuando se almacenan en archivo externo.</translation>
++ </message>
++</context>
++<context>
++ <name>CToolCutMap</name>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="30"/>
++ <source>Cut Map</source>
++ <translation>Cortar Mapa</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolCutMap.cpp" line="32"/>
++ <source>Paper maps usually have a border you don&apos;t want to have. To combine maps seamlessly you have to cut that border, replacing it by transparent pixel. This tool allows you to define a cut line and it will add an alpha channel for transparency to your map.</source>
++ <translation>Los mapas en papel suelen tener un marco en blanco innecesario. Para unir mapas a la perfección, es necesario eliminar ese borde y reemplazarlo por un píxel transparente. Esta herramienta te permite definir una línea de corte y agregar un canal alfa para la transparencia del mapa.</translation>
++ </message>
++</context>
++<context>
++ <name>CToolExport</name>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="30"/>
++ <source>Export Maps</source>
++ <translation>Exportar Mapas</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="33"/>
++ <source>To use the maps on your device you have to export them to the proprietary format supported by the device. Depending on the device this can vary from a single layer map to a map stack with maps of different scale.</source>
++ <translation>Para poder ver los mapas en tu dispositivo hay que exportarlos a un formato que este admita, puede ser necesario un mapa multicapa con distintos niveles de zoom o de una sola capa.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="41"/>
++ <source>Note: This tool will use all files in the list as a input. This will only work if all files have the same projection.</source>
++ <translation>Nota: Esta herramienta usa todos los archivos de la lista. Es necesario que todos tengan la misma proyección.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolExport.cpp" line="136"/>
++ <source>Select filename...</source>
++ <translation>Seleccionar nombre de archivo...</translation>
++ </message>
++</context>
++<context>
++ <name>CToolGrid</name>
++ <message>
++ <location filename="../tool/CToolGrid.cpp" line="37"/>
++ <source>By placing 4 reference points at the corners of a grid square and referencing them by their top left corner, the width and height, all the other grid points can be estimated.</source>
++ <translation>Al poner los 4 puntos de referencia en las esquinas de un cuadrado de la cuadrícula y referenciarlos en ancho y alto por su esquina superior izquierda, todos los otros puntos se pueden estimar.</translation>
++ </message>
++</context>
++<context>
++ <name>CToolPalettize</name>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="30"/>
++ <source>Add Color Palette</source>
++ <translation>Añadir Paleta de Color</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="34"/>
++ <source>Usually you use RGBA color while referencing a map because the large color space allows you to scale and rotate the map without any loss of quality. But it results into rather large files. The file size can be optimized by using a color palette instead of the RGBA color space. The impact on quality is low as long as you do not want to scale or rotate the map. If you want to combine files with a color palette all files need to have the same palette.</source>
++ <translation>Por lo general, se utiliza color RGBA al referenciar un mapa, ya que el gran espacio de color permite escalar y rotar sin pérdida de calidad, pero los archivos resultan ser muy grandes, se puede optimizar utilizando una paleta de colores en lugar del espacio de color RGBA. El impacto en la calidad es bajo siempre y cuando no quieras escalar o rotar. Si quieres combinar archivos con paleta de colores, todos deben de tener la misma.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="46"/>
++ <source>Note: This tool will use all files in the list as a combined input to derive an optimal palette. This will only work if all files have the same projection and scale.</source>
++ <translation>Nota: Esta herramienta utilizará los archivos de la lista para obtener una paleta óptima. Solo funcionará si todos los archivos tienen la misma proyección y escala.</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolPalettize.cpp" line="109"/>
++ <source>Select filename...</source>
++ <translation>Seleccionar nombre de archivo...</translation>
++ </message>
++</context>
++<context>
++ <name>CToolRefMap</name>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="34"/>
++ <source>Reference Map</source>
++ <translation>Referenciar Mapa</translation>
++ </message>
++ <message>
++ <location filename="../tool/CToolRefMap.cpp" line="36"/>
++ <source>A scan of a paper map can be converted to a referenced raster map if you place at least three reference points on the map. The more points the better the result. If your map has a grid you can place points on that grid with the grid tool.</source>
++ <translation>Un mapa de papel escaneado se puede convertir en un mapa ráster referenciado poniendo al menos tres puntos de referencia en el mapa. Cuantos más puntos, mejor es el resultado. Si el mapa tiene una cuadrícula, se pueden poner puntos en esa cuadrícula con la herramienta de cuadrícula.</translation>
++ </message>
++</context>
++<context>
++ <name>IAbout</name>
++ <message>
++ <location filename="../IAbout.ui" line="14"/>
++ <source>About...</source>
++ <translation>Acerca de...</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="26"/>
++ <source>&lt;b&gt;QMapTool&lt;/b&gt;, Version</source>
++ <translation>&lt;b&gt;QMapTool&lt;/b&gt;, Versión</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="39"/>
++ <location filename="../IAbout.ui" line="77"/>
++ <location filename="../IAbout.ui" line="91"/>
++ <location filename="../IAbout.ui" line="105"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="70"/>
++ <source>Qt</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="84"/>
++ <source>GDAL</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="98"/>
++ <source>Proj4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="121"/>
++ <source>This software is licensed under GPL3 or any later version</source>
++ <translation>Este programa está bajo licencia GPL3 o posterior</translation>
++ </message>
++ <message>
++ <location filename="../IAbout.ui" line="128"/>
++ <source>© 2017 Oliver Eichler (oliver.eichler@gmx.de)</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>ICoordFormatSetup</name>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="14"/>
++ <source>Coordinate Format...</source>
++ <translation>Formato de Coordenadas...</translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="24"/>
++ <source>N48° 53&apos; 39.6&quot; E13° 31&apos; 6.78&quot;</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="31"/>
++ <source>N48.8943° E013.51855°</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="38"/>
++ <source>N48° 53.660 E013° 31.113</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ICoordFormatSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation>&lt;b&gt;Nota:&lt;/b&gt; El cambio de las unidades de algunos elementos no se producirá hasta el reinicio de QMapTool.</translation>
++ </message>
++</context>
++<context>
++ <name>IDialogRefPoint</name>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="14"/>
++ <source>Dialog</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="25"/>
++ <source>Coord. Map File [pixel]</source>
++ <translation>Coord. archivo Map [pixel]</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="32"/>
++ <source>x</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="42"/>
++ <source>y</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="49"/>
++ <source>Coord. lat/lon WGS84 [°]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IDialogRefPoint.ui" line="59"/>
++ <source>Bad position format. Must be:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++or
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation>Formato de posición incorrecto. Debe ser:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++o
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</translation>
++ </message>
++</context>
++<context>
++ <name>IGridPlacer</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="150"/>
++ <source>Reset</source>
++ <translation>Reiniciar</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridPlacer.ui" line="224"/>
++ <source>Set Area</source>
++ <translation>Establecer área</translation>
++ </message>
++</context>
++<context>
++ <name>IGridSelArea</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSelArea.ui" line="35"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IGridSetRef</name>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="35"/>
++ <source>Grid Projection:</source>
++ <translation>Proyección de la Cuadrícula:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="47"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="60"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="72"/>
++ <source>Easting</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="82"/>
++ <source>Horiz. Spacing</source>
++ <translation>Espaciado horizontal</translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="92"/>
++ <source>Northing</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/gridtool/IGridSetRef.ui" line="102"/>
++ <source>Vert. Spacing</source>
++ <translation>Espaciado vertical</translation>
++ </message>
++</context>
++<context>
++ <name>IItemListWidget</name>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="40"/>
++ <source>Add map files to list</source>
++ <translation>Añadir archivos de mapa a la lista</translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="43"/>
++ <location filename="../items/IItemListWidget.ui" line="60"/>
++ <location filename="../items/IItemListWidget.ui" line="77"/>
++ <location filename="../items/IItemListWidget.ui" line="94"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="57"/>
++ <source>Remove selected file from the list.</source>
++ <translation>Borrar archivo seleccionado de la lista.</translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="74"/>
++ <source>Clear complete list of map files.</source>
++ <translation>Borrar lista completa de archivos de mapa.</translation>
++ </message>
++ <message>
++ <location filename="../items/IItemListWidget.ui" line="91"/>
++ <source>Reload the currently selected map.</source>
++ <translation>Recargar mapa seleccionado.</translation>
++ </message>
++</context>
++<context>
++ <name>IMainWindow</name>
++ <message>
++ <location filename="../IMainWindow.ui" line="14"/>
++ <source>MainWindow</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="32"/>
++ <source>Setup</source>
++ <translation>Configuración</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="41"/>
++ <source>View</source>
++ <translation>Ver</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="47"/>
++ <source>Window</source>
++ <translation>Ventana</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="52"/>
++ <source>?</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="67"/>
++ <source>Tools</source>
++ <translation>Herramientas</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="100"/>
++ <source>Shell</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="119"/>
++ <source>About</source>
++ <translation>Acerca de</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="128"/>
++ <source>Ext. Tools</source>
++ <translation>Herramientas ext.</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="131"/>
++ <source>Setup paths to external tools, like gdalwarp etc.</source>
++ <translation>Configurar rutas de las herramientas ext.</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="143"/>
++ <location filename="../IMainWindow.ui" line="146"/>
++ <source>Flip Mouse Wheel</source>
++ <translation>Invertir rueda del ratón</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="155"/>
++ <location filename="../IMainWindow.ui" line="158"/>
++ <source>Setup Units</source>
++ <translation>Configurar unidades</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="167"/>
++ <source>Setup Coord. Format</source>
++ <translation>Configurar formato de coordenadas</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="170"/>
++ <source>Change the format coordinates are displayed</source>
++ <translation>Cambiar formato de coordenadas mostrado.</translation>
++ </message>
++ <message>
++ <location filename="../IMainWindow.ui" line="181"/>
++ <source>Show Tool Help</source>
++ <translation>Mostrar ayuda de la herramienta</translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayCutMap</name>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="35"/>
++ <source>Just move the map and zoom.</source>
++ <translation>Solo mueve el mapa y zoom</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="58"/>
++ <source>Add point to mask.</source>
++ <translation>Añadir punto a la máscara.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="61"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="84"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="107"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="137"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="158"/>
++ <location filename="../overlay/IOverlayCutMap.ui" line="175"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="81"/>
++ <source>Move point of mask.</source>
++ <translation>Mover punto de la máscara.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="104"/>
++ <source>Remove point from mask.</source>
++ <translation>Borrar punto de la máscara.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="134"/>
++ <source>Remove complete cut mask.</source>
++ <translation>Borrar máscara de corte completa.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="155"/>
++ <source>Load cut mask from shape file.</source>
++ <translation>Cargar máscara de corte desde archivo Shape.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayCutMap.ui" line="172"/>
++ <source>Save cut mask to shape file.</source>
++ <translation>Guardar máscara de corte en archivo Shape.</translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayGridTool</name>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayGridTool.ui" line="145"/>
++ <source>do not translate</source>
++ <translation>No traducir</translation>
++ </message>
++</context>
++<context>
++ <name>IOverlayRefMap</name>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="40"/>
++ <source>Just move the map and zoom.</source>
++ <translation>Solo mover mapa y zoom.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="63"/>
++ <source>Add reference point.</source>
++ <translation>Añadir punto de referencia.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="66"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="89"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="112"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="135"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="165"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="179"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="200"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="217"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="244"/>
++ <location filename="../overlay/IOverlayRefMap.ui" line="326"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="86"/>
++ <source>Move reference point.</source>
++ <translation>Mover punto de referencia.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="109"/>
++ <source>Remove single reference point.</source>
++ <translation>Borrar un punto de referencia.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="132"/>
++ <source>Move reference points with auto mode. This will pickup the next point after you moved a reference point.</source>
++ <translation>Mover puntos de referencia con modo auto, captará el siguiente tras el desplazamiento del anterior.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="162"/>
++ <source>Remove all reference points.</source>
++ <translation>Borrar todos los puntos de referencia.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="176"/>
++ <source>Switch to the Grid Tool.</source>
++ <translation>Cambiar a la Herramienta de cuadrícula.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="197"/>
++ <source>Load reference points from GCP file.</source>
++ <translation>Cargar puntos de referencia desde archivo GCP.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="214"/>
++ <source>Save reference points into GCP file.</source>
++ <translation>Guardar puntos de referencia en archivo GCP.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="241"/>
++ <source>Sort list of reference points.</source>
++ <translation>Ordenar lista de puntos de referencia</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="281"/>
++ <source>(x, y)[pixel]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="286"/>
++ <source>(lat, lon)[°]</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="294"/>
++ <source>TextLabel</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="304"/>
++ <source>Final Map Projection:</source>
++ <translation>Proyección final del mapa:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="316"/>
++ <source>Enter a valid projection string. Valid strings are &quot;+proj...&quot; or &quot;+init=epsg:...&quot;.</source>
++ <translation>Introducir una cadena de proyección válida. Las cadenas válidas son &quot;+proj...&quot; o &quot;+init=epsg:...&quot;.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="323"/>
++ <source>Start projection wizard.</source>
++ <translation>Iniciar asistente de proyección.</translation>
++ </message>
++ <message>
++ <location filename="../overlay/IOverlayRefMap.ui" line="343"/>
++ <source>Delete</source>
++ <translation>Borrar</translation>
++ </message>
++</context>
++<context>
++ <name>IProjWizard</name>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="14"/>
++ <source>Proj4 Wizard</source>
++ <translation>Asistente de Proj4</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="29"/>
++ <source>Mercator</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="38"/>
++ <source>UTM</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="45"/>
++ <source>zone</source>
++ <translation>zona</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="82"/>
++ <source>user defined</source>
++ <translation>definida por el usuario</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="94"/>
++ <source>Datum</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="104"/>
++ <source>World Mercator (OSM)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="124"/>
++ <source>Result:</source>
++ <translation>Resultado:</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="138"/>
++ <source>UPS North (North Pole)</source>
++ <translation>UPS Norte (Polo Norte)</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="145"/>
++ <source>UPS South (South Pole)</source>
++ <translation>UPS Sur (Polo Sur)</translation>
++ </message>
++ <message>
++ <location filename="../overlay/refmap/IProjWizard.ui" line="152"/>
++ <source>Projection</source>
++ <translation>Proyección</translation>
++ </message>
++</context>
++<context>
++ <name>ISetupExtTools</name>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="14"/>
++ <source>Setup Ext. Tools</source>
++ <translation>Configurar Herramientas Ext.</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="22"/>
++ <location filename="../setup/ISetupExtTools.ui" line="64"/>
++ <location filename="../setup/ISetupExtTools.ui" line="99"/>
++ <location filename="../setup/ISetupExtTools.ui" line="173"/>
++ <location filename="../setup/ISetupExtTools.ui" line="194"/>
++ <location filename="../setup/ISetupExtTools.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;not found&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;no encontrado&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="32"/>
++ <location filename="../setup/ISetupExtTools.ui" line="53"/>
++ <location filename="../setup/ISetupExtTools.ui" line="74"/>
++ <location filename="../setup/ISetupExtTools.ui" line="88"/>
++ <location filename="../setup/ISetupExtTools.ui" line="135"/>
++ <location filename="../setup/ISetupExtTools.ui" line="149"/>
++ <location filename="../setup/ISetupExtTools.ui" line="183"/>
++ <location filename="../setup/ISetupExtTools.ui" line="211"/>
++ <location filename="../setup/ISetupExtTools.ui" line="225"/>
++ <location filename="../setup/ISetupExtTools.ui" line="239"/>
++ <location filename="../setup/ISetupExtTools.ui" line="264"/>
++ <location filename="../setup/ISetupExtTools.ui" line="275"/>
++ <source>...</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="112"/>
++ <source>gdal_translate:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="43"/>
++ <source>gdalbuildvrt</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="166"/>
++ <source>gdaladdo:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="125"/>
++ <source>gdalwarp:</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="29"/>
++ <location filename="../setup/ISetupExtTools.ui" line="132"/>
++ <location filename="../setup/ISetupExtTools.ui" line="180"/>
++ <location filename="../setup/ISetupExtTools.ui" line="208"/>
++ <location filename="../setup/ISetupExtTools.ui" line="222"/>
++ <source>Setup user defined path.</source>
++ <translation>Configurar ruta definida por el usuario.</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="201"/>
++ <source>qmt_rgb2pct</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="50"/>
++ <location filename="../setup/ISetupExtTools.ui" line="71"/>
++ <location filename="../setup/ISetupExtTools.ui" line="85"/>
++ <location filename="../setup/ISetupExtTools.ui" line="146"/>
++ <location filename="../setup/ISetupExtTools.ui" line="236"/>
++ <source>Reset user defined path setup.</source>
++ <translation>Reiniciar la configuración de la ruta definida por el usuario.</translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="250"/>
++ <source>qmt_map2jnx</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../setup/ISetupExtTools.ui" line="288"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; Usually QMapTool should detect all external tools by itself. If it does not, it&apos;s a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it&apos;s not setup properly you might get results but these can be off grid.</source>
++ <translation>&lt;b&gt;Nota:&lt;/b&gt; QMapTool debería detectar todas las herramientas externas automáticamente, si no es así, es debido a una configuración errónea y hay que corregir la variable PATH del sistema. También se pueden configurar las rutas manualmente, si se sabe lo que se está haciendo, pero ten en cuenta que GDAL necesita una configuración del entorno adecuada para funcionar correctamente. Si no es correcta se pueden obtener resultados, pero pueden ser incorrectos.</translation>
++ </message>
++</context>
++<context>
++ <name>ITimeZoneSetup</name>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="14"/>
++ <source>Setup Time Zone ...</source>
++ <translation>Configurar Zona Horaria...</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="22"/>
++ <source>UTC</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="32"/>
++ <source>Local</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="42"/>
++ <source>Automatic</source>
++ <translation>Automática</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="75"/>
++ <source>Print date/time in </source>
++ <translation>Mostrar fecha y hora en </translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="82"/>
++ <source>long format, or</source>
++ <translation>formato largo o</translation>
++ </message>
++ <message>
++ <location filename="../units/ITimeZoneSetup.ui" line="92"/>
++ <source>short format</source>
++ <translation>formato corto</translation>
++ </message>
++</context>
++<context>
++ <name>IToolAddOverview</name>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="59"/>
++ <source>do not translate</source>
++ <translation>no traducir</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="119"/>
++ <source>:2</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="126"/>
++ <source>:4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="133"/>
++ <source>:8</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="140"/>
++ <source>:16</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="147"/>
++ <source>:32</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="154"/>
++ <source>:64</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="164"/>
++ <source>Remove all overview levels from map file.</source>
++ <translation>Borrar los niveles de zoom del archivo del mapa.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="167"/>
++ <source>Remove</source>
++ <translation>Borrar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="174"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation>No copiar los niveles de zoom en el mismo archivo, hacerlo en uno externo.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="177"/>
++ <source>Overview as external file</source>
++ <translation>Niveles de zoom en archivo externo</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="207"/>
++ <source>Start</source>
++ <translation>Iniciar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="221"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="232"/>
++ <source>For all files</source>
++ <translation>Para todos los archivos</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolAddOverview.ui" line="257"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdaladdo&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IToolCutMap</name>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation>no traducir</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="114"/>
++ <source>Output filename suffix</source>
++ <translation>Sufijo del nombre de archivo resultante</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="133"/>
++ <source>_cut</source>
++ <translation>_cortar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="148"/>
++ <source>Create overviews for result.</source>
++ <translation>Crear niveles de zoom.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="176"/>
++ <source>Start</source>
++ <translation>Iniciar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="190"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="201"/>
++ <source>For all files</source>
++ <translation>Para todos los archivos</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="226"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>lt;b style=&apos;color: red;&apos;&gt; &quot;Gdalwarp&quot;no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolCutMap.ui" line="236"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt; &quot;Gdaladdo&quot;no encontrado ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IToolExport</name>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="59"/>
++ <location filename="../tool/IToolExport.ui" line="72"/>
++ <source>do not translate</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="83"/>
++ <source>Garmin BirdsEye (*.jnx)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="88"/>
++ <source>TwoNav Raster (*.rmap)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="101"/>
++ <source>not implemented yet</source>
++ <translation>Todavía no implementado</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="112"/>
++ <source>Target File</source>
++ <translation>Archivo de destino</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="130"/>
++ <source>Start</source>
++ <translation>Iniciar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="144"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="173"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_map2jnx&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;qmt_map2jnx&quot; No encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolExport.ui" line="184"/>
++ <source>Target Filename</source>
++ <translation>Nombre del archivo de destino</translation>
++ </message>
++</context>
++<context>
++ <name>IToolExportJnx</name>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="35"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="81"/>
++ <source>BirdsEye</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="50"/>
++ <source>Product ID</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="57"/>
++ <source>Copyright notice</source>
++ <translation>Aviso de copyright</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="64"/>
++ <location filename="../tool/export/IToolExportJnx.ui" line="95"/>
++ <source>None</source>
++ <translation>Ninguno</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="71"/>
++ <source>Product name</source>
++ <translation>Nombre del producto</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="88"/>
++ <source>Description</source>
++ <translation type="unfinished">Descripción</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="105"/>
++ <source>JPEG</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="133"/>
++ <source>Quality</source>
++ <translation>Calidad</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="140"/>
++ <source>Chroma subsampling</source>
++ <translation>Submuestreo de Chroma</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="148"/>
++ <source>411</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="153"/>
++ <source>422</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="158"/>
++ <source>444</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="169"/>
++ <source>Device</source>
++ <translation>Dispositivo</translation>
++ </message>
++ <message>
++ <location filename="../tool/export/IToolExportJnx.ui" line="184"/>
++ <source>Z-Order</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>IToolGrid</name>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="56"/>
++ <source>Grid Tool</source>
++ <translation>Herramienta Cuadrícula</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="65"/>
++ <source>do not translate</source>
++ <translation>no traducir</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="99"/>
++ <source>Ok</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="110"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolGrid.ui" line="134"/>
++ <source>Reset</source>
++ <translation>Reiniciar</translation>
++ </message>
++</context>
++<context>
++ <name>IToolOverviewGroupBox</name>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="14"/>
++ <source>GroupBox</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="71"/>
++ <source>:2</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="78"/>
++ <source>:4</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="85"/>
++ <source>:8</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="92"/>
++ <source>:16</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="99"/>
++ <source>:32</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="106"/>
++ <source>:64</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="119"/>
++ <source>Do not copy the overviews into the file itself. Add them as external file.</source>
++ <translation>No copiar los niveles de zoom en el mismo archivo, hacerlo en uno externo.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolOverviewGroupBox.ui" line="122"/>
++ <source>Overview as external file</source>
++ <translation>Niveles de zoom en archivo externo</translation>
++ </message>
++</context>
++<context>
++ <name>IToolPalettize</name>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="65"/>
++ <location filename="../tool/IToolPalettize.ui" line="78"/>
++ <source>do not translate</source>
++ <translation>no traducir</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="96"/>
++ <source>Single files, filename suffix</source>
++ <translation>Archivos individuales, sufijo del nombre</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="109"/>
++ <source>_8bit</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="123"/>
++ <source>Combined file, filename:</source>
++ <translation>Archivo combinado, nombre:</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="135"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation>Insertar el resultado en un archivo *.vrt.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="142"/>
++ <source>Create overviews for result.</source>
++ <translation>Crear niveles de zoom.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="170"/>
++ <source>Start</source>
++ <translation>Iniciar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="184"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="213"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdaladdo&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="223"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdal_translate&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="233"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;qmt_rgb2pct&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Qmt_rgb2pct&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolPalettize.ui" line="247"/>
++ <source>Select filename</source>
++ <translation>Seleccionar nombre de archivo</translation>
++ </message>
++</context>
++<context>
++ <name>IToolRefMap</name>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="14"/>
++ <source>Form</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="59"/>
++ <source>do not translate</source>
++ <translation>no traducir</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="113"/>
++ <source>Output filename suffix</source>
++ <translation>Sufijo del nombre de archivo</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="132"/>
++ <source>_ref</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="144"/>
++ <source>Embed result into *.vrt file.</source>
++ <translation>Insertar resultado en archivo *.vrt.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="151"/>
++ <source>Create overviews for result.</source>
++ <translation>Crear niveles de zoom.</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="179"/>
++ <source>Start</source>
++ <translation>Iniciar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="193"/>
++ <source>Cancel</source>
++ <translation>Cancelar</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="204"/>
++ <source>For all files</source>
++ <translation>Para todos los archivos</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="229"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdalwarp&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="239"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdal_translate&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++ <message>
++ <location filename="../tool/IToolRefMap.ui" line="249"/>
++ <source>&lt;b style=&apos;color: red;&apos;&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</source>
++ <translation>&lt;b style=&apos;color: red;&apos;&gt;&quot;Gdaladdo&quot; no encontrado. ¡Comprobar la configuración!&lt;/b&gt;</translation>
++ </message>
++</context>
++<context>
++ <name>IUnit</name>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Error</source>
++ <translation>Error</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="740"/>
++ <source>Bad position format. Must be: &quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot; or &quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</source>
++ <translation>Formato de posición incorrecto. Debe ser: &quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot; or &quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnit.cpp" line="746"/>
++ <source>Position values out of bounds. </source>
++ <translation>Valores de posición fuera de los límites.</translation>
++ </message>
++</context>
++<context>
++ <name>IUnitsSetup</name>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="14"/>
++ <source>Setup units...</source>
++ <translation>Configurar unidades...</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="24"/>
++ <source>Nautical</source>
++ <translation>Náutico</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="31"/>
++ <source>Imperial</source>
++ <translation>Imperial</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="38"/>
++ <source>Metric</source>
++ <translation>Métrico</translation>
++ </message>
++ <message>
++ <location filename="../units/IUnitsSetup.ui" line="53"/>
++ <source>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</source>
++ <translation>&lt;b&gt;Nota:&lt;/b&gt; El cambio de las unidades de algunos elementos no se producirá hasta el reinicio de QMapTool.</translation>
++ </message>
++</context>
++</TS>
+diff --git a/src/qmaptool/main.cpp b/src/qmaptool/main.cpp
+new file mode 100644
+index 00000000..2d23b037
+--- /dev/null
++++ b/src/qmaptool/main.cpp
+@@ -0,0 +1,76 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "CSingleInstanceProxy.h"
++#include "setup/IAppSetup.h"
++#include "version.h"
++
++#include <QApplication>
++#include <QtWidgets>
++
++int main(int argc, char ** argv)
++{
++ QApplication app(argc, argv);
++
++ QCoreApplication::setApplicationName("QMapTool");
++ QCoreApplication::setOrganizationName("QLandkarte");
++ QCoreApplication::setOrganizationDomain("qlandkarte.org");
++
++ IAppSetup& env = IAppSetup::createInstance(qApp);
++ env.processArguments();
++ env.initLogHandler();
++ env.initQMapTool();
++
++ // make sure this is the one and only instance on the system
++ CSingleInstanceProxy s(qlOpts->arguments);
++
++ QSplashScreen *splash = nullptr;
++ if (!qlOpts->nosplash)
++ {
++ QPixmap pic(":/pic/splash.png");
++ QPainter p(&pic);
++ QFont f = p.font();
++ f.setBold(true);
++
++ p.setPen(Qt::black);
++ p.setFont(f);
++ p.drawText(260,195,"QMapTool, V " VER_STR);
++
++ splash = new QSplashScreen(pic);
++#ifdef Q_OS_MAC
++ // remove the splash screen flag on OS-X as workaround for the reported bug
++ // https://bugreports.qt.io/browse/QTBUG-49576
++ splash->setWindowFlags(splash->windowFlags() & (~Qt::SplashScreen));
++#endif
++ splash->show();
++ }
++
++ CMainWindow w;
++ w.show();
++
++ if(nullptr != splash)
++ {
++ splash->finish(&w);
++ delete splash;
++ }
++
++ return app.exec();
++}
++
++
+diff --git a/src/qmaptool/overlay/COverlayCutMap.cpp b/src/qmaptool/overlay/COverlayCutMap.cpp
+new file mode 100644
+index 00000000..ec64e12a
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayCutMap.cpp
+@@ -0,0 +1,644 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CDraw.h"
++#include "helpers/CSettings.h"
++#include "items/CItemCutMap.h"
++#include "overlay/COverlayCutMap.h"
++
++#include <functional>
++#include <QtWidgets>
++using std::bind;
++
++static inline qreal sqr(qreal a)
++{
++ return a*a;
++}
++
++static inline qreal sqrlen(const QPointF &a)
++{
++ return sqr(a.x()) + sqr(a.y());
++}
++
++
++COverlayCutMap::COverlayCutMap(CItemCutMap *item, QStackedWidget *stackedWidget)
++ : IOverlay(stackedWidget)
++ , context(item->getDrawContext())
++{
++ setupUi(this);
++
++ QFileInfo fi(item->getFilename());
++ shapeFilename = fi.completeBaseName() + ".shp";
++
++ connect(toolNone, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModeNone, std::placeholders::_1));
++ connect(toolPointMove, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointMove, std::placeholders::_1));
++ connect(toolPointAdd, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointAdd, std::placeholders::_1));
++ connect(toolPointDel, &QToolButton::clicked, this, bind(&COverlayCutMap::slotSetMode, this, eModePointDel, std::placeholders::_1));
++ connect(toolPointDelAll, &QToolButton::clicked, this, &COverlayCutMap::slotResetMask);
++ connect(toolLoadShape, &QToolButton::clicked, this, &COverlayCutMap::slotLoadShape);
++ connect(toolSaveShape, &QToolButton::clicked, this, &COverlayCutMap::slotSaveShape);
++}
++
++void COverlayCutMap::saveSettings(QSettings& cfg)
++{
++ cfg.setValue("region", region);
++}
++
++void COverlayCutMap::loadSettings(QSettings& cfg)
++{
++ region = (cfg.value("region", QPolygonF()).value<QPolygonF>());
++
++ updateGui();
++}
++
++
++bool COverlayCutMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ if(region.isEmpty())
++ {
++ return true;
++ }
++
++ QPolygonF shape = region;
++ context->convertMap2Screen(shape);
++
++ if(shape.size() > 2)
++ {
++ QPainterPath path;
++
++ QRectF rectMap = context->getMapArea();
++ context->convertMap2Screen(rectMap);
++
++ path.addRect(rectMap);
++ path.addPolygon(shape);
++
++ p.setPen(QPen(Qt::darkBlue,1));
++
++ p.setBrush((idxFocus1 == NOIDX) ? Qt::BDiagPattern : Qt::NoBrush);
++ p.drawPath(path);
++ }
++
++ QRectF dot1(0,0,5,5);
++ QRectF dot2(0,0,7,7);
++ const QPointF& pt1 = idxFocus1 != NOIDX ? shape[idxFocus1] : NOPOINTF;
++ const QPointF& pt2 = idxFocus2 != NOIDX ? shape[idxFocus2] : NOPOINTF;
++
++ // draw black dots for each point in region
++ p.setPen(QPen(Qt::black, 1));
++ p.setBrush(Qt::black);
++ for(const QPointF& pt : shape)
++ {
++ if(pt == pt1)
++ {
++ continue;
++ }
++ dot1.moveCenter(pt);
++ p.drawRect(dot1);
++ }
++
++ // if just one dot is selected draw crosshair
++ if((idxFocus2 == NOIDX) && (idxFocus1 != NOIDX))
++ {
++ CDraw::drawCrossHairDot(p, pt1);
++ }
++ else if((idxFocus2 != NOIDX) && (idxFocus1 == NOIDX))
++ {
++ CDraw::drawCrossHairDot(p, pt2);
++ }
++ // if both points are selected highlight segment
++ else if((idxFocus2 != NOIDX) && (idxFocus1 != NOIDX))
++ {
++ p.setPen(QPen(Qt::red, 2));
++ p.setBrush(Qt::red);
++
++ dot2.moveCenter(pt1);
++ p.drawRect(dot2);
++ dot2.moveCenter(pt2);
++ p.drawRect(dot2);
++ p.drawLine(pt1, pt2);
++ }
++ return true;
++}
++
++void COverlayCutMap::mouseMoveEventFx(QMouseEvent *e)
++{
++ QPointF pt = e->pos();
++ context->convertScreen2Map(pt);
++
++ switch(mode)
++ {
++ case eModePointMove:
++ mouseMovePointMove(pt);
++ break;
++
++ case eModePointAdd:
++ mouseMovePointAdd(pt);
++ break;
++
++ case eModePointDel:
++ mouseMovePointDel(pt);
++ break;
++
++ default:
++ return;
++ }
++
++ updateGui();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayCutMap::mouseReleaseEventFx(QMouseEvent *e)
++{
++ QPointF pt = e->pos();
++ context->convertScreen2Map(pt);
++
++ Qt::MouseButton button = e->button();
++
++ switch(mode)
++ {
++ case eModePointMove:
++ mouseReleasePointMove(pt, button);
++ break;
++
++ case eModePointAdd:
++ mouseReleasePointAdd(pt, button);
++ break;
++
++ case eModePointDel:
++ mouseReleasePointDel(pt, button);
++ break;
++
++ default:
++ return;
++ }
++
++ updateGui();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++QCursor COverlayCutMap::getCursorFx()
++{
++ switch(mode)
++ {
++ case eModePointAdd:
++ return QCursor(QPixmap(":/cursors/cursorPointAdd.png"), 0, 0);
++
++ case eModePointDel:
++ return QCursor(QPixmap(":/cursors/cursorPointDel.png"), 0, 0);
++
++ case eModePointMove:
++ return QCursor(QPixmap(":/cursors/cursorPointMove.png"), 0, 0);
++ }
++
++ return Qt::ArrowCursor;
++}
++
++void COverlayCutMap::slotSetMode(mode_e m, bool on)
++{
++ if(on)
++ {
++ mode = m;
++ }
++}
++
++void COverlayCutMap::slotResetMask()
++{
++ int res = QMessageBox::question(this, tr("Delete mask..."), tr("Are you sure to delete complete mask?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
++ if(res != QMessageBox::Yes)
++ {
++ return;
++ }
++
++ mouseReset();
++ region.clear();
++ storeToHistory(region);
++ updateGui();
++}
++
++void COverlayCutMap::slotSaveShape()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/shapeInput", QDir::homePath()).toString();
++
++ QString filename = QFileDialog::getSaveFileName(&CMainWindow::self(), tr("Save mask..."), path + "/" + shapeFilename, "Shape file (*.shp)");
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/shapeInput", QFileInfo(shapeFilename).absolutePath());
++
++ if(region.isEmpty())
++ {
++ return;
++ }
++ shapeFilename = filename;
++ saveShape(filename);
++}
++
++void COverlayCutMap::saveShape(const QString& filename)
++{
++ const QPolygonF& line = region;
++
++ QFile file(filename);
++ file.open(QIODevice::WriteOnly);
++ QTextStream out(&file);
++
++ out << "id,WKT" << endl;
++ out << "1,\"POLYGON((";
++
++ bool first = true;
++ for(const QPointF& pt : line)
++ {
++ QPointF pt1 = pt;
++ context->convertMap2Coord(pt1);
++
++ if(!first)
++ {
++ out << ", ";
++ }
++ first = false;
++
++ out << qRound(pt1.x()) << " " << qRound(pt1.y());
++ }
++ out << "))\"" << endl;
++}
++
++void COverlayCutMap::slotLoadShape()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/shapeInput", QDir::homePath()).toString();
++
++ QString filename = QFileDialog::getOpenFileName(&CMainWindow::self(), tr("Load mask..."), path, "Shape file (*.shp)");
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/shapeInput", QFileInfo(filename).absolutePath());
++
++ QFile file(filename);
++ file.open(QIODevice::ReadOnly);
++ QTextStream in(&file);
++
++ QString line = in.readLine().simplified();
++ if(line != "id,WKT")
++ {
++ QMessageBox::warning(&CMainWindow::self(), tr("Failed..."), tr("Not a shape file."), QMessageBox::Abort);
++ return;
++ }
++
++ while(!in.atEnd())
++ {
++ QString line = in.readLine().simplified();
++ if(line.startsWith("1,\"POLYGON(("))
++ {
++ region.clear();
++
++ line = line.mid(12);
++ QTextStream in2(&line, QIODevice::ReadOnly);
++
++ while(!in2.atEnd())
++ {
++ qreal x, y;
++ in2 >> x >> y;
++
++ QPointF pt(x,y);
++ context->convertCoord2Map(pt);
++
++ region << pt;
++
++ QString str;
++ in2 >> str;
++ if(str != ",")
++ {
++ break;
++ }
++ }
++ }
++ }
++
++ updateGui();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ emit sigChanged();
++}
++
++void COverlayCutMap::mouseReset()
++{
++ addPoint = false;
++ movePoint = false;
++ idxFocus1 = NOIDX;
++ idxFocus1 = NOIDX;
++}
++
++void COverlayCutMap::abortStep()
++{
++ if(addPoint)
++ {
++ restoreFromHistory(region);
++ addPoint = false;
++ idxFocus1 = NOIDX;
++ idxFocus2 = NOIDX;
++ }
++ else if(movePoint)
++ {
++ restoreFromHistory(region);
++ movePoint = false;
++ idxFocus1 = NOIDX;
++ }
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayCutMap::restoreFromHistory(QPolygonF& line)
++{
++ line = history[idxHistory];
++ emit sigChanged();
++}
++
++void COverlayCutMap::storeToHistory(const QPolygonF& line)
++{
++ // crop history if necessary
++ if(idxHistory != NOIDX)
++ {
++ while(history.size() > (idxHistory + 1))
++ {
++ history.pop_back();
++ }
++ }
++
++ history << line;
++ idxHistory = history.size() - 1;
++
++ emit sigChanged();
++}
++
++void COverlayCutMap::isCloseTo(QPointF pt, QPolygonF line, qint32& idx) const
++{
++ idx = NOIDX;
++
++ context->convertMap2Screen(pt);
++ context->convertMap2Screen(line);
++
++ if(line.isEmpty())
++ {
++ return;
++ }
++
++ qint32 min = 30;
++ const int N = region.size();
++ for(int i = 0; i < N; i++)
++ {
++ qint32 d = (pt - line[i]).manhattanLength();
++ if(d < min)
++ {
++ min = d;
++ idx = i;
++ }
++ }
++}
++
++void COverlayCutMap::isCloseToLine(QPointF pt, QPolygonF line, qint32& idx1, qint32& idx2) const
++{
++ idx1 = NOIDX;
++ idx2 = NOIDX;
++
++ context->convertMap2Screen(pt);
++ context->convertMap2Screen(line);
++
++ const int count = line.size();
++ if(count < 2)
++ {
++ return;
++ }
++
++ QPointF b = line[0];
++ QPointF dbq = b - pt;
++ qreal dist = 30*30;
++
++ for (qint32 i = 1; i < count; ++i)
++ {
++ const QPointF a = b;
++ const QPointF daq = dbq;
++ b = line[i];
++ dbq = b - pt;
++
++ const QPointF dab = a - b;
++
++ const qreal inv_sqrlen = 1./sqrlen(dab);
++ const qreal t = (dab.x()*daq.x() + dab.y()*daq.y())*inv_sqrlen;
++ if (t < 0.)
++ {
++ continue;
++ }
++ qreal current_dist;
++ if (t <= 1.)
++ {
++ current_dist = sqr(dab.x()*dbq.y() - dab.y()*dbq.x())*inv_sqrlen;
++ }
++ else//t>1.
++ {
++ current_dist = sqrlen(dbq);
++ }
++
++ if (current_dist < dist)
++ {
++ dist = current_dist;
++ idx1 = i - 1;
++ idx2 = i;
++ }
++ }
++}
++
++
++void COverlayCutMap::mouseMovePointAdd(const QPointF &pt)
++{
++ if(region.isEmpty())
++ {
++ return;
++ }
++
++ if(addPoint)
++ {
++ region[idxFocus1] = pt;
++ }
++ else
++ {
++ // find line segment close to cursor
++ isCloseToLine(pt, region, idxFocus1, idxFocus2);
++ }
++}
++
++void COverlayCutMap::mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button)
++{
++ if(button == Qt::LeftButton)
++ {
++ if(addPoint)
++ {
++ // if isPoint is true the line has been appended/prepended
++ // in this case go on with adding another point
++ if(idxFocus1 == (region.size() - 1))
++ {
++ idxFocus1++;
++ }
++ // store current state of line to undo/redo history
++ storeToHistory(region);
++ region.insert(idxFocus1, pt);
++ }
++ else if(idxFocus1 != NOIDX)
++ {
++ // add a new point to line segment
++ idxFocus2 = NOIDX;
++ idxFocus1++;
++ region.insert(idxFocus1, pt);
++ addPoint = true;
++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointAdd");
++ }
++ else if(region.isEmpty())
++ {
++ region.append(pt);
++ storeToHistory(region);
++ region.append(pt);
++ region.append(pt);
++ idxFocus1 = 1;
++ addPoint = true;
++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointAdd");
++ }
++ }
++ else if(button == Qt::RightButton)
++ {
++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointAdd");
++ if(!addPoint)
++ {
++ toolNone->click();
++ }
++ abortStep();
++ }
++}
++
++void COverlayCutMap::mouseMovePointDel(const QPointF &pt)
++{
++ isCloseTo(pt, region, idxFocus1);
++}
++
++void COverlayCutMap::mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button)
++{
++ if((idxFocus1 != NOIDX) && (button == Qt::LeftButton))
++ {
++ //special case first or last point.
++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1)))
++ {
++ if(region.size() > 2)
++ {
++ // more than one point set
++ region.pop_back();
++ region.pop_front();
++ }
++ else
++ {
++ // remove last point
++ region.clear();
++ }
++
++ // close polygon area by appending the first point
++ if(!region.isEmpty())
++ {
++ region << region.first();
++ }
++ }
++ else
++ {
++ region.remove(idxFocus1);
++ }
++ storeToHistory(region);
++ }
++ else if(button == Qt::RightButton)
++ {
++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointDel");
++ toolNone->click();
++ }
++ idxFocus1 = NOIDX;
++}
++
++void COverlayCutMap::mouseMovePointMove(const QPointF &pt)
++{
++ if(movePoint)
++ {
++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1)))
++ {
++ region.first() = pt;
++ region.last() = pt;
++ }
++ else
++ {
++ region[idxFocus1] = pt;
++ }
++ }
++ else
++ {
++ // no point selected yet, find point to highlight
++ isCloseTo(pt, region, idxFocus1);
++ }
++}
++
++void COverlayCutMap::mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button)
++{
++ if(button == Qt::LeftButton)
++ {
++ if(movePoint)
++ {
++ // terminate moving the point
++ movePoint = false;
++ // store new state of line to undo/redo history
++ storeToHistory(region);
++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointAdd");
++ }
++ else if(idxFocus1 != NOIDX)
++ {
++ if((idxFocus1 == 0) || (idxFocus1 == (region.size() - 1)))
++ {
++ region.first() = pt;
++ region.last() = pt;
++ }
++ else
++ {
++ region[idxFocus1] = pt;
++ }
++
++ movePoint = true;
++ CCanvas::setOverrideCursor(Qt::BlankCursor, "COverlayCutMap::mouseReleasePointMove");
++ }
++ }
++ else if(button == Qt::RightButton)
++ {
++ CCanvas::restoreOverrideCursor("COverlayCutMap::mouseReleasePointMove");
++ if(!movePoint)
++ {
++ toolNone->click();
++ }
++ abortStep();
++ }
++}
++
++void COverlayCutMap::updateGui()
++{
++ bool enable = !region.isEmpty();
++ toolPointMove->setEnabled(enable);
++ toolPointDel->setEnabled(enable);
++ toolPointDelAll->setEnabled(enable);
++ toolSaveShape->setEnabled(enable);
++}
+diff --git a/src/qmaptool/overlay/COverlayCutMap.h b/src/qmaptool/overlay/COverlayCutMap.h
+new file mode 100644
+index 00000000..8938f006
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayCutMap.h
+@@ -0,0 +1,105 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef COVERLAYCUTMAP_H
++#define COVERLAYCUTMAP_H
++
++#include "canvas/CCanvas.h"
++#include "overlay/IOverlay.h"
++#include "ui_IOverlayCutMap.h"
++#include "units/IUnit.h"
++
++
++class QStackedWidget;
++class IDrawContext;
++class QSettings;
++class CItemCutMap;
++
++class COverlayCutMap : public IOverlay, private Ui::IOverlayCutMap
++{
++ Q_OBJECT
++public:
++ COverlayCutMap(CItemCutMap *item, QStackedWidget * stackedWidget);
++ virtual ~COverlayCutMap() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ QCursor getCursorFx();
++
++ void abortStep();
++
++ enum mode_e
++ {
++ eModeNone
++ ,eModePointMove
++ ,eModePointAdd
++ ,eModePointDel
++ };
++
++ void saveShape(const QString& filename);
++
++ bool isOk() const
++ {
++ return !region.isEmpty();
++ }
++
++private slots:
++ void slotSetMode(mode_e m, bool on);
++ void slotResetMask();
++ void slotSaveShape();
++ void slotLoadShape();
++
++private:
++ void restoreFromHistory(QPolygonF& line);
++ void storeToHistory(const QPolygonF& line);
++ void isCloseTo(QPointF pt, QPolygonF line, qint32& idx) const;
++ void isCloseToLine(QPointF pt, QPolygonF line, qint32 &idx1, qint32 &idx2) const;
++ void mouseReset();
++
++ void mouseMovePointAdd(const QPointF &pt);
++ void mouseMovePointDel(const QPointF &pt);
++ void mouseMovePointMove(const QPointF &pt);
++
++ void mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button);
++ void mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button);
++ void mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button);
++
++ void updateGui();
++
++ IDrawContext* context;
++
++ mode_e mode = eModeNone;
++ QPolygonF region;
++
++ qint32 idxFocus1 = NOIDX;
++ qint32 idxFocus2 = NOIDX;
++ bool addPoint = false;
++ bool movePoint = false;
++
++ QList<QPolygonF> history;
++ qint32 idxHistory = NOIDX;
++
++ QString shapeFilename;
++};
++
++#endif //COVERLAYCUTMAP_H
++
+diff --git a/src/qmaptool/overlay/COverlayGridTool.cpp b/src/qmaptool/overlay/COverlayGridTool.cpp
+new file mode 100644
+index 00000000..7a0fa26e
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayGridTool.cpp
+@@ -0,0 +1,348 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "items/CItemRefMap.h"
++#include "overlay/COverlayGridTool.h"
++#include "overlay/refmap/COverlayRefMapPoint.h"
++#include "overlay/refmap/CProjWizard.h"
++
++#include <proj_api.h>
++#include <QtWidgets>
++
++COverlayGridTool::COverlayGridTool(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++ labelFinal->setText(tr("Before you proceed with 'ok':\n"
++ "Please cross check all data once again. A bad reference coordinate will ruin "
++ "all the work. Also cross check if the selected area contains as many reference "
++ "points as possible at the border. You can easily delete points outside the map "
++ "in the Reference Tool. But it's much more effort to set additional points in "
++ "case you miss some. When you are done press 'ok' to transfer the derived "
++ "reference points to the Reference Tool.\n\n"
++ "The next step will be to use the Reference Tool to adjust the position of all "
++ "reference points to the real grid position on the map."));
++
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelFinal, &QLabel::setVisible);
++
++ QButtonGroup * group = new QButtonGroup(this);
++ group->addButton(radioSetRef);
++ group->addButton(radioGridPlacer);
++ group->addButton(radioSelectArea);
++
++
++ connect(radioSetRef, &QRadioButton::toggled, widgetSetRef, &QFrame::setEnabled);
++ connect(radioGridPlacer, &QRadioButton::toggled, widgetGridPlacer, &CGridPlacer::setEnabled);
++ connect(radioSelectArea, &QRadioButton::toggled, widgetSelectArea, &QLabel::setEnabled);
++
++
++ connect(widgetSetRef, &CGridSetRef::sigChanged, this, &COverlayGridTool::slotCalculate);
++ connect(widgetSetRef, &CGridSetRef::sigChanged, this, &COverlayGridTool::slotCheckInput);
++
++ connect(widgetGridPlacer, &CGridPlacer::sigChanged, this, &COverlayGridTool::slotCheckInput);
++ connect(widgetGridPlacer, &CGridPlacer::sigSetArea, this, &COverlayGridTool::slotSetArea);
++ connect(widgetGridPlacer, &CGridPlacer::sigChanged, this, &COverlayGridTool::slotCalculate);
++
++ connect(widgetSelectArea, &CGridSelArea::sigChanged, this, &COverlayGridTool::slotCalculate);
++ connect(widgetSelectArea, &CGridSelArea::sigChanged, this, &COverlayGridTool::slotCheckInput);
++}
++
++void COverlayGridTool::slotReset()
++{
++ widgetSetRef->slotReset();
++ widgetGridPlacer->slotReset();
++ widgetSelectArea->slotReset();
++
++ radioSetRef->setChecked(true);
++
++ SETTINGS;
++ cfg.beginGroup("GridTool");
++ cfg.remove("");
++ cfg.endGroup();
++ cfg.sync();
++}
++
++void COverlayGridTool::registerItem(CItemRefMap * item)
++{
++ this->item = item;
++ if(item != nullptr)
++ {
++ context = item->getDrawContext();
++ if(context == nullptr)
++ {
++ this->item = nullptr;
++ }
++ }
++ else
++ {
++ context = nullptr;
++ }
++
++
++ widgetGridPlacer->registerItem(this->item);
++ widgetSelectArea->registerItem(this->item);
++
++ radioSetRef->setChecked(true);
++
++ SETTINGS;
++ cfg.beginGroup("GridTool");
++ if(this->item != nullptr)
++ {
++ widgetSetRef->loadSettings(cfg);
++ widgetGridPlacer->loadSettings(cfg);
++ widgetSelectArea->loadSettings(cfg);
++ }
++ else
++ {
++ cfg.remove("");
++
++ widgetSetRef->saveSettings(cfg);
++ widgetGridPlacer->saveSettings(cfg);
++ widgetSelectArea->saveSettings(cfg);
++ }
++ cfg.endGroup();
++
++ slotCheckInput();
++}
++
++
++void COverlayGridTool::slotCheckInput()
++{
++ bool group1Ok = widgetSetRef->isOk();
++ radioGridPlacer->setEnabled(group1Ok);
++
++ bool group2Ok = widgetGridPlacer->isOk();
++ radioSelectArea->setEnabled(group2Ok&& group1Ok);
++
++ const QPointF& p1 = widgetGridPlacer->getPoint(0);
++ const QPointF& p2 = widgetGridPlacer->getPoint(1);
++ const QPointF& p3 = widgetGridPlacer->getPoint(2);
++ const QPointF& p4 = widgetGridPlacer->getPoint(3);
++ const QRectF& area = widgetSelectArea->getArea();
++
++ bool group3Ok = true;
++ group3Ok &= !area.isEmpty();
++ group3Ok &= area.isValid();
++ group3Ok &= !area.isNull();
++ group3Ok &= area.contains(p1);
++ group3Ok &= area.contains(p2);
++ group3Ok &= area.contains(p3);
++ group3Ok &= area.contains(p4);
++
++ labelFinal->setEnabled(group1Ok && group2Ok && group3Ok);
++
++ emit sigChanged(group1Ok && group2Ok && group3Ok);
++}
++
++bool COverlayGridTool::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ if(radioSelectArea->isEnabled())
++ {
++ widgetSelectArea->drawFx(p, needsRedraw);
++
++ QRectF dot1(0,0,7,7);
++ p.setPen(QPen(Qt::white, 1));
++ p.setBrush(Qt::darkGreen);
++
++ for(COverlayRefMapPoint * point : refPoints)
++ {
++ QPointF pt = point->getPtPtx();
++ context->convertMap2Screen(pt);
++ dot1.moveCenter(pt);
++ p.drawRect(dot1);
++ }
++ }
++
++ widgetGridPlacer->drawFx(p, needsRedraw);
++ return false;
++}
++
++void COverlayGridTool::mouseMoveEventFx(QMouseEvent *e)
++{
++ if(radioGridPlacer->isChecked())
++ {
++ widgetGridPlacer->mouseMoveEventFx(e);
++ }
++ else if(radioSelectArea->isChecked())
++ {
++ widgetSelectArea->mouseMoveEventFx(e);
++ }
++}
++
++void COverlayGridTool::mouseReleaseEventFx(QMouseEvent *e)
++{
++ if(radioGridPlacer->isChecked())
++ {
++ widgetGridPlacer->mouseReleaseEventFx(e);
++ }
++ else if(radioSelectArea->isChecked())
++ {
++ widgetSelectArea->mouseReleaseEventFx(e);
++ }
++}
++
++void COverlayGridTool::leaveEventFx(QEvent *e)
++{
++ if(radioGridPlacer->isChecked())
++ {
++ widgetGridPlacer->leaveEventFx(e);
++ }
++ else if(radioSelectArea->isChecked())
++ {
++ widgetSelectArea->leaveEventFx(e);
++ }
++}
++
++QCursor COverlayGridTool::getCursorFx()
++{
++ if(radioGridPlacer->isChecked())
++ {
++ return widgetGridPlacer->getCursorFx();
++ }
++ else if(radioSelectArea->isChecked())
++ {
++ return widgetSelectArea->getCursorFx();
++ }
++ else
++ {
++ return Qt::ArrowCursor;
++ }
++}
++
++
++void COverlayGridTool::slotSetArea(const QRectF& rect)
++{
++ qreal hspace = rect.width() / 2;
++ qreal vspace = rect.height() / 2;
++ QRectF area = rect;
++
++ area.setTopLeft(rect.topLeft() - QPointF(hspace, vspace));
++ area.setBottomRight(rect.bottomRight() + QPointF(hspace, vspace));
++
++ widgetSelectArea->slotSetArea(area);
++ radioSelectArea->setChecked(true);
++}
++
++void COverlayGridTool::slotCalculate()
++{
++ if(!radioSelectArea->isEnabled())
++ {
++ return;
++ }
++
++ qDeleteAll(refPoints);
++ refPoints.clear();
++
++ projPJ pjsrc = pj_init_plus(widgetSetRef->getProjection().toLatin1());
++ if(pjsrc == nullptr)
++ {
++ return;
++ }
++
++ projPJ pjtar = pj_init_plus("+proj=longlat +datum=WGS84 +no_defs");
++ if(pjtar == nullptr)
++ {
++ pj_free(pjsrc);
++ return;
++ }
++
++ const QRectF& area = widgetSelectArea->getArea();
++
++ const QPointF& ptTopLeft = widgetGridPlacer->getPoint(0);
++ const QPointF& ptTopRight = widgetGridPlacer->getPoint(1);
++ const QPointF& ptBottomRight = widgetGridPlacer->getPoint(2);
++ const QPointF& ptBottomLeft = widgetGridPlacer->getPoint(3);
++
++ qreal dx11 = ptTopRight.x() - ptTopLeft.x();
++ qreal dy11 = ptTopRight.y() - ptTopLeft.y();
++ qreal dx12 = ptBottomRight.x() - ptBottomLeft.x();
++ qreal dy12 = ptBottomRight.y() - ptBottomLeft.y();
++ qreal dx1 = (dx11 + dx12) / 2;
++ qreal dy1 = (dy11 + dy12) / 2;
++
++ qreal alpha = qAtan(dy1/dx1);
++ qreal distx = qSqrt(dx1*dx1 + dy1*dy1);
++
++ qreal dx21 = ptBottomLeft.x() - ptTopLeft.x();
++ qreal dy21 = ptBottomLeft.y() - ptTopLeft.y();
++ qreal dx22 = ptBottomRight.x() - ptTopRight.x();
++ qreal dy22 = ptBottomRight.y() - ptTopRight.y();
++ qreal dx2 = (dx21 + dx22) / 2;
++ qreal dy2 = (dy21 + dy22) / 2;
++
++ qreal disty = qSqrt(dx2*dx2 + dy2*dy2);
++
++ QMatrix translationMatrix(1, 0, 0, 1, ptTopLeft.x(), ptTopLeft.y());
++ QMatrix rotationMatrix(qCos(alpha), qSin(alpha), -qSin(alpha), qCos(alpha), 0, 0);
++ QMatrix scalingMatrix(distx, 0, 0, disty, 0, 0);
++
++ // forward matrix index -> map pixel coord
++ QMatrix mxFwd = scalingMatrix * rotationMatrix * translationMatrix;
++ // backward matrix map pixel coord -> index
++ QMatrix mxBwd = mxFwd.inverted();
++
++ QPointF tl = mxBwd.map(area.topLeft());
++ QPointF br = mxBwd.map(area.bottomRight());
++
++ int xMin = qCeil(tl.x()) - 1;
++ int yMin = qCeil(tl.y()) - 1;
++
++ int xMax = qCeil(br.x()) + 1;
++ int yMax = qCeil(br.y()) + 1;
++
++ qreal lonRef = widgetSetRef->getEasting();
++ qreal latRef = widgetSetRef->getNorthing();
++ qreal dLon = widgetSetRef->getHorizSpacing();
++ qreal dLat = widgetSetRef->getVertSpacing();
++
++ bool isLonLat = pj_is_latlong(pjsrc);
++
++ for(int y = yMin; y < yMax; y++)
++ {
++ for(int x = xMin; x < xMax; x++)
++ {
++ QPointF ptPtx = mxFwd.map(QPointF(x,y));
++ if(area.contains(ptPtx))
++ {
++ ptPtx.rx() = qRound(ptPtx.x());
++ ptPtx.ry() = qRound(ptPtx.y());
++
++ qreal lat = latRef - y * dLat;
++ qreal lon = lonRef + x * dLon;
++
++ if(isLonLat)
++ {
++ lon *= DEG_TO_RAD;
++ lat *= DEG_TO_RAD;
++ }
++
++ pj_transform(pjsrc, pjtar, 1, 0, &lon, &lat, 0);
++ lon *= RAD_TO_DEG;
++ lat *= RAD_TO_DEG;
++
++ refPoints << new COverlayRefMapPoint(0, QPointF(lon,lat), ptPtx, nullptr);
++ }
++ }
++ }
++
++ pj_free(pjsrc);
++ pj_free(pjtar);
++}
+diff --git a/src/qmaptool/overlay/COverlayGridTool.h b/src/qmaptool/overlay/COverlayGridTool.h
+new file mode 100644
+index 00000000..f50b22f1
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayGridTool.h
+@@ -0,0 +1,68 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef COVERLAYGRIDTOOL_H
++#define COVERLAYGRIDTOOL_H
++
++#include "canvas/CCanvas.h"
++#include "ui_IOverlayGridTool.h"
++
++class CItemRefMap;
++class COverlayRefMapPoint;
++
++class COverlayGridTool : public QWidget, private Ui::IOverlayGridTool
++{
++ Q_OBJECT
++public:
++ COverlayGridTool(QWidget * parent);
++ virtual ~COverlayGridTool() = default;
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ void leaveEventFx(QEvent *e);
++ QCursor getCursorFx();
++
++ void registerItem(CItemRefMap * item);
++
++ QList<COverlayRefMapPoint*>& getRefPoints()
++ {
++ return refPoints;
++ }
++
++signals:
++ void sigChanged(bool ok);
++
++public slots:
++ void slotReset();
++
++private slots:
++ void slotCheckInput();
++ void slotSetArea(const QRectF& rect);
++ void slotCalculate();
++
++private:
++
++ CItemRefMap * item = nullptr;
++ const IDrawContext * context = nullptr;
++
++ QList<COverlayRefMapPoint*> refPoints;
++};
++
++#endif //COVERLAYGRIDTOOL_H
++
+diff --git a/src/qmaptool/overlay/COverlayRefMap.cpp b/src/qmaptool/overlay/COverlayRefMap.cpp
+new file mode 100644
+index 00000000..0afc882c
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayRefMap.cpp
+@@ -0,0 +1,747 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CDraw.h"
++#include "helpers/CSettings.h"
++#include "items/CItemRefMap.h"
++#include "overlay/COverlayRefMap.h"
++#include "overlay/refmap/CDialogRefPoint.h"
++#include "overlay/refmap/COverlayRefMapPoint.h"
++#include "overlay/refmap/CProjWizard.h"
++
++#include <functional>
++#include <QtWidgets>
++using std::bind;
++
++COverlayRefMap::COverlayRefMap(CItemRefMap *item, QStackedWidget *stackedWidget)
++ : IOverlay(stackedWidget)
++ , context(item->getDrawContext())
++ , item(item)
++{
++ setupUi(this);
++
++ QFileInfo fi(item->getFilename());
++ gcpFilename = fi.completeBaseName() + ".gcp";
++
++ labelHelp->setText(tr("If you used the Grid Tool you have to fine tune the reference points by placing them "
++ "as much as possible on the grid crossing. Be aware that if you over scale you get "
++ "jumping points by rounding effects. Be precise but do not make religion out "
++ "of the task.\nIf your mouse focus is on the map you can use the N and B keys to "
++ "jump forward an backward in the reference point list. "
++ "\nThe is also the option to fine tune the reference points in auto-mode. In this "
++ "mode the next reference point is selected automatically right after you placed the "
++ "current one. This is very convenient for a large number of reference points."));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ treeWidget->addAction(actionDelRefPoint);
++
++ connect(toolNone, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModeNone, std::placeholders::_1));
++ connect(toolRefMove, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointMove, std::placeholders::_1));
++ connect(toolRefAdd, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointAdd, std::placeholders::_1));
++ connect(toolRefDel, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointDel, std::placeholders::_1));
++ connect(toolRefMoveAuto, &QToolButton::clicked, this, bind(&COverlayRefMap::slotSetMode, this, eModePointMoveAuto, std::placeholders::_1));
++ connect(toolRefDelAll, &QToolButton::clicked, this, &COverlayRefMap::slotResetRef);
++ connect(toolLoadGcp, &QToolButton::clicked, this, &COverlayRefMap::slotLoadGcp);
++ connect(toolSaveGcp, &QToolButton::clicked, this, &COverlayRefMap::slotSaveGcp);
++ connect(toolProjection, &QToolButton::clicked, this, &COverlayRefMap::slotProjWizard);
++ connect(toolGridTool, &QToolButton::clicked, this, &COverlayRefMap::slotGridTool);
++ connect(toolSort, &QToolButton::clicked, this, &COverlayRefMap::slotSortRefPoints);
++ connect(treeWidget, &QTreeWidget::itemSelectionChanged, this, &COverlayRefMap::slotSelectionChanged);
++ connect(actionDelRefPoint, &QAction::triggered, this, &COverlayRefMap::slotDelRefPoints);
++}
++
++void COverlayRefMap::saveSettings(QSettings& cfg)
++{
++ QByteArray buffer;
++ QDataStream stream(&buffer, QIODevice::WriteOnly);
++ stream.setByteOrder(QDataStream::LittleEndian);
++ stream.setVersion(QDataStream::Qt_5_4);
++
++ const int N = treeWidget->topLevelItemCount();
++ stream << N;
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item != nullptr)
++ {
++ stream << item->getPtPtx() << item->getPtRef();
++ }
++ }
++
++ cfg.beginGroup("grid");
++ cfg.setValue("points", buffer);
++ cfg.setValue("projection", lineProjection->text());
++ cfg.endGroup();
++}
++
++void COverlayRefMap::loadSettings(QSettings& cfg)
++{
++ QByteArray buffer;
++ cfg.beginGroup("grid");
++ buffer = cfg.value("points", buffer).toByteArray();
++ lineProjection->setText(cfg.value("projection", "").toString());
++ lineProjection->setCursorPosition(0);
++ cfg.endGroup();
++
++ QDataStream stream(&buffer, QIODevice::ReadOnly);
++ stream.setByteOrder(QDataStream::LittleEndian);
++ stream.setVersion(QDataStream::Qt_5_4);
++
++
++ int N;
++ stream >> N;
++ for(int n = 0; n < N; n++)
++ {
++ QPointF ptPtx;
++ QPointF ptRef;
++ stream >> ptPtx >> ptRef;
++ new COverlayRefMapPoint(n+1, ptRef, ptPtx, treeWidget);
++ }
++
++ updateGui();
++ slotSortRefPoints();
++ emit sigChanged();
++}
++
++void COverlayRefMap::slotSortRefPoints()
++{
++ treeWidget->sortItems(0, Qt::AscendingOrder);
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * point = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(point == nullptr)
++ {
++ continue;
++ }
++
++ point->setIndex(n);
++ }
++
++ treeWidget->header()->resizeSections(QHeaderView::ResizeToContents);
++}
++
++void COverlayRefMap::addRefPoints(QList<COverlayRefMapPoint*>& points)
++{
++ // it's faster to use a bulk add
++ QList<QTreeWidgetItem*> items;
++ for(QTreeWidgetItem * item : points)
++ {
++ items << item;
++ }
++ treeWidget->addTopLevelItems(items);
++
++ // as the tree widget owns the items now, the list has to be cleared
++ points.clear();
++ // reflect changes on the GUI
++ updateGui();
++
++ emit sigChanged();
++}
++
++QString COverlayRefMap::getMapProjection() const
++{
++ return lineProjection->text();
++}
++
++const QList<COverlayRefMapPoint*> COverlayRefMap::getRefPoints() const
++{
++ QList<COverlayRefMapPoint*> points;
++
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item != nullptr)
++ {
++ points << item;
++ }
++ }
++
++ return points;
++}
++
++bool COverlayRefMap::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ QRectF dot1(0,0,5,5);
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item != nullptr)
++ {
++ if(item->isSelected())
++ {
++ p.setPen(QPen(Qt::red, 1));
++ p.setBrush(Qt::red);
++ }
++ else
++ {
++ p.setPen(QPen(Qt::black, 1));
++ p.setBrush(Qt::black);
++ }
++
++ QPointF pt = item->getPtPtx();
++ if((pt - ptFocus1).manhattanLength() > 30)
++ {
++ context->convertMap2Screen(pt);
++ dot1.moveCenter(pt);
++ p.drawRect(dot1);
++ }
++ }
++ }
++
++ QPointF pt = NOPOINTF;
++ if(ptFocus2 != NOPOINTF)
++ {
++ pt = ptFocus2;
++ }
++ else if(ptFocus1 != NOPOINTF)
++ {
++ pt = ptFocus1;
++ }
++
++
++ if(pt != NOPOINTF)
++ {
++ context->convertMap2Screen(pt);
++
++ if(movePoint)
++ {
++ QPointF pt1 = ptFocus1;
++ context->convertMap2Screen(pt1);
++
++ p.setPen(QPen(Qt::red, 1));
++ p.setBrush(Qt::red);
++ p.drawLine(pt1, pt);
++ dot1.moveCenter(pt1);
++ p.drawRect(dot1);
++ }
++
++ CDraw::drawCrossHairDot(p, pt);
++ }
++
++
++ return true;
++}
++
++QPointF COverlayRefMap::isCloseTo(QPointF pt)
++{
++ qint32 min = 30;
++ COverlayRefMapPoint * selItem = nullptr;
++
++ context->convertMap2Screen(pt);
++
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item == nullptr)
++ {
++ continue;
++ }
++
++ QPointF ptx = item->getPtPtx();
++ context->convertMap2Screen(ptx);
++
++ qint32 d = (pt - ptx).manhattanLength();
++ if(d < min)
++ {
++ min = d;
++ selItem = item;
++ }
++ }
++
++ if(selItem != nullptr)
++ {
++ treeWidget->setCurrentItem(selItem);
++ return selItem->getPtPtx();
++ }
++ else
++ {
++ return NOPOINTF;
++ }
++}
++
++
++void COverlayRefMap::mouseMoveEventFx(QMouseEvent *e)
++{
++ QPointF pt = e->pos();
++ context->convertScreen2Map(pt);
++
++ switch(mode)
++ {
++ case eModePointMove:
++ case eModePointMoveAuto:
++ mouseMovePointMove(pt);
++ break;
++
++ case eModePointAdd:
++ mouseMovePointAdd(pt);
++ break;
++
++ case eModePointDel:
++ mouseMovePointDel(pt);
++ break;
++ }
++
++ updateGui();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayRefMap::mouseReleaseEventFx(QMouseEvent *e)
++{
++ QPointF pt = e->pos();
++ context->convertScreen2Map(pt);
++
++ Qt::MouseButton button = e->button();
++
++ switch(mode)
++ {
++ case eModePointMove:
++ case eModePointMoveAuto:
++ mouseReleasePointMove(pt, button);
++ break;
++
++ case eModePointAdd:
++ mouseReleasePointAdd(pt, button);
++ break;
++
++ case eModePointDel:
++ mouseReleasePointDel(pt, button);
++ break;
++ }
++
++ updateGui();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayRefMap::mouseMovePointAdd(const QPointF &pt)
++{
++ ptFocus1 = pt;
++}
++
++void COverlayRefMap::mouseMovePointDel(const QPointF &pt)
++{
++ ptFocus1 = isCloseTo(pt);
++}
++
++void COverlayRefMap::mouseMovePointMove(const QPointF &pt)
++{
++ if(movePoint)
++ {
++ ptFocus2 = pt;
++ }
++ else
++ {
++ ptFocus1 = isCloseTo(pt);
++ }
++}
++
++void COverlayRefMap::mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button)
++{
++ if(button == Qt::LeftButton)
++ {
++ QPointF ptPtx = pt;
++ QPointF ptRef = NOPOINTF;
++ // ask for coordinate
++ CDialogRefPoint dlg(ptPtx, ptRef, this);
++ int res = dlg.exec();
++ if(res == QDialog::Accepted)
++ {
++ new COverlayRefMapPoint(treeWidget->topLevelItemCount() + 1, ptRef, ptPtx, treeWidget);
++ emit sigChanged();
++ }
++ }
++ else if(button == Qt::RightButton)
++ {
++ abortStep();
++ toolNone->click();
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointAdd");
++ }
++}
++
++void COverlayRefMap::mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button)
++{
++ if(button == Qt::LeftButton)
++ {
++ if(ptFocus1 == NOPOINTF)
++ {
++ return;
++ }
++
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item == nullptr)
++ {
++ continue;
++ }
++
++ if(item->getPtPtx() == ptFocus1)
++ {
++ delete item;
++ abortStep();
++ emit sigChanged();
++ return;
++ }
++ }
++ }
++ else if(button == Qt::RightButton)
++ {
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointDel");
++ toolNone->click();
++ abortStep();
++ }
++}
++
++void COverlayRefMap::mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button)
++{
++ if(button == Qt::LeftButton)
++ {
++ if(movePoint)
++ {
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * item = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(item == nullptr)
++ {
++ continue;
++ }
++
++ if(item->getPtPtx() == ptFocus1)
++ {
++ item->setPtPtx(pt);
++ break;
++ }
++ }
++
++ switch(mode)
++ {
++ case eModePointMove:
++ {
++ abortStep();
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove");
++ break;
++ }
++
++ case eModePointMoveAuto:
++ {
++ int idx = treeWidget->indexOfTopLevelItem(treeWidget->currentItem()) + 1;
++ if(idx >= treeWidget->topLevelItemCount())
++ {
++ abortStep();
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove");
++ }
++ else
++ {
++ COverlayRefMapPoint * point = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(idx));
++ if(point == nullptr)
++ {
++ return;
++ }
++ treeWidget->setCurrentItem(point);
++ treeWidget->scrollToItem(point);
++
++ QPointF pt1 = point->getPtPtx();
++ ptFocus1 = pt1;
++ ptFocus2 = pt;
++ context->convertMap2Screen(pt1);
++
++ QPointF pt2 = context->getCanvas()->rect().center();
++ context->move(pt2 - pt1);
++ context->triggerCompleteUpdate(CCanvas::eRedrawAll);
++ }
++ break;
++ }
++ }
++ }
++ else
++ {
++ if(ptFocus1 != NOPOINTF)
++ {
++ ptFocus2 = pt;
++ movePoint = true;
++ CCanvas::setOverrideCursor(Qt::BlankCursor, "CRefMapGrid::mouseReleasePointMove");
++ }
++ }
++ }
++ else if(button == Qt::RightButton)
++ {
++ if(!movePoint)
++ {
++ toolNone->click();
++ }
++ abortStep();
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove");
++ }
++}
++
++
++bool COverlayRefMap::keyPressEventFx(QKeyEvent *e)
++{
++ QTreeWidgetItem * item = treeWidget->currentItem();
++ if(item == nullptr)
++ {
++ return false;
++ }
++
++ int idx = treeWidget->indexOfTopLevelItem(item);
++
++ switch(e->key())
++ {
++ case Qt::Key_N:
++ {
++ ++idx;
++ idx = qMin(idx, treeWidget->topLevelItemCount() - 1);
++ break;
++ }
++
++ case Qt::Key_B:
++ {
++ --idx;
++ idx = qMax(idx, 0);
++ break;
++ }
++
++ default:
++ return false;
++ }
++
++
++ if(movePoint)
++ {
++ switch(mode)
++ {
++ case eModePointMove:
++ return false;
++
++ case eModePointMoveAuto:
++ abortStep();
++ CCanvas::restoreOverrideCursor("CRefMapGrid::mouseReleasePointMove");
++ break;
++ }
++ }
++
++ COverlayRefMapPoint * point = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(idx));
++ if(point == nullptr)
++ {
++ return false;
++ }
++ treeWidget->setCurrentItem(point);
++ treeWidget->scrollToItem(point);
++
++ QPointF pt1 = point->getPtPtx();
++ QPointF pt2 = context->getCanvas()->rect().center();
++ context->convertMap2Screen(pt1);
++ context->move(pt2 - pt1);
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawAll);
++
++ return true;
++}
++
++QCursor COverlayRefMap::getCursorFx()
++{
++ switch(mode)
++ {
++ case COverlayRefMap::eModePointAdd:
++ return Qt::BlankCursor;
++
++ case COverlayRefMap::eModePointDel:
++ return QCursor(QPixmap(":/cursors/cursorPointDel.png"), 0, 0);
++
++ case COverlayRefMap::eModePointMoveAuto:
++ case COverlayRefMap::eModePointMove:
++ return QCursor(QPixmap(":/cursors/cursorPointMove.png"), 0, 0);
++ }
++
++ return Qt::ArrowCursor;
++}
++
++void COverlayRefMap::updateGui()
++{
++ bool isEmpty = treeWidget->topLevelItemCount() == 0;
++ toolRefDel->setDisabled(isEmpty);
++ toolRefMove->setDisabled(isEmpty);
++ toolRefDelAll->setDisabled(isEmpty);
++ toolRefMoveAuto->setDisabled(isEmpty);
++ toolSaveGcp->setDisabled(isEmpty);
++}
++
++void COverlayRefMap::abortStep()
++{
++ movePoint = false;
++ ptFocus1 = NOPOINTF;
++ ptFocus2 = NOPOINTF;
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayRefMap::slotSetMode(mode_e m, bool on)
++{
++ if(on)
++ {
++ mode = m;
++ }
++}
++
++void COverlayRefMap::slotSaveGcp()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/gcpInput", QDir::homePath()).toString();
++
++ QString filename = QFileDialog::getSaveFileName(0, tr("Save reference points..."), path + "/" + gcpFilename, "Ref. points (*.gcp)");
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/gcpInput", QFileInfo(filename).absolutePath());
++
++ gcpFilename = filename;
++
++ QFile file(filename);
++ file.open(QIODevice::WriteOnly);
++ QTextStream out(&file);
++ out.setRealNumberPrecision(10);
++
++ out << "#V1.0" << endl;
++ out << "#gcpproj: +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" << endl;
++
++ const int N = treeWidget->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ COverlayRefMapPoint * pt = dynamic_cast<COverlayRefMapPoint*>(treeWidget->topLevelItem(n));
++ if(pt == nullptr)
++ {
++ continue;
++ }
++ const QPointF& ptx = pt->getPtPtx();
++ const QPointF& ref = pt->getPtRef();
++
++ out << "-gcp " << ptx.x() << " " << ptx.y() << " " << ref.y() << " " << ref.x() << endl;
++ }
++
++ file.close();
++}
++
++void COverlayRefMap::slotLoadGcp()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/gcpInput", QDir::homePath()).toString();
++
++ QString filename = QFileDialog::getOpenFileName(0, tr("Load reference points..."), path, "Ref. points (*.gcp)");
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/gcpInput", QFileInfo(filename).absolutePath());
++
++ QFile file(filename);
++ file.open(QIODevice::ReadOnly);
++ QString line = file.readLine();
++ if(line.trimmed() == "#V1.0")
++ {
++ QRegExp re1("^-gcp\\s(-{0,1}[0-9]+)\\s(-{0,1}[0-9]+)\\s(-{0,1}[0-9\\.]+)\\s(-{0,1}[0-9\\.]+).*$");
++ QRegExp re2("^-a_srs\\s(.*)$");
++ QRegExp re3("^#gcpproj:\\s(.*)$");
++
++ qint32 cnt = 1;
++ while(1)
++ {
++ if(re1.exactMatch(line))
++ {
++ QPointF ptPtx(re1.cap(1).toDouble(),re1.cap(2).toDouble());
++ QPointF ptRef(re1.cap(4).toDouble(),re1.cap(3).toDouble());
++ new COverlayRefMapPoint(cnt++, ptRef, ptPtx, treeWidget);
++ }
++
++ if (file.atEnd())
++ {
++ break;
++ }
++ line = file.readLine();
++ }
++ }
++
++ updateGui();
++
++ emit sigChanged();
++}
++
++void COverlayRefMap::slotResetRef()
++{
++ int res = QMessageBox::question(this, tr("Delete all reference points..."), tr("Are you sure to delete all reference points in the list?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
++ if(res != QMessageBox::Yes)
++ {
++ return;
++ }
++ treeWidget->clear();
++ updateGui();
++
++ emit sigChanged();
++}
++
++void COverlayRefMap::slotProjWizard()
++{
++ CProjWizard dlg(*lineProjection, this);
++ dlg.exec();
++ lineProjection->setCursorPosition(0);
++
++ emit sigChanged();
++}
++
++void COverlayRefMap::slotGridTool()
++{
++ CMainWindow::self().startGridTool(item);
++}
++
++void COverlayRefMap::slotSelectionChanged()
++{
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void COverlayRefMap::slotDelRefPoints()
++{
++ const QList<QTreeWidgetItem*>items = treeWidget->selectedItems();
++ if(items.count() > 1)
++ {
++ int res = QMessageBox::question(this, tr("Delete..."), tr("Delete all selected reference points?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
++ if(res != QMessageBox::Yes)
++ {
++ return;
++ }
++ }
++
++ qDeleteAll(items);
++
++ emit sigChanged();
++}
++
++bool COverlayRefMap::isOk() const
++{
++ bool ok = true;
++ ok &= (treeWidget->topLevelItemCount() > 2);
++ ok &= CProjWizard::validProjStr(lineProjection->text());
++ return ok;
++}
+diff --git a/src/qmaptool/overlay/COverlayRefMap.h b/src/qmaptool/overlay/COverlayRefMap.h
+new file mode 100644
+index 00000000..03391000
+--- /dev/null
++++ b/src/qmaptool/overlay/COverlayRefMap.h
+@@ -0,0 +1,103 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef COVERLAYREFMAP_H
++#define COVERLAYREFMAP_H
++
++#include "overlay/IOverlay.h"
++#include "ui_IOverlayRefMap.h"
++#include "units/IUnit.h"
++
++class QStackedWidget;
++class IDrawContext;
++class QSettings;
++class CItemRefMap;
++class COverlayRefMapPoint;
++
++class COverlayRefMap : public IOverlay, private Ui::IOverlayRefMap
++{
++ Q_OBJECT
++public:
++ COverlayRefMap(CItemRefMap *item, QStackedWidget * stackedWidget);
++ virtual ~COverlayRefMap() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ void addRefPoints(QList<COverlayRefMapPoint*>& points);
++ QString getMapProjection() const;
++ const QList<COverlayRefMapPoint *> getRefPoints() const;
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ bool keyPressEventFx(QKeyEvent *e);
++ QCursor getCursorFx();
++
++ void abortStep();
++
++ enum mode_e
++ {
++ eModeNone
++ ,eModePointMove
++ ,eModePointAdd
++ ,eModePointDel
++ ,eModePointMoveAuto
++ };
++
++ bool isOk() const;
++
++private slots:
++ void slotSetMode(mode_e m, bool on);
++ void slotSaveGcp();
++ void slotLoadGcp();
++ void slotResetRef();
++ void slotProjWizard();
++ void slotGridTool();
++ void slotSelectionChanged();
++ void slotDelRefPoints();
++ void slotSortRefPoints();
++
++
++private:
++ void updateGui();
++ QPointF isCloseTo(QPointF pt);
++
++ void mouseMovePointAdd(const QPointF &pt);
++ void mouseMovePointDel(const QPointF &pt);
++ void mouseMovePointMove(const QPointF &pt);
++
++ void mouseReleasePointAdd(const QPointF &pt, Qt::MouseButton button);
++ void mouseReleasePointDel(const QPointF &pt, Qt::MouseButton button);
++ void mouseReleasePointMove(const QPointF &pt, Qt::MouseButton button);
++
++ IDrawContext* context;
++ CItemRefMap * item;
++
++ mode_e mode = eModeNone;
++
++ QPointF ptFocus1 = NOPOINTF;
++ QPointF ptFocus2 = NOPOINTF;
++ bool movePoint = false;
++
++ QString gcpFilename;
++};
++
++#endif //COVERLAYREFMAP_H
++
++
+diff --git a/src/qmaptool/overlay/IOverlay.cpp b/src/qmaptool/overlay/IOverlay.cpp
+new file mode 100644
+index 00000000..148d1c10
+--- /dev/null
++++ b/src/qmaptool/overlay/IOverlay.cpp
+@@ -0,0 +1,36 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "overlay/IOverlay.h"
++
++#include <QtWidgets>
++
++IOverlay::IOverlay(QStackedWidget *parent)
++ : QWidget(parent)
++ , stackedWidget(parent)
++{
++ stackedWidget->addWidget(this);
++}
++
++
++void IOverlay::toFront()
++{
++ stackedWidget->setCurrentWidget(this);
++}
++
++
+diff --git a/src/qmaptool/overlay/IOverlay.h b/src/qmaptool/overlay/IOverlay.h
+new file mode 100644
+index 00000000..d7e968ec
+--- /dev/null
++++ b/src/qmaptool/overlay/IOverlay.h
+@@ -0,0 +1,43 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef IOVERLAY_H
++#define IOVERLAY_H
++
++#include <QWidget>
++
++class QStackedWidget;
++
++class IOverlay : public QWidget
++{
++ Q_OBJECT
++public:
++ IOverlay(QStackedWidget * parent);
++ virtual ~IOverlay() = default;
++
++ void toFront();
++
++signals:
++ void sigChanged();
++
++protected:
++ QStackedWidget * stackedWidget;
++};
++
++#endif //IOVERLAY_H
++
+diff --git a/src/qmaptool/overlay/IOverlayCutMap.ui b/src/qmaptool/overlay/IOverlayCutMap.ui
+new file mode 100644
+index 00000000..e7a69766
+--- /dev/null
++++ b/src/qmaptool/overlay/IOverlayCutMap.ui
+@@ -0,0 +1,202 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IOverlayCutMap</class>
++ <widget class="QWidget" name="IOverlayCutMap">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>254</width>
++ <height>25</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QToolButton" name="toolNone">
++ <property name="toolTip">
++ <string>Just move the map and zoom.</string>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/MoveArrow.png</normaloff>:/icons/32x32/MoveArrow.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolPointAdd">
++ <property name="toolTip">
++ <string>Add point to mask.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PointAdd.png</normaloff>:/icons/32x32/PointAdd.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolPointMove">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Move point of mask.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PointMove.png</normaloff>:/icons/32x32/PointMove.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolPointDel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove point from mask.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PointDel.png</normaloff>:/icons/32x32/PointDel.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="Line" name="line">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolPointDelAll">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove complete cut mask.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PointDelAll.png</normaloff>:/icons/32x32/PointDelAll.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="Line" name="line_2">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolLoadShape">
++ <property name="toolTip">
++ <string>Load cut mask from shape file.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/LoadShape.png</normaloff>:/icons/32x32/LoadShape.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolSaveShape">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Save cut mask to shape file.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/SaveShape.png</normaloff>:/icons/32x32/SaveShape.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/IOverlayGridTool.ui b/src/qmaptool/overlay/IOverlayGridTool.ui
+new file mode 100644
+index 00000000..7e8c1ab3
+--- /dev/null
++++ b/src/qmaptool/overlay/IOverlayGridTool.ui
+@@ -0,0 +1,184 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IOverlayGridTool</class>
++ <widget class="QWidget" name="IOverlayGridTool">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>462</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QGridLayout" name="gridLayout_2">
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item row="0" column="0">
++ <layout class="QVBoxLayout" name="verticalLayout_3">
++ <item>
++ <widget class="QRadioButton" name="radioSetRef">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer_3">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item row="1" column="0">
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <widget class="QRadioButton" name="radioGridPlacer">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item row="1" column="1">
++ <widget class="CGridPlacer" name="widgetGridPlacer" native="true">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="0">
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <item>
++ <widget class="QRadioButton" name="radioSelectArea">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer_2">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item row="2" column="1">
++ <widget class="CGridSelArea" name="widgetSelectArea" native="true">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="1">
++ <widget class="QLabel" name="labelFinal">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="CGridSetRef" name="widgetSetRef" native="true"/>
++ </item>
++ </layout>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CGridPlacer</class>
++ <extends>QWidget</extends>
++ <header>overlay/gridtool/CGridPlacer.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CGridSelArea</class>
++ <extends>QWidget</extends>
++ <header>overlay/gridtool/CGridSelArea.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CGridSetRef</class>
++ <extends>QWidget</extends>
++ <header>overlay/gridtool/CGridSetRef.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <tabstops>
++ <tabstop>radioSetRef</tabstop>
++ <tabstop>radioGridPlacer</tabstop>
++ <tabstop>radioSelectArea</tabstop>
++ </tabstops>
++ <resources/>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/IOverlayRefMap.ui b/src/qmaptool/overlay/IOverlayRefMap.ui
+new file mode 100644
+index 00000000..9001fe66
+--- /dev/null
++++ b/src/qmaptool/overlay/IOverlayRefMap.ui
+@@ -0,0 +1,351 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IOverlayRefMap</class>
++ <widget class="QWidget" name="IOverlayRefMap">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>376</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QToolButton" name="toolNone">
++ <property name="toolTip">
++ <string>Just move the map and zoom.</string>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/MoveArrow.png</normaloff>:/icons/32x32/MoveArrow.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolRefAdd">
++ <property name="toolTip">
++ <string>Add reference point.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/RefAdd.png</normaloff>:/icons/32x32/RefAdd.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolRefMove">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Move reference point.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/RefMove.png</normaloff>:/icons/32x32/RefMove.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolRefDel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove single reference point.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/RefDel.png</normaloff>:/icons/32x32/RefDel.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolRefMoveAuto">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Move reference points with auto mode. This will pickup the next point after you moved a reference point.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/RefMoveAuto.png</normaloff>:/icons/32x32/RefMoveAuto.png</iconset>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="autoExclusive">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="Line" name="line_2">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolRefDelAll">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Remove all reference points.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/RefDelAll.png</normaloff>:/icons/32x32/RefDelAll.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolGridTool">
++ <property name="toolTip">
++ <string>Switch to the Grid Tool.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/GridTool.png</normaloff>:/icons/32x32/GridTool.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="Line" name="line">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolLoadGcp">
++ <property name="toolTip">
++ <string>Load reference points from GCP file.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/LoadGcp.png</normaloff>:/icons/32x32/LoadGcp.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolSaveGcp">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="toolTip">
++ <string>Save reference points into GCP file.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/SaveGcp.png</normaloff>:/icons/32x32/SaveGcp.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolSort">
++ <property name="toolTip">
++ <string>Sort list of reference points.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Sort.png</normaloff>:/icons/32x32/Sort.png</iconset>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QTreeWidget" name="treeWidget">
++ <property name="contextMenuPolicy">
++ <enum>Qt::ActionsContextMenu</enum>
++ </property>
++ <property name="selectionMode">
++ <enum>QAbstractItemView::ExtendedSelection</enum>
++ </property>
++ <property name="selectionBehavior">
++ <enum>QAbstractItemView::SelectRows</enum>
++ </property>
++ <property name="rootIsDecorated">
++ <bool>false</bool>
++ </property>
++ <property name="itemsExpandable">
++ <bool>false</bool>
++ </property>
++ <property name="expandsOnDoubleClick">
++ <bool>false</bool>
++ </property>
++ <column>
++ <property name="text">
++ <string notr="true">#</string>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>(x, y)[pixel]</string>
++ </property>
++ </column>
++ <column>
++ <property name="text">
++ <string>(lat, lon)[°]</string>
++ </property>
++ </column>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Final Map Projection:</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QLineEdit" name="lineProjection">
++ <property name="toolTip">
++ <string>Enter a valid projection string. Valid strings are &quot;+proj...&quot; or &quot;+init=epsg:...&quot;.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolProjection">
++ <property name="toolTip">
++ <string>Start projection wizard.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/GridWizard.png</normaloff>:/icons/32x32/GridWizard.png</iconset>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ <action name="actionDelRefPoint">
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/DeleteMultiple.png</normaloff>:/icons/32x32/DeleteMultiple.png</iconset>
++ </property>
++ <property name="text">
++ <string>Delete</string>
++ </property>
++ </action>
++ </widget>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/gridtool/CGridPlacer.cpp b/src/qmaptool/overlay/gridtool/CGridPlacer.cpp
+new file mode 100644
+index 00000000..62b211c3
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridPlacer.cpp
+@@ -0,0 +1,274 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "items/CItemRefMap.h"
++#include "overlay/gridtool/CGridPlacer.h"
++#include "overlay/gridtool/CGridPoint.h"
++
++#include <functional>
++#include <QtWidgets>
++using std::bind;
++
++
++CGridPlacer::CGridPlacer(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++
++ labelHelp->setText(tr("Select one of the corners and place the marker at "
++ "the corresponding grid crossing on the map. All "
++ "4 corners have to be placed."));
++
++ QButtonGroup * group = new QButtonGroup(this);
++ group->addButton(radioPoint1);
++ group->addButton(radioPoint2);
++ group->addButton(radioPoint3);
++ group->addButton(radioPoint4);
++
++ connect(radioPoint1, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 0, std::placeholders::_1));
++ connect(radioPoint2, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 1, std::placeholders::_1));
++ connect(radioPoint3, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 2, std::placeholders::_1));
++ connect(radioPoint4, &QToolButton::toggled, this, bind(&CGridPlacer::slotSetPoint, this, 3, std::placeholders::_1));
++ connect(pushReset, &QPushButton::clicked, this, &CGridPlacer::slotReset);
++ connect(pushSetArea, &QPushButton::clicked, this, &CGridPlacer::slotSetArea);
++}
++
++void CGridPlacer::registerItem(CItemRefMap * item)
++{
++ this->item = item;
++
++ if(item != nullptr)
++ {
++ points = QVector<CGridPoint>(4);
++
++ for(CGridPoint& point : points)
++ {
++ point.registerItem(item);
++ }
++
++ radioPoint1->setChecked(true);
++ }
++}
++
++void CGridPlacer::saveSettings(QSettings& cfg)
++{
++ cfg.beginGroup("Points");
++ for(int i = 0; i < points.size(); i++)
++ {
++ const QPointF& pt = points[i].getPoint();
++ if(pt != NOPOINTF)
++ {
++ cfg.setValue(QString::number(i), pt);
++ }
++ }
++ cfg.endGroup();
++}
++
++void CGridPlacer::loadSettings(QSettings& cfg)
++{
++ cfg.beginGroup("Points");
++ for(int i = 0; i < points.size(); i++)
++ {
++ QPointF pt = cfg.value(QString::number(i), NOPOINTF).toPointF();
++ points[i].setPoint(pt);
++ }
++ cfg.endGroup();
++ updateStatus();
++}
++
++bool CGridPlacer::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ for(CGridPoint& point : points)
++ {
++ point.drawFx(p, needsRedraw);
++ }
++
++ return true;
++}
++
++void CGridPlacer::mouseMoveEventFx(QMouseEvent *e)
++{
++ points[idx].mouseMoveEventFx(e);
++}
++
++void CGridPlacer::mouseReleaseEventFx(QMouseEvent *e)
++{
++ points[idx].mouseReleaseEventFx(e);
++ updateStatus();
++}
++
++void CGridPlacer::leaveEventFx(QEvent *e)
++{
++ points[idx].leaveEventFx(e);
++}
++
++QCursor CGridPlacer::getCursorFx()
++{
++ return points[idx].getCursorFx();
++}
++
++void CGridPlacer::slotSetPoint(qint32 i, bool on)
++{
++ if(on)
++ {
++ idx = i;
++ }
++}
++
++void CGridPlacer::slotReset()
++{
++ for(CGridPoint& point : points)
++ {
++ point.setPoint(NOPOINTF);
++ }
++
++ updateStatus();
++
++ item->getDrawContext()->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void CGridPlacer::updateStatus()
++{
++ /// @todo optimize this
++
++ const QPointF& pt1 = points[0].getPoint();
++ const QPointF& pt2 = points[1].getPoint();
++ const QPointF& pt3 = points[2].getPoint();
++ const QPointF& pt4 = points[3].getPoint();
++
++ statusIsOk = true;
++
++ if(pt1 == NOPOINTF)
++ {
++ statusIsOk = false;
++ labelStatusPoint1->setText(tr("Point 1 - not set"));
++ }
++ else
++ {
++ labelStatusPoint1->setText("<b style='color: green'>" + tr("Point 1 - ok") + "</b>");
++
++ if((pt2 != NOPOINTF) && (pt2.x() < pt1.x()))
++ {
++ statusIsOk = false;
++ labelStatusPoint1->setText("<b style='color: red'>" + tr("Point 1 - bad") + "</b>");
++ }
++ if((pt4 != NOPOINTF) && (pt4.y() < pt1.y()))
++ {
++ statusIsOk = false;
++ labelStatusPoint1->setText("<b style='color: red'>" + tr("Point 1 - bad") + "</b>");
++ }
++ }
++
++ if(pt2 == NOPOINTF)
++ {
++ statusIsOk = false;
++ labelStatusPoint2->setText(tr("Point 2 - not set"));
++ }
++ else
++ {
++ labelStatusPoint2->setText("<b style='color: green'>" + tr("Point 2 - ok") + "</b>");
++
++ if((pt1 != NOPOINTF) && (pt1.x() > pt2.x()))
++ {
++ statusIsOk = false;
++ labelStatusPoint2->setText("<b style='color: red'>" + tr("Point 2 - bad") + "</b>");
++ }
++ if((pt3 != NOPOINTF) && (pt3.y() < pt2.y()))
++ {
++ statusIsOk = false;
++ labelStatusPoint2->setText("<b style='color: red'>" + tr("Point 2 - bad") + "</b>");
++ }
++ }
++
++
++ if(pt3 == NOPOINTF)
++ {
++ statusIsOk = false;
++ labelStatusPoint3->setText(tr("Point 3 - not set"));
++ }
++ else
++ {
++ labelStatusPoint3->setText("<b style='color: green'>" + tr("Point 3 - ok") + "</b>");
++
++ if((pt4 != NOPOINTF) && (pt4.x() > pt3.x()))
++ {
++ statusIsOk = false;
++ labelStatusPoint3->setText("<b style='color: red'>" + tr("Point 3 - bad") + "</b>");
++ }
++ if((pt2 != NOPOINTF) && (pt2.y() > pt3.y()))
++ {
++ statusIsOk = false;
++ labelStatusPoint3->setText("<b style='color: red'>" + tr("Point 3 - bad") + "</b>");
++ }
++ }
++
++
++ if(pt4 == NOPOINTF)
++ {
++ statusIsOk = false;
++ labelStatusPoint4->setText(tr("Point 4 - not set"));
++ }
++ else
++ {
++ labelStatusPoint4->setText("<b style='color: green'>" + tr("Point 4 - ok") + "</b>");
++
++ if((pt3 != NOPOINTF) && (pt3.x() < pt4.x()))
++ {
++ statusIsOk = false;
++ labelStatusPoint4->setText("<b style='color: red'>" + tr("Point 4 - bad") + "</b>");
++ }
++ if((pt1 != NOPOINTF) && (pt1.y() > pt4.y()))
++ {
++ statusIsOk = false;
++ labelStatusPoint4->setText("<b style='color: red'>" + tr("Point 4 - bad") + "</b>");
++ }
++ }
++
++ pushSetArea->setEnabled(statusIsOk);
++
++ emit sigChanged();
++}
++
++
++void CGridPlacer::slotSetArea() const
++{
++ qreal bottom = -NOFLOAT;
++ qreal top = NOFLOAT;
++ qreal left = NOFLOAT;
++ qreal right = -NOFLOAT;
++
++ for(const CGridPoint& point : points)
++ {
++ const QPointF& pt = point.getPoint();
++
++ top = qMin(pt.y(), top);
++ bottom = qMax(pt.y(), bottom);
++ left = qMin(pt.x(), left);
++ right = qMax(pt.x(), right);
++ }
++
++ QRectF r(0,0,1,1);
++ r.setLeft(left);
++ r.setRight(right);
++ r.setTop(top);
++ r.setBottom(bottom);
++
++
++ emit sigSetArea(r);
++}
+diff --git a/src/qmaptool/overlay/gridtool/CGridPlacer.h b/src/qmaptool/overlay/gridtool/CGridPlacer.h
+new file mode 100644
+index 00000000..8d321041
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridPlacer.h
+@@ -0,0 +1,85 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CGRIDPLACER_H
++#define CGRIDPLACER_H
++
++#include "canvas/CCanvas.h"
++#include "overlay/gridtool/CGridPoint.h"
++
++#include "ui_IGridPlacer.h"
++
++class CItemRefMap;
++class QSettings;
++
++class CGridPlacer : public QWidget, private Ui::IGridPlacer
++{
++ Q_OBJECT
++public:
++ CGridPlacer(QWidget * parent);
++ virtual ~CGridPlacer() = default;
++
++ void registerItem(CItemRefMap * item);
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ void leaveEventFx(QEvent *e);
++ QCursor getCursorFx();
++
++ bool isOk() const
++ {
++ return statusIsOk;
++ }
++
++ const QPointF& getPoint(int idx) const
++ {
++ if(idx < points.count())
++ {
++ return points[idx].getPoint();
++ }
++ return NOPOINTF;
++ }
++
++signals:
++ void sigChanged();
++ void sigSetArea(const QRectF& area) const;
++
++public slots:
++ void slotReset();
++
++private slots:
++ void slotSetPoint(qint32 i, bool on);
++ void slotSetArea() const;
++
++private:
++ void updateStatus();
++ CItemRefMap * item = nullptr;
++
++ qint32 idx = 0;
++
++ QVector<CGridPoint> points;
++
++ bool statusIsOk = false;
++};
++
++#endif //CGRIDPLACER_H
++
+diff --git a/src/qmaptool/overlay/gridtool/CGridPoint.cpp b/src/qmaptool/overlay/gridtool/CGridPoint.cpp
+new file mode 100644
+index 00000000..b1a1cf6e
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridPoint.cpp
+@@ -0,0 +1,184 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CDraw.h"
++#include "items/CItemRefMap.h"
++#include "overlay/gridtool/CGridPoint.h"
++
++#include <QtWidgets>
++
++CGridPoint::CGridPoint()
++{
++}
++
++void CGridPoint::registerItem(CItemRefMap * item)
++{
++ this->item = item;
++
++ if(item != nullptr)
++ {
++ context = item->getDrawContext();
++ if(context == nullptr)
++ {
++ this->item = nullptr;
++ }
++ }
++ else
++ {
++ context = nullptr;
++ }
++}
++
++bool CGridPoint::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ if(ptFocus1 != NOPOINTF)
++ {
++ QPointF pt = ptFocus1;
++ context->convertMap2Screen(pt);
++ CDraw::drawCrossHairDot(p, pt);
++ }
++
++ if(ptPoint != NOPOINTF)
++ {
++ QPointF pt = ptPoint;
++ context->convertMap2Screen(pt);
++
++ QRectF dot1(0,0,7,7);
++ dot1.moveCenter(pt);
++
++ if(state == eStateHighlight)
++ {
++ p.setPen(QPen(QColor("#ffaa00"), 2));
++ p.setBrush(QColor("#ffaa00"));
++ }
++ else
++ {
++ p.setPen(QPen(Qt::white, 1));
++ p.setBrush(QColor("#ffaa00"));
++ }
++
++ p.drawRect(dot1);
++ }
++
++ return true;
++}
++
++void CGridPoint::mouseMoveEventFx(QMouseEvent *e)
++{
++ QPointF pt = e->pos();
++
++
++ switch(state)
++ {
++ case eStateMove:
++ case eStateNotSet:
++ context->convertScreen2Map(pt);
++ ptFocus1 = pt;
++ break;
++
++ case eStateSet:
++ {
++ QPointF point = ptPoint;
++ context->convertMap2Screen(point);
++ if((point - pt).manhattanLength() < 30)
++ {
++ state = eStateHighlight;
++ }
++ break;
++ }
++
++ case eStateHighlight:
++ {
++ QPointF point = ptPoint;
++ context->convertMap2Screen(point);
++ if((point - pt).manhattanLength() >= 30)
++ {
++ state = eStateSet;
++ }
++ break;
++ }
++ }
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void CGridPoint::mouseReleaseEventFx(QMouseEvent *e)
++{
++ switch(state)
++ {
++ case eStateMove:
++ case eStateNotSet:
++ ptPoint = ptFocus1;
++ ptFocus1 = NOPOINTF;
++ state = eStateSet;
++ CCanvas::restoreOverrideCursor("CGridPoint::mouseReleaseEventFx");
++ break;
++
++ case eStateSet:
++ break;
++
++ case eStateHighlight:
++ ptFocus1 = ptPoint;
++ ptPoint = NOPOINTF;
++ state = eStateMove;
++ CCanvas::setOverrideCursor(Qt::BlankCursor, "CGridPoint::mouseReleaseEventFx");
++ break;
++ }
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++void CGridPoint::leaveEventFx(QEvent *e)
++{
++ ptFocus1 = NOPOINTF;
++
++ switch(state)
++ {
++ case eStateNotSet:
++ case eStateSet:
++ break;
++
++ case eStateHighlight:
++ case eStateMove:
++ state = eStateSet;
++ break;
++ }
++
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++}
++
++QCursor CGridPoint::getCursorFx()
++{
++ switch(state)
++ {
++ case eStateNotSet:
++ return Qt::BlankCursor;
++
++ case eStateSet:
++ return Qt::ArrowCursor;
++
++ case eStateHighlight:
++ return Qt::ArrowCursor;
++
++ case eStateMove:
++ return Qt::BlankCursor;
++ }
++
++ return Qt::ArrowCursor;
++}
+diff --git a/src/qmaptool/overlay/gridtool/CGridPoint.h b/src/qmaptool/overlay/gridtool/CGridPoint.h
+new file mode 100644
+index 00000000..5db2d868
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridPoint.h
+@@ -0,0 +1,70 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CGRIDPOINT_H
++#define CGRIDPOINT_H
++
++#include "canvas/CCanvas.h"
++#include "units/IUnit.h"
++
++class CItemRefMap;
++class IDrawContext;
++
++class CGridPoint
++{
++public:
++ CGridPoint();
++ virtual ~CGridPoint() = default;
++
++ void registerItem(CItemRefMap * item);
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ void leaveEventFx(QEvent *e);
++ QCursor getCursorFx();
++
++ const QPointF& getPoint() const
++ {
++ return ptPoint;
++ }
++
++ void setPoint(const QPointF& pt)
++ {
++ ptPoint = pt;
++ state = pt == NOPOINTF ? eStateNotSet : eStateSet;
++ }
++
++private:
++ enum state_e
++ {
++ eStateNotSet
++ ,eStateSet
++ ,eStateHighlight
++ ,eStateMove
++ };
++
++ state_e state = eStateNotSet;
++ CItemRefMap * item = nullptr;
++ const IDrawContext * context = nullptr;
++ QPointF ptPoint = NOPOINTF;
++ QPointF ptFocus1 = NOPOINTF;
++};
++
++#endif //CGRIDPOINT_H
++
+diff --git a/src/qmaptool/overlay/gridtool/CGridSelArea.cpp b/src/qmaptool/overlay/gridtool/CGridSelArea.cpp
+new file mode 100644
+index 00000000..d929633d
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridSelArea.cpp
+@@ -0,0 +1,240 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "helpers/CDraw.h"
++#include "items/CItemRefMap.h"
++#include "overlay/gridtool/CGridSelArea.h"
++
++#include <QtWidgets>
++
++CGridSelArea::CGridSelArea(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++ labelHelp->setText(tr("Select the area to be covered by the calculated reference points. Simply grab "
++ "the corners of the selection rectangle with a left click and place them where "
++ "you want with a second click."));
++}
++
++
++void CGridSelArea::registerItem(CItemRefMap * item)
++{
++ this->item = item;
++
++ if(item != nullptr)
++ {
++ context = item->getDrawContext();
++ if(context == nullptr)
++ {
++ this->item = nullptr;
++ }
++ }
++ else
++ {
++ context = nullptr;
++ }
++}
++
++void CGridSelArea::saveSettings(QSettings& cfg)
++{
++ cfg.setValue("area", area);
++}
++
++void CGridSelArea::loadSettings(QSettings& cfg)
++{
++ area = cfg.value("area", QRectF()).toRectF();
++ emit sigChanged();
++}
++
++bool CGridSelArea::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ if(area.isEmpty())
++ {
++ return false;
++ }
++
++ QRectF rect = area;
++ context->convertMap2Screen(rect);
++
++ rectTopLeft.moveTopLeft(rect.topLeft());
++ rectTopRight.moveTopRight(rect.topRight());
++ rectBottomLeft.moveBottomLeft(rect.bottomLeft());
++ rectBottomRight.moveBottomRight(rect.bottomRight());
++
++ CDraw::drawRectangle(p, rectTopLeft, Qt::black, Qt::lightGray);
++ CDraw::drawRectangle(p, rectTopRight, Qt::black, Qt::lightGray);
++ CDraw::drawRectangle(p, rectBottomLeft, Qt::black, Qt::lightGray);
++ CDraw::drawRectangle(p, rectBottomRight, Qt::black, Qt::lightGray);
++
++ p.setBrush(Qt::red);
++ switch(corner)
++ {
++ case eCornerTopLeft:
++ CDraw::drawRectangle(p, rectTopLeft, Qt::black, Qt::red);
++ break;
++
++ case eCornerTopRight:
++ CDraw::drawRectangle(p, rectTopRight, Qt::black, Qt::red);
++ break;
++
++ case eCornerBottomLeft:
++ CDraw::drawRectangle(p, rectBottomLeft, Qt::black, Qt::red);
++ break;
++
++ case eCornerBottomRight:
++ CDraw::drawRectangle(p, rectBottomRight, Qt::black, Qt::red);
++ break;
++ }
++
++ CDraw::drawRectangle(p, rect, QPen(Qt::black), Qt::NoBrush);
++
++ return true;
++}
++
++void CGridSelArea::mouseMoveEventFx(QMouseEvent *e)
++{
++ switch(state)
++ {
++ case eStateIdle:
++ {
++ corner_e _corner = corner;
++ QPoint pos = e->pos();
++ if(rectTopLeft.contains(pos))
++ {
++ offset = pos - rectTopLeft.topLeft();
++ corner = eCornerTopLeft;
++ }
++ else if(rectTopRight.contains(pos))
++ {
++ offset = pos - rectTopRight.topRight();
++ corner = eCornerTopRight;
++ }
++ else if(rectBottomLeft.contains(pos))
++ {
++ offset = pos - rectBottomLeft.bottomLeft();
++ corner = eCornerBottomLeft;
++ }
++ else if(rectBottomRight.contains(pos))
++ {
++ offset = pos - rectBottomRight.bottomRight();
++ corner = eCornerBottomRight;
++ }
++ else
++ {
++ corner = eCornerNone;
++ }
++
++ if(corner != _corner)
++ {
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ }
++
++ break;
++ }
++
++ case eStateMove:
++ {
++ QPointF pos = e->pos() - offset;
++ context->convertScreen2Map(pos);
++
++ switch(corner)
++ {
++ case eCornerTopLeft:
++ area.setTopLeft(pos);
++ break;
++
++ case eCornerTopRight:
++ area.setTopRight(pos);
++ break;
++
++ case eCornerBottomLeft:
++ area.setBottomLeft(pos);
++ break;
++
++ case eCornerBottomRight:
++ area.setBottomRight(pos);
++ break;
++ }
++
++ emit sigChanged();
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ break;
++ }
++ }
++}
++
++void CGridSelArea::mouseReleaseEventFx(QMouseEvent *e)
++{
++ if(e->button() == Qt::LeftButton)
++ {
++ switch(state)
++ {
++ case eStateIdle:
++ {
++ if(corner != eCornerNone)
++ {
++ areaSave = area;
++ state = eStateMove;
++ }
++ break;
++ }
++
++ case eStateMove:
++ {
++ corner = eCornerNone;
++ state = eStateIdle;
++ break;
++ }
++ }
++ }
++ else
++ {
++ area = areaSave;
++ state = eStateIdle;
++ corner = eCornerNone;
++ }
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ emit sigChanged();
++}
++
++void CGridSelArea::leaveEventFx(QEvent *e)
++{
++}
++
++QCursor CGridSelArea::getCursorFx()
++{
++ return Qt::ArrowCursor;
++}
++
++
++void CGridSelArea::slotSetArea(const QRectF& rect)
++{
++ area = rect;
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ emit sigChanged();
++}
++
++void CGridSelArea::slotReset()
++{
++ area = QRectF();
++ state = eStateIdle;
++ corner = eCornerNone;
++ context->triggerCompleteUpdate(CCanvas::eRedrawOverlay);
++ emit sigChanged();
++}
+diff --git a/src/qmaptool/overlay/gridtool/CGridSelArea.h b/src/qmaptool/overlay/gridtool/CGridSelArea.h
+new file mode 100644
+index 00000000..1505c106
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridSelArea.h
+@@ -0,0 +1,97 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CGRIDSELAREA_H
++#define CGRIDSELAREA_H
++
++#include "canvas/CCanvas.h"
++#include "ui_IGridSelArea.h"
++
++class CItemRefMap;
++class QSettings;
++class IDrawContext;
++
++
++class CGridSelArea : public QWidget, private Ui::IGridSelArea
++{
++ Q_OBJECT
++public:
++ CGridSelArea(QWidget * parent);
++ virtual ~CGridSelArea() = default;
++
++ void registerItem(CItemRefMap * item);
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw);
++ void mouseMoveEventFx(QMouseEvent *e);
++ void mouseReleaseEventFx(QMouseEvent *e);
++ void leaveEventFx(QEvent *e);
++ QCursor getCursorFx();
++
++ const QRectF& getArea() const
++ {
++ return area;
++ }
++
++public slots:
++ void slotSetArea(const QRectF& rect);
++ void slotReset();
++
++
++signals:
++ void sigChanged();
++
++private:
++ CItemRefMap * item = nullptr;
++ const IDrawContext * context = nullptr;
++
++ QRectF area;
++ QRectF areaSave;
++ QPointF offset;
++
++ QRectF rectTopLeft {0, 0, 20, 20};
++ QRectF rectTopRight {0, 0, 20, 20};
++ QRectF rectBottomLeft {0, 0, 20, 20};
++ QRectF rectBottomRight {0, 0, 20, 20};
++
++ enum state_e
++ {
++ eStateIdle
++ ,eStateMove
++ };
++
++ state_e state = eStateIdle;
++
++ enum corner_e
++ {
++ eCornerNone
++ , eCornerTopLeft
++ , eCornerTopRight
++ , eCornerBottomLeft
++ , eCornerBottomRight
++ , eCornerPrint
++ , eCornerImage
++ };
++
++ corner_e corner = eCornerNone;
++};
++
++#endif //CGRIDSELAREA_H
++
+diff --git a/src/qmaptool/overlay/gridtool/CGridSetRef.cpp b/src/qmaptool/overlay/gridtool/CGridSetRef.cpp
+new file mode 100644
+index 00000000..c027cf15
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridSetRef.cpp
+@@ -0,0 +1,105 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "overlay/gridtool/CGridSetRef.h"
++#include "overlay/refmap/CProjWizard.h"
++
++#include <QtWidgets>
++
++CGridSetRef::CGridSetRef(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++
++ connect(toolGridProj, &QToolButton::clicked, this, &CGridSetRef::slotSetupGridProj);
++ connect(lineEasting, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged);
++ connect(lineNorthing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged);
++ connect(lineHorizSpacing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged);
++ connect(lineVertSpacing, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged);
++ connect(lineGridProj, &QLineEdit::textChanged, this, &CGridSetRef::sigChanged);
++
++ labelHelp->setText(tr("Valid coordinate formats: If the projection is lat/lon all values have to be in degree, e.g. \"48.2\" or \"12.4\". "
++ "For all other projections values are either in multiple of meter or feet. If you are doing it wrong the entry field "
++ "will turn red."
++ ));
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++}
++
++void CGridSetRef::saveSettings(QSettings& cfg)
++{
++ cfg.setValue("proj", lineGridProj->text());
++ cfg.setValue("easting", lineEasting->text().toDouble());
++ cfg.setValue("northing", lineNorthing->text().toDouble());
++ cfg.setValue("horizSpacing", lineHorizSpacing->text().toDouble());
++ cfg.setValue("vertSpacing", lineVertSpacing->text().toDouble());
++}
++
++void CGridSetRef::loadSettings(QSettings& cfg)
++{
++ lineGridProj->setText(cfg.value("proj","").toString());
++ lineEasting->setText(cfg.value("easting","").toString());
++ lineNorthing->setText(cfg.value("northing","").toString());
++ lineHorizSpacing->setText(cfg.value("horizSpacing","").toString());
++ lineVertSpacing->setText(cfg.value("vertSpacing","").toString());
++ lineGridProj->setCursorPosition(0);
++}
++
++
++bool CGridSetRef::isOk()
++{
++ bool allOk = true;
++
++ bool ok = CProjWizard::validProjStr(lineGridProj->text());
++ markWidget(lineGridProj, ok);
++ allOk &= ok;
++
++ ok &= lineEasting->text().toDouble(&ok) != 0;
++ markWidget(lineEasting, ok);
++ allOk &= ok;
++
++ ok &= lineNorthing->text().toDouble(&ok) != 0;
++ markWidget(lineNorthing, ok);
++ allOk &= ok;
++
++ ok &= lineHorizSpacing->text().toDouble(&ok) != 0;
++ markWidget(lineHorizSpacing, ok);
++ allOk &= ok;
++
++ ok &= lineVertSpacing->text().toDouble(&ok) != 0;
++ markWidget(lineVertSpacing, ok);
++ allOk &= ok;
++
++ return allOk;
++}
++
++void CGridSetRef::slotSetupGridProj()
++{
++ CProjWizard dlg(*lineGridProj, this);
++ dlg.exec();
++ lineGridProj->setCursorPosition(0);
++}
++
++void CGridSetRef::slotReset()
++{
++ lineGridProj->clear();
++ lineEasting->clear();
++ lineNorthing->clear();
++ lineHorizSpacing->clear();
++ lineVertSpacing->clear();
++}
+diff --git a/src/qmaptool/overlay/gridtool/CGridSetRef.h b/src/qmaptool/overlay/gridtool/CGridSetRef.h
+new file mode 100644
+index 00000000..7956b0d3
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/CGridSetRef.h
+@@ -0,0 +1,86 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CGRIDSETREF_H
++#define CGRIDSETREF_H
++
++#include "ui_IGridSetRef.h"
++
++class QSettings;
++
++class CGridSetRef : public QWidget, private Ui::IGridSetRef
++{
++ Q_OBJECT
++public:
++ CGridSetRef(QWidget * parent);
++ virtual ~CGridSetRef() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++ bool isOk();
++
++ QString getProjection() const
++ {
++ return lineGridProj->text();
++ }
++
++ qreal getEasting() const
++ {
++ return lineEasting->text().toDouble();
++ }
++
++ qreal getNorthing() const
++ {
++ return lineNorthing->text().toDouble();
++ }
++
++ qreal getHorizSpacing() const
++ {
++ return lineHorizSpacing->text().toDouble();
++ }
++
++ qreal getVertSpacing() const
++ {
++ return lineVertSpacing->text().toDouble();
++ }
++
++signals:
++ void sigChanged();
++
++public slots:
++ void slotReset();
++
++private slots:
++ void slotSetupGridProj();
++
++private:
++ template<typename T>
++ void markWidget(T * w, bool isOk)
++ {
++ QPalette pal = T(this).palette();
++ if(!isOk)
++ {
++ pal.setColor(QPalette::Base, "#ffaa7f");
++ }
++ w->setPalette(pal);
++ }
++};
++
++#endif //CGRIDSETREF_H
++
+diff --git a/src/qmaptool/overlay/gridtool/IGridPlacer.ui b/src/qmaptool/overlay/gridtool/IGridPlacer.ui
+new file mode 100644
+index 00000000..833585ad
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/IGridPlacer.ui
+@@ -0,0 +1,248 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IGridPlacer</class>
++ <widget class="QWidget" name="IGridPlacer">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>254</width>
++ <height>224</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
++ <property name="spacing">
++ <number>0</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <layout class="QGridLayout" name="gridLayout">
++ <item row="1" column="1">
++ <widget class="QRadioButton" name="radioPoint1">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="1">
++ <widget class="QRadioButton" name="radioPoint4">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="2">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="../../resources.qrc">:/pic/line_3px_horizontal.png</pixmap>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="3">
++ <widget class="QRadioButton" name="radioPoint3">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="3">
++ <widget class="QLabel" name="label_3">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="../../resources.qrc">:/pic/line_3px_vertical.png</pixmap>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="3">
++ <widget class="QRadioButton" name="radioPoint2">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="1">
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="../../resources.qrc">:/pic/line_3px_vertical.png</pixmap>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="4">
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item row="2" column="2">
++ <widget class="QPushButton" name="pushReset">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Reset</string>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="2">
++ <widget class="QLabel" name="label_5">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="../../resources.qrc">:/pic/line_3px_horizontal.png</pixmap>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="5">
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <item>
++ <widget class="QLabel" name="labelStatusPoint1">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelStatusPoint2">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelStatusPoint3">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelStatusPoint4">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushSetArea">
++ <property name="text">
++ <string>Set Area</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item row="0" column="0" colspan="6">
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string/>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/gridtool/IGridSelArea.ui b/src/qmaptool/overlay/gridtool/IGridSelArea.ui
+new file mode 100644
+index 00000000..dd3f4a04
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/IGridSelArea.ui
+@@ -0,0 +1,49 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IGridSelArea</class>
++ <widget class="QWidget" name="IGridSelArea">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>300</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>0</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/gridtool/IGridSetRef.ui b/src/qmaptool/overlay/gridtool/IGridSetRef.ui
+new file mode 100644
+index 00000000..68fe4d31
+--- /dev/null
++++ b/src/qmaptool/overlay/gridtool/IGridSetRef.ui
+@@ -0,0 +1,117 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IGridSetRef</class>
++ <widget class="QWidget" name="IGridSetRef">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>133</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Grid Projection:</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QLineEdit" name="lineGridProj"/>
++ </item>
++ <item>
++ <widget class="QToolButton" name="toolGridProj">
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../resources.qrc">
++ <normaloff>:/icons/32x32/GridWizard.png</normaloff>:/icons/32x32/GridWizard.png</iconset>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>TextLabel</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QGridLayout" name="gridLayout">
++ <item row="0" column="0">
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>Easting</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="QLineEdit" name="lineEasting"/>
++ </item>
++ <item row="0" column="2">
++ <widget class="QLabel" name="label_3">
++ <property name="text">
++ <string>Horiz. Spacing</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="3">
++ <widget class="QLineEdit" name="lineHorizSpacing"/>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string>Northing</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QLineEdit" name="lineNorthing"/>
++ </item>
++ <item row="1" column="2">
++ <widget class="QLabel" name="labelVertSpacing">
++ <property name="text">
++ <string>Vert. Spacing</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="3">
++ <widget class="QLineEdit" name="lineVertSpacing"/>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp b/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp
+new file mode 100644
+index 00000000..895ef920
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/CDialogRefPoint.cpp
+@@ -0,0 +1,74 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "overlay/refmap/CDialogRefPoint.h"
++#include "units/IUnit.h"
++
++#include <QtWidgets>
++
++CDialogRefPoint::CDialogRefPoint(QPointF& ptPtx, QPointF& ptRef, QWidget *parent)
++ : QDialog(parent)
++ , ptPtx(ptPtx)
++ , ptRef(ptRef)
++{
++ setupUi(this);
++ connect(lineCoord, &QLineEdit::textEdited, this, &CDialogRefPoint::slotEditPosition);
++
++ lineX->setText(QString::number(qRound(ptPtx.x())));
++ lineY->setText(QString::number(qRound(ptPtx.y())));
++ if(ptRef != NOPOINTF)
++ {
++ QString str;
++ if(IUnit::degToStr(ptRef.x(), ptRef.y(), str))
++ {
++ str = tr("bad coordinate");
++ }
++ lineCoord->setText(str);
++ }
++
++ labelWarning->hide();
++}
++
++void CDialogRefPoint::slotEditPosition(const QString& str)
++{
++ labelWarning->setVisible(!IUnit::isValidCoordString(str));
++}
++
++void CDialogRefPoint::accept()
++{
++ bool ok;
++ ptPtx.setX(lineX->text().toInt(&ok));
++ if(!ok)
++ {
++ QMessageBox::warning(this, tr("Error"), tr("Bad value for X pixel."), QMessageBox::Ok);
++ return;
++ }
++ ptPtx.setY(lineY->text().toInt(&ok));
++ if(!ok)
++ {
++ QMessageBox::warning(this, tr("Error"), tr("Bad value for Y pixel."), QMessageBox::Ok);
++ return;
++ }
++
++ if(!IUnit::strToDeg(lineCoord->text(), ptRef.rx(), ptRef.ry()))
++ {
++ return;
++ }
++
++ QDialog::accept();
++}
+diff --git a/src/qmaptool/overlay/refmap/CDialogRefPoint.h b/src/qmaptool/overlay/refmap/CDialogRefPoint.h
+new file mode 100644
+index 00000000..67bc5df5
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/CDialogRefPoint.h
+@@ -0,0 +1,46 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CDIALOGREFPOINT_H
++#define CDIALOGREFPOINT_H
++
++#include "ui_IDialogRefPoint.h"
++#include <QDialog>
++
++class QPointF;
++
++class CDialogRefPoint : public QDialog, private Ui::IDialogRefPoint
++{
++ Q_OBJECT
++public:
++ CDialogRefPoint(QPointF& ptPtx, QPointF& ptRef, QWidget * parent);
++ virtual ~CDialogRefPoint() = default;
++
++public slots:
++ void accept() override;
++
++private slots:
++ void slotEditPosition(const QString& str);
++
++private:
++ QPointF& ptPtx;
++ QPointF& ptRef;
++};
++
++#endif //CDIALOGREFPOINT_H
++
+diff --git a/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp
+new file mode 100644
+index 00000000..eae52331
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.cpp
+@@ -0,0 +1,52 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "overlay/refmap/COverlayRefMapPoint.h"
++#include "units/IUnit.h"
++
++COverlayRefMapPoint::COverlayRefMapPoint(qint32 cnt, const QPointF &ptRef, const QPointF &ptPtx, QTreeWidget *parent)
++ : QTreeWidgetItem(parent)
++{
++ setText(eColumnCnt, QString::number(cnt));
++ setPtPtx(ptPtx);
++ setPtRef(ptRef);
++}
++
++void COverlayRefMapPoint::setPtPtx(const QPointF& pt)
++{
++ ptPtx.rx() = qRound(pt.x());
++ ptPtx.ry() = qRound(pt.y());
++ setText(eColumnXY, QString("%1, %2").arg(ptPtx.x()).arg(ptPtx.y()));
++}
++
++void COverlayRefMapPoint::setPtRef(const QPointF& pt)
++{
++ ptRef = pt;
++ QString str;
++ if(!IUnit::self().degToStr(ptRef.x(), ptRef.y(), str))
++ {
++ str = tr("bad coordinate");
++ }
++ setText(eColumnLonLat, str);
++}
++
++void COverlayRefMapPoint::setIndex(int n)
++{
++ setText(eColumnCnt, QString::number(n));
++}
++
+diff --git a/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h
+new file mode 100644
+index 00000000..53bced7c
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/COverlayRefMapPoint.h
+@@ -0,0 +1,67 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef COVERLAYREFMAPPOINT_H
++#define COVERLAYREFMAPPOINT_H
++
++#include <QCoreApplication>
++#include <QTreeWidgetItem>
++
++class COverlayRefMapPoint : public QTreeWidgetItem
++{
++ Q_DECLARE_TR_FUNCTIONS(COverlayRefMapPoint)
++public:
++ COverlayRefMapPoint(qint32 cnt, const QPointF& ptRef, const QPointF& ptPtx, QTreeWidget * parent);
++ virtual ~COverlayRefMapPoint() = default;
++
++ enum column_e
++ {
++ eColumnCnt
++ , eColumnXY
++ , eColumnLonLat
++ };
++
++ void setPtPtx(const QPointF& pt);
++ void setPtRef(const QPointF& pt);
++ void setIndex(int n);
++
++ const QPointF& getPtPtx() const
++ {
++ return ptPtx;
++ }
++
++ const QPointF& getPtRef() const
++ {
++ return ptRef;
++ }
++
++ bool operator<(const QTreeWidgetItem& p) const override
++ {
++ const COverlayRefMapPoint& pt = dynamic_cast<const COverlayRefMapPoint&>(p);
++ qreal v1 = ptPtx.y() * 1000000000 + ptPtx.x();
++ qreal v2 = pt.ptPtx.y() * 1000000000 + pt.ptPtx.x();
++ return v1 < v2;
++ }
++
++private:
++ QPointF ptRef;
++ QPointF ptPtx;
++};
++
++#endif //COVERLAYREFMAPPOINT_H
++
+diff --git a/src/qmaptool/overlay/refmap/CProjWizard.cpp b/src/qmaptool/overlay/refmap/CProjWizard.cpp
+new file mode 100644
+index 00000000..2f325932
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/CProjWizard.cpp
+@@ -0,0 +1,237 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "helpers/mitab.h"
++#include "overlay/refmap/CProjWizard.h"
++
++#include <proj_api.h>
++#include <QtWidgets>
++
++struct mitab_entry_t
++{
++ QString name;
++ int idx;
++};
++
++static bool mitabLessThan(const mitab_entry_t &s1, const mitab_entry_t &s2)
++{
++ return s1.name < s2.name;
++}
++
++CProjWizard::CProjWizard(QLineEdit &line, QWidget * parent)
++ : QDialog(parent)
++ , line(line)
++{
++ setupUi(this);
++ QList<mitab_entry_t> list;
++ int idx = 0;
++ const MapInfoDatumInfo * di = asDatumInfoListQL;
++
++ while(di->nMapInfoDatumID != -1)
++ {
++ mitab_entry_t entry;
++ entry.name = di->pszOGCDatumName;
++ entry.idx = idx;
++ list << entry;
++ ++di;
++ ++idx;
++ }
++ qSort(list.begin(), list.end(), mitabLessThan);
++
++ for(const mitab_entry_t &entry : list)
++ {
++ comboDatum->addItem(entry.name, entry.idx);
++ }
++
++ comboHemisphere->addItem(tr("north"), "");
++ comboHemisphere->addItem(tr("south"), "+south");
++
++ connect(radioMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(radioWorldMercator, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(radioUPSNorth, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(radioUPSSouth, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(radioUTM, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(radioUserDef, &QRadioButton::clicked, this, &CProjWizard::slotChange);
++ connect(lineUserDef, &QLineEdit::textChanged, this, &CProjWizard::slotChange);
++
++ connect(spinUTMZone, static_cast<void (QSpinBox::*)(int) >(&QSpinBox::valueChanged), this, &CProjWizard::slotChange);
++ connect(comboDatum, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange);
++ connect(comboHemisphere, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CProjWizard::slotChange);
++
++ QString projstr = line.text();
++ QRegExp re2("\\s*\\+proj=merc \\+a=6378137 \\+b=6378137 \\+lat_ts=0.001 \\+lon_0=0.0 \\+x_0=0.0 \\+y_0=0 \\+k=1.0 \\+units=m \\+nadgrids=@null \\+no_defs");
++ QRegExp re3("\\s*\\+proj=merc\\s(.*)");
++ QRegExp re4("\\s*\\+proj=utm \\+zone=([0-9]+)\\s(.*)");
++
++ if(re2.exactMatch(projstr))
++ {
++ radioWorldMercator->setChecked(true);
++ }
++ else if(re3.exactMatch(projstr))
++ {
++ radioMercator->setChecked(true);
++ findDatum(re3.cap(1));
++ }
++ else if(re4.exactMatch(projstr))
++ {
++ radioUTM->setChecked(true);
++ spinUTMZone->setValue(re4.cap(1).toInt());
++
++ QString datum = re4.cap(2);
++ if(datum.startsWith("+south "))
++ {
++ datum = datum.mid(7);
++ comboHemisphere->setCurrentIndex(1);
++ }
++
++ findDatum(datum);
++ }
++
++ slotChange();
++}
++
++CProjWizard::~CProjWizard()
++{
++}
++
++
++void CProjWizard::findDatum(const QString& str)
++{
++ QString cmp;
++ int idx = 0;
++ const MapInfoDatumInfo * di = asDatumInfoListQL;
++
++ while(di->nMapInfoDatumID != -1)
++ {
++ cmp.clear();
++ if(di->pszOGCDatumName != QString())
++ {
++ const MapInfoSpheroidInfo * si = asSpheroidInfoList;
++ while(si->nMapInfoId != -1)
++ {
++ if(si->nMapInfoId == di->nEllipsoid)
++ {
++ break;
++ }
++ ++si;
++ }
++
++ cmp += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4);
++ cmp += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di->dfShiftX).arg(di->dfShiftY).arg(di->dfShiftZ).arg(di->dfDatumParm0).arg(di->dfDatumParm1).arg(di->dfDatumParm2).arg(di->dfDatumParm3).arg(di->dfDatumParm4);
++ cmp += "+units=m +no_defs";
++ }
++
++ if(cmp == str)
++ {
++ comboDatum->setCurrentIndex(comboDatum->findText(di->pszOGCDatumName));
++ break;
++ }
++
++ ++di;
++ ++idx;
++ }
++}
++
++
++void CProjWizard::slotChange()
++{
++ QString str;
++ if(radioMercator->isChecked())
++ {
++ str += "+proj=merc ";
++ }
++ else if(radioWorldMercator->isChecked())
++ {
++ str += "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.001 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
++ labelResult->setText(str);
++ return;
++ }
++ else if(radioUPSNorth->isChecked())
++ {
++ str += "+init=epsg:32661";
++ }
++ else if(radioUPSSouth->isChecked())
++ {
++ str += "+init=epsg:32761";
++ }
++ else if(radioUTM->isChecked())
++ {
++ str += QString("+proj=utm +zone=%1 %2 ").arg(spinUTMZone->value()).arg(comboHemisphere->itemData(comboHemisphere->currentIndex()).toString());
++ }
++ else if(radioUserDef->isChecked())
++ {
++ str += lineUserDef->text() + " ";
++ }
++
++ int idx = comboDatum->itemData(comboDatum->currentIndex()).toInt();
++ const MapInfoDatumInfo di = asDatumInfoListQL[idx];
++ if(di.pszOGCDatumName != QString())
++ {
++ const MapInfoSpheroidInfo * si = asSpheroidInfoList;
++ while(si->nMapInfoId != -1)
++ {
++ if(si->nMapInfoId == di.nEllipsoid)
++ {
++ break;
++ }
++ ++si;
++ }
++
++ str += QString("+a=%1 +b=%2 ").arg(si->dfA,0,'f',4).arg(si->dfA * (1.0 - (1.0/si->dfInvFlattening)),0,'f',4);
++ str += QString("+towgs84=%1,%2,%3,%4,%5,%6,%7,%8 ").arg(di.dfShiftX).arg(di.dfShiftY).arg(di.dfShiftZ).arg(di.dfDatumParm0).arg(di.dfDatumParm1).arg(di.dfDatumParm2).arg(di.dfDatumParm3).arg(di.dfDatumParm4);
++ str += "+units=m +no_defs";
++ }
++
++ labelResult->setText(str);
++}
++
++
++void CProjWizard::accept()
++{
++ if (CProjWizard::validProjStr(labelResult->text()))
++ {
++ line.setText(labelResult->text());
++ line.setCursorPosition(0);
++ QDialog::accept();
++ }
++}
++
++
++bool CProjWizard::validProjStr(const QString projStr)
++{
++ if(projStr.isEmpty())
++ {
++ return false;
++ }
++
++ projPJ projCheck = pj_init_plus(projStr.toUtf8().data());
++
++ if (!projCheck)
++ { /* For some reason pj_errno does not work as expected in some versions of Visual Studio, so using pj_get_errno_ref instead */
++ QMessageBox::warning(&CMainWindow::self(), tr("Error..."),tr("The value\n'%1'\nis not a valid coordinate system definition:\n%2").arg(projStr).arg(pj_strerrno(*pj_get_errno_ref())),QMessageBox::Abort,QMessageBox::Abort);
++ return false;
++ }
++ else
++ {
++ pj_free(projCheck);
++ return true;
++ }
++}
++
++
+diff --git a/src/qmaptool/overlay/refmap/CProjWizard.h b/src/qmaptool/overlay/refmap/CProjWizard.h
+new file mode 100644
+index 00000000..5cd1f38f
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/CProjWizard.h
+@@ -0,0 +1,44 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CPROJWIZARD_H
++#define CPROJWIZARD_H
++
++#include "ui_IProjWizard.h"
++#include <QDialog>
++
++class CProjWizard : public QDialog, private Ui::IProjWizard
++{
++ Q_OBJECT
++public:
++ CProjWizard(QLineEdit& line, QWidget *parent);
++ virtual ~CProjWizard();
++ static bool validProjStr(const QString projStr);
++
++public slots:
++ void accept() override;
++ void slotChange();
++
++private:
++ void findDatum(const QString& str);
++
++ QLineEdit& line;
++};
++
++#endif //CPROJWIZARD_H
++
+diff --git a/src/qmaptool/overlay/refmap/IDialogRefPoint.ui b/src/qmaptool/overlay/refmap/IDialogRefPoint.ui
+new file mode 100644
+index 00000000..7e1ecd4e
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/IDialogRefPoint.ui
+@@ -0,0 +1,131 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IDialogRefPoint</class>
++ <widget class="QDialog" name="IDialogRefPoint">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>510</width>
++ <height>191</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Dialog</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QGridLayout" name="gridLayout">
++ <item row="1" column="2" colspan="3">
++ <widget class="QLineEdit" name="lineCoord"/>
++ </item>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Coord. Map File [pixel]</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string>x</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="2">
++ <widget class="QLineEdit" name="lineX"/>
++ </item>
++ <item row="0" column="3">
++ <widget class="QLabel" name="label_5">
++ <property name="text">
++ <string>y</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>Coord. lat/lon WGS84 [°]</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="4">
++ <widget class="QLineEdit" name="lineY"/>
++ </item>
++ <item row="2" column="2" colspan="3">
++ <widget class="QLabel" name="labelWarning">
++ <property name="text">
++ <string>Bad position format. Must be:
++&quot;[N|S] ddd mm.sss [W|E] ddd mm.sss&quot;
++or
++&quot;[N|S] ddd.ddd [W|E] ddd.ddd&quot;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>IDialogRefPoint</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>IDialogRefPoint</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++</ui>
+diff --git a/src/qmaptool/overlay/refmap/IProjWizard.ui b/src/qmaptool/overlay/refmap/IProjWizard.ui
+new file mode 100644
+index 00000000..3f78eec9
+--- /dev/null
++++ b/src/qmaptool/overlay/refmap/IProjWizard.ui
+@@ -0,0 +1,210 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IProjWizard</class>
++ <widget class="QDialog" name="IProjWizard">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>440</width>
++ <height>280</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Proj4 Wizard</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="frameShape">
++ <enum>QFrame::StyledPanel</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Raised</enum>
++ </property>
++ <layout class="QGridLayout">
++ <item row="1" column="1">
++ <widget class="QRadioButton" name="radioMercator">
++ <property name="text">
++ <string>Mercator</string>
++ </property>
++ </widget>
++ </item>
++ <item row="5" column="1">
++ <layout class="QHBoxLayout">
++ <item>
++ <widget class="QRadioButton" name="radioUTM">
++ <property name="text">
++ <string>UTM</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_3">
++ <property name="text">
++ <string>zone</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QSpinBox" name="spinUTMZone">
++ <property name="minimum">
++ <number>1</number>
++ </property>
++ <property name="maximum">
++ <number>60</number>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QComboBox" name="comboHemisphere"/>
++ </item>
++ <item>
++ <spacer>
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item row="6" column="1">
++ <layout class="QHBoxLayout">
++ <item>
++ <widget class="QRadioButton" name="radioUserDef">
++ <property name="text">
++ <string>user defined</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineUserDef"/>
++ </item>
++ </layout>
++ </item>
++ <item row="7" column="0">
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>Datum</string>
++ </property>
++ </widget>
++ </item>
++ <item row="7" column="1">
++ <widget class="QComboBox" name="comboDatum"/>
++ </item>
++ <item row="2" column="1">
++ <widget class="QRadioButton" name="radioWorldMercator">
++ <property name="text">
++ <string>World Mercator (OSM)</string>
++ </property>
++ </widget>
++ </item>
++ <item row="8" column="1">
++ <spacer>
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item row="9" column="0">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string>Result:</string>
++ </property>
++ </widget>
++ </item>
++ <item row="9" column="1">
++ <widget class="QLabel" name="labelResult">
++ <property name="text">
++ <string/>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="1">
++ <widget class="QRadioButton" name="radioUPSNorth">
++ <property name="text">
++ <string>UPS North (North Pole)</string>
++ </property>
++ </widget>
++ </item>
++ <item row="4" column="1">
++ <widget class="QRadioButton" name="radioUPSSouth">
++ <property name="text">
++ <string>UPS South (South Pole)</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Projection</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>IProjWizard</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>IProjWizard</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++</ui>
+diff --git a/src/qmaptool/resources.qrc b/src/qmaptool/resources.qrc
+new file mode 100644
+index 00000000..9dc34535
+--- /dev/null
++++ b/src/qmaptool/resources.qrc
+@@ -0,0 +1,93 @@
++<RCC>
++ <qresource prefix="/">
++ <file>../animation/loader.gif</file>
++
++ <file>../cursors/cursorPointAdd.png</file>
++ <file>../cursors/cursorPointDel.png</file>
++ <file>../cursors/cursorPointMove.png</file>
++
++ <file>../icons/32x32/AddOverview.png</file>
++ <file>../icons/32x32/Add.png</file>
++ <file>../icons/32x32/Apply.png</file>
++ <file>../icons/32x32/Cancel.png</file>
++ <file>../icons/32x32/Check.png</file>
++ <file>../icons/32x32/CombineMap.png</file>
++ <file>../icons/32x32/CutMap.png</file>
++ <file>../icons/32x32/DeleteMultiple.png</file>
++ <file>../icons/32x32/DeleteOne.png</file>
++ <file>../icons/32x32/Export.png</file>
++ <file>../icons/32x32/FolderMap.png</file>
++ <file>../icons/32x32/GridTool.png</file>
++ <file>../icons/32x32/GridWizard.png</file>
++ <file>../icons/32x32/Info.png</file>
++ <file>../icons/32x32/LoadGcp.png</file>
++ <file>../icons/32x32/LoadShape.png</file>
++ <file>../icons/32x32/MapLayer.png</file>
++ <file>../icons/32x32/MouseWheel.png</file>
++ <file>../icons/32x32/MoveArrow.png</file>
++ <file>../icons/32x32/PathBlue.png</file>
++ <file>../icons/32x32/PointAdd.png</file>
++ <file>../icons/32x32/PointDelAll.png</file>
++ <file>../icons/32x32/PointDel.png</file>
++ <file>../icons/32x32/PointMove.png</file>
++ <file>../icons/32x32/QMapTool.png</file>
++ <file>../icons/32x32/Rasterize.png</file>
++ <file>../icons/32x32/RefAdd.png</file>
++ <file>../icons/32x32/RefDelAll.png</file>
++ <file>../icons/32x32/RefDel.png</file>
++ <file>../icons/32x32/ReferenceMap.png</file>
++ <file>../icons/32x32/RefMoveAuto.png</file>
++ <file>../icons/32x32/RefMove.png</file>
++ <file>../icons/32x32/Reload.png</file>
++ <file>../icons/32x32/Reset.png</file>
++ <file>../icons/32x32/SaveGcp.png</file>
++ <file>../icons/32x32/SaveShape.png</file>
++ <file>../icons/32x32/SetupCoordFormat.png</file>
++ <file>../icons/32x32/Sort.png</file>
++ <file>../icons/32x32/UnitSetup.png</file>
++
++ <file>../icons/48x48/AddOverview.png</file>
++ <file>../icons/48x48/Add.png</file>
++ <file>../icons/48x48/Apply.png</file>
++ <file>../icons/48x48/Cancel.png</file>
++ <file>../icons/48x48/Check.png</file>
++ <file>../icons/48x48/CombineMap.png</file>
++ <file>../icons/48x48/CutMap.png</file>
++ <file>../icons/48x48/DeleteMultiple.png</file>
++ <file>../icons/48x48/DeleteOne.png</file>
++ <file>../icons/48x48/Export.png</file>
++ <file>../icons/48x48/FolderMap.png</file>
++ <file>../icons/48x48/GridTool.png</file>
++ <file>../icons/48x48/GridWizard.png</file>
++ <file>../icons/48x48/Info.png</file>
++ <file>../icons/48x48/LoadGcp.png</file>
++ <file>../icons/48x48/LoadShape.png</file>
++ <file>../icons/48x48/MapLayer.png</file>
++ <file>../icons/48x48/MouseWheel.png</file>
++ <file>../icons/48x48/MoveArrow.png</file>
++ <file>../icons/48x48/PathBlue.png</file>
++ <file>../icons/48x48/PointAdd.png</file>
++ <file>../icons/48x48/PointDelAll.png</file>
++ <file>../icons/48x48/PointDel.png</file>
++ <file>../icons/48x48/PointMove.png</file>
++ <file>../icons/48x48/QMapTool.png</file>
++ <file>../icons/48x48/Rasterize.png</file>
++ <file>../icons/48x48/RefAdd.png</file>
++ <file>../icons/48x48/RefDelAll.png</file>
++ <file>../icons/48x48/RefDel.png</file>
++ <file>../icons/48x48/ReferenceMap.png</file>
++ <file>../icons/48x48/RefMoveAuto.png</file>
++ <file>../icons/48x48/RefMove.png</file>
++ <file>../icons/48x48/Reload.png</file>
++ <file>../icons/48x48/Reset.png</file>
++ <file>../icons/48x48/SaveGcp.png</file>
++ <file>../icons/48x48/SaveShape.png</file>
++ <file>../icons/48x48/SetupCoordFormat.png</file>
++ <file>../icons/48x48/Sort.png</file>
++ <file>../icons/48x48/UnitSetup.png</file>
++
++ <file>pic/line_3px_horizontal.png</file>
++ <file>pic/line_3px_vertical.png</file>
++ <file>pic/splash.png</file>
++ </qresource>
++</RCC>
+diff --git a/src/qmaptool/setup/CAppOpts.h b/src/qmaptool/setup/CAppOpts.h
+new file mode 100644
+index 00000000..88992b17
+--- /dev/null
++++ b/src/qmaptool/setup/CAppOpts.h
+@@ -0,0 +1,47 @@
++/**********************************************************************************************
++ Copyright (C) 2009 Joerg Wunsch <j@uriah.heep.sax.de>
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#ifndef CAPPOPTS_H
++#define CAPPOPTS_H
++/*
++ * This class holds the options passed from the command-line,
++ * including the positional arguments.
++ */
++
++#include <QStringList>
++
++class CAppOpts
++{
++public:
++ const bool debug; // -d, print debug messages
++ const bool logfile; // -f, print debug messages to logfile
++ const bool nosplash; // -n, do not display splash screen
++ const QString configfile;
++ const QStringList arguments;
++
++ CAppOpts(bool doDebug, bool doLogfile, bool noSplash, const QString& config, const QStringList& args)
++ : debug(doDebug)
++ , logfile(doLogfile)
++ , nosplash(noSplash)
++ , configfile(config)
++ , arguments(args)
++ {
++ }
++};
++
++extern CAppOpts *qlOpts;
++#endif //CAPPOPTS_H
+diff --git a/src/qmaptool/setup/CAppSetupLinux.cpp b/src/qmaptool/setup/CAppSetupLinux.cpp
+new file mode 100644
+index 00000000..e2d012d8
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupLinux.cpp
+@@ -0,0 +1,62 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "config.h"
++#include "setup/CAppSetupLinux.h"
++
++#ifndef _MKSTR_1
++#define _MKSTR_1(x) #x
++#define _MKSTR(x) _MKSTR_1(x)
++#endif
++
++void CAppSetupLinux::initQMapTool()
++{
++ prepareGdal("", "");
++
++ // setup translators
++ QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
++ QString translationPath = QCoreApplication::applicationDirPath();
++ translationPath.replace(QRegExp("bin$"), "share/qmaptool/translations");
++ prepareTranslator(resourceDir, "qt_");
++ prepareTranslator(translationPath, "qmaptool_");
++
++ // create directories
++ IAppSetup::path(logDir(), 0, true, "LOG");
++
++ prepareToolPaths();
++}
++
++
++
++QString CAppSetupLinux::defaultCachePath()
++{
++ return IAppSetup::path(QDir::home().absolutePath(), ".QMapTool/", false, 0);
++}
++
++
++QString CAppSetupLinux::userDataPath(QString subdir)
++{
++ QString path = QDir::home().absoluteFilePath(CONFIGDIR);
++ return IAppSetup::path(path, subdir, false, 0);
++}
++
++
++QString CAppSetupLinux::logDir()
++{
++ return QDir::temp().absolutePath();
++}
+diff --git a/src/qmaptool/setup/CAppSetupLinux.h b/src/qmaptool/setup/CAppSetupLinux.h
+new file mode 100644
+index 00000000..a0d26b45
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupLinux.h
+@@ -0,0 +1,44 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CAPPSETUPLINUX_H
++#define CAPPSETUPLINUX_H
++
++#include "setup/IAppSetup.h"
++
++#include <QtCore>
++
++class CAppSetupLinux : public IAppSetup
++{
++public:
++ CAppSetupLinux(QObject * parent)
++ : IAppSetup(parent)
++ {
++ }
++
++ ~CAppSetupLinux() = default;
++ void initQMapTool() override;
++
++ QString defaultCachePath() override;
++ QString userDataPath(QString subdir = 0) override;
++ QString logDir() override;
++ QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); }
++};
++
++
++#endif // CAPPSETUPLINUX_H
+diff --git a/src/qmaptool/setup/CAppSetupMac.cpp b/src/qmaptool/setup/CAppSetupMac.cpp
+new file mode 100644
+index 00000000..8d7ab0a2
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupMac.cpp
+@@ -0,0 +1,140 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "setup/CAppSetupMac.h"
++
++static QString relTranslationDir = "Resources/translations"; // app
++static QString relGdalDir = "Resources/gdal"; // app
++static QString relProjDir = "Resources/proj"; // app
++static QString relBinDir = "Tools"; // app
++
++static QString relLogDir = "Library/Logs"; // home
++
++
++void CAppSetupMac::extendPath()
++{
++ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
++ QStringList envlist = env.toStringList();
++ QString value = "";
++ for(int i=0; i < envlist.size(); i++)
++ {
++ QString entry = envlist[i];
++ if(entry.startsWith("PATH="))
++ {
++ int index = entry.indexOf("=");
++
++ if(index != -1)
++ {
++ value = entry.right(entry.length() - (index+1)) + ":";
++ }
++ break;
++ }
++ }
++ QString binDir = getApplicationDir(relBinDir).absolutePath();
++ qDebug() << "BIN" << binDir;
++ value += binDir;
++ qputenv("PATH", value.toLatin1().constData());
++
++ prepareToolPaths();
++}
++
++
++void CAppSetupMac::initQMapTool()
++{
++ extendPath();
++ // setup gdal
++ QString gdalDir = getApplicationDir(relGdalDir).absolutePath();
++ QString projDir = getApplicationDir(relProjDir).absolutePath();
++ prepareGdal(gdalDir, projDir);
++
++ // setup translators
++ QString translationPath = getApplicationDir(relTranslationDir).absolutePath();
++ prepareTranslator(translationPath, "qt_");
++ prepareTranslator(translationPath, "qmaptool_");
++
++ migrateDirContent(defaultCachePath());
++ migrateDirContent(userDataPath());
++
++ // create directories
++ IAppSetup::path(logDir(), 0, false, "LOG");
++}
++
++
++QString CAppSetupMac::defaultCachePath()
++{
++ QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first();
++ return IAppSetup::path(cachePath, 0, false, 0);
++}
++
++
++QString CAppSetupMac::userDataPath(QString subdir)
++{
++#if QT_VERSION >= 0x050400
++ QString dataDir = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation).first();
++#else
++ QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first();
++#endif
++ return IAppSetup::path(dataDir, subdir, false, 0);
++}
++
++
++QString CAppSetupMac::logDir()
++{
++ // home location returns / (root) instead of user home...
++ QString home = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first();
++ QDir dir = QDir(home);
++ dir.cdUp();
++ return IAppSetup::path(dir.absolutePath(), relLogDir, false, 0);
++}
++
++
++QDir CAppSetupMac::getApplicationDir(QString subdir)
++{
++ QDir appDir(QCoreApplication::applicationDirPath());
++ appDir.cdUp();
++ appDir.cd(subdir);
++ return appDir;
++}
++
++
++void CAppSetupMac::migrateDirContent(QString dest)
++{
++ QString src = dest;
++ src.replace("/QLandkarte/", "/");
++ QDir dirDest = QDir(dest);
++ QDir dirSource = QDir(src);
++
++ if (!dirDest.exists() && dirSource.exists())
++ {
++ qDebug() << "src directory for migration" << src;
++ qDebug() << "dst directory for migration" << dest;
++
++ QDir wdir;
++ QString newdir = dest;
++ newdir.remove("/QMapTool");
++ wdir.mkdir(newdir);
++ qDebug() << "directory created" << newdir;
++
++ qDebug() << "migrate data from "<<dirSource.absolutePath() << "to" << dirDest.absolutePath();
++ QDir mvDir;
++ if(!mvDir.rename(dirSource.absolutePath(), dirDest.absolutePath()))
++ {
++ qDebug() << "error migrating directory" << dirSource;
++ }
++ }
++}
+diff --git a/src/qmaptool/setup/CAppSetupMac.h b/src/qmaptool/setup/CAppSetupMac.h
+new file mode 100644
+index 00000000..6afbb8f7
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupMac.h
+@@ -0,0 +1,49 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CAPPSETUPMAC_H
++#define CAPPSETUPMAC_H
++
++#include "setup/IAppSetup.h"
++
++#include <QtCore>
++
++
++class CAppSetupMac : public IAppSetup
++{
++public:
++ CAppSetupMac(QObject * parent)
++ : IAppSetup(parent)
++ {
++ }
++
++ ~CAppSetupMac() = default;
++ void initQMapTool() override;
++
++ QString defaultCachePath() override;
++ QString userDataPath(QString subdir = 0) override;
++ QString logDir() override;
++ QString findExecutable(const QString &name) override { return QStandardPaths::findExecutable(name); }
++
++private:
++ QDir getApplicationDir(QString subdir);
++ void migrateDirContent(QString dest);
++ void extendPath();
++};
++
++#endif // CAPPSETUPMAC_H
+diff --git a/src/qmaptool/setup/CAppSetupWin.cpp b/src/qmaptool/setup/CAppSetupWin.cpp
+new file mode 100644
+index 00000000..ede10da7
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupWin.cpp
+@@ -0,0 +1,69 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "config.h"
++#include "setup/CAppSetupWin.h"
++
++
++void CAppSetupWin::initQMapTool()
++{
++ // setup environment variables for GDAL/Proj4
++ QString apppath = QCoreApplication::applicationDirPath();
++ apppath = apppath.replace("/", "\\");
++ QString gdalDir = QString("%1\\data").arg(apppath);
++ QString projDir = QString("%1\\share\\proj").arg(apppath);
++
++ qunsetenv("GDAL_DRIVER_PATH");
++ prepareGdal(gdalDir, projDir);
++
++ QString appResourceDir = QString("%1\\translations").arg(apppath).toUtf8();
++ prepareTranslator(appResourceDir, "qtbase_");
++ prepareTranslator(appResourceDir, "qmaptool_");
++
++ // limit PATH to application directory in order to avoid that wrong .dll's are loaded
++ path = apppath.toUtf8();
++ qputenv("PATH", path);
++
++ // create directories
++ IAppSetup::path(logDir(), 0, true, "LOG");
++
++ prepareToolPaths();
++}
++
++QString CAppSetupWin::defaultCachePath()
++{
++ return IAppSetup::path(QDir::home().absolutePath(), ".QMapTool/", false, 0);
++}
++
++
++QString CAppSetupWin::userDataPath(QString subdir)
++{
++ QString path = QDir::home().absoluteFilePath(CONFIGDIR);
++ return IAppSetup::path(path, subdir, false, 0);
++}
++
++
++QString CAppSetupWin::logDir()
++{
++ return QDir::temp().absolutePath();
++}
++
++QString CAppSetupWin::findExecutable(const QString &name)
++{
++ return QStandardPaths::findExecutable(name);
++}
+diff --git a/src/qmaptool/setup/CAppSetupWin.h b/src/qmaptool/setup/CAppSetupWin.h
+new file mode 100644
+index 00000000..4ef0043e
+--- /dev/null
++++ b/src/qmaptool/setup/CAppSetupWin.h
+@@ -0,0 +1,45 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CAPPSETUPWIN_H
++#define CAPPSETUPWIN_H
++
++#include "setup/IAppSetup.h"
++
++#include <QtCore>
++
++class CAppSetupWin : public IAppSetup
++{
++public:
++ CAppSetupWin(QObject * parent)
++ : IAppSetup(parent)
++ {
++ }
++
++ ~CAppSetupWin() = default;
++ void initQMapTool() override;
++
++ QString defaultCachePath() override;
++ QString userDataPath(QString subdir = 0) override;
++ QString logDir() override;
++ QString findExecutable(const QString &name) override;
++
++ QByteArray path;
++};
++
++#endif // CAPPSETUPWIN_H
+diff --git a/src/qmaptool/setup/CCommandProcessor.cpp b/src/qmaptool/setup/CCommandProcessor.cpp
+new file mode 100644
+index 00000000..b0cf6519
+--- /dev/null
++++ b/src/qmaptool/setup/CCommandProcessor.cpp
+@@ -0,0 +1,58 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "setup/CCommandProcessor.h"
++
++#include <iostream>
++#include <QApplication>
++#include <QCommandLineParser>
++
++
++CAppOpts* CCommandProcessor::processOptions(const QStringList &arguments)
++{
++ QCommandLineParser parser;
++ QCommandLineOption helpOption = parser.addHelpOption(); // h help
++
++ QCommandLineOption debugOption(QStringList() << "d" << "debug", tr("Print debug output to console."));
++ parser.addOption(debugOption);
++
++ QCommandLineOption logfileOption(QStringList() << "f" << "logfile", tr("Print debug output to logfile (temp. path)."));
++ parser.addOption(logfileOption);
++
++ QCommandLineOption nosplashOption(QStringList() << "n" << "no-splash", tr("Do not show splash screen."));
++ parser.addOption(nosplashOption);
++
++ QCommandLineOption configOption(QStringList() << "c" << "config", tr("File with QMapTool configuration."), tr("file"));
++ parser.addOption(configOption);
++
++ //parser.addPositionalArgument("files", tr("Files for future use."));
++
++ if (!parser.parse(arguments))
++ {
++ std::cerr << parser.errorText().toUtf8().constData();
++ std::cerr << parser.helpText().toUtf8().constData();
++ exit(1);
++ }
++ if (parser.isSet(helpOption))
++ {
++ std::cout << parser.helpText().toUtf8().constData();
++ exit(0);
++ }
++
++ return new CAppOpts(parser.isSet(debugOption), parser.isSet(logfileOption), parser.isSet(nosplashOption), parser.value(configOption), parser.positionalArguments());
++}
+diff --git a/src/qmaptool/setup/CCommandProcessor.h b/src/qmaptool/setup/CCommandProcessor.h
+new file mode 100644
+index 00000000..55a41e8f
+--- /dev/null
++++ b/src/qmaptool/setup/CCommandProcessor.h
+@@ -0,0 +1,33 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CCOMMANDPROCESSOR_H
++#define CCOMMANDPROCESSOR_H
++
++#include "setup/CAppOpts.h"
++#include <QCoreApplication>
++
++class CCommandProcessor
++{
++ Q_DECLARE_TR_FUNCTIONS(CCommandProcessor)
++public:
++ CAppOpts* processOptions(const QStringList &arguments);
++};
++
++
++#endif // CCOMMANDPROCESSOR_H
+diff --git a/src/qmaptool/setup/CLogHandler.cpp b/src/qmaptool/setup/CLogHandler.cpp
+new file mode 100644
+index 00000000..41b87cc2
+--- /dev/null
++++ b/src/qmaptool/setup/CLogHandler.cpp
+@@ -0,0 +1,122 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "setup/CLogHandler.h"
++#include <iostream>
++
++
++CLogHandler::CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput) :
++ writeToFile(writeToFile), debugOutput(debugOutput), logFile(QDir(logDirectory).absoluteFilePath(logfileName())),
++ fileStream(&logFile)
++{
++ if (writeToFile)
++ {
++ fileStream.setCodec("UTF-8");
++ logFile.open(QIODevice::WriteOnly | QIODevice::Append);
++ }
++ qSetMessagePattern("%{time yyyy-MM-dd h:mm:ss.zzz} [%{type}] %{message}");
++}
++
++void CLogHandler::log(QtMsgType type, const QMessageLogContext &context, const QString &msg)
++{
++#if QT_VERSION >= 0x050400
++ QString txt = qFormatLogMessage(type, context, msg);
++#else
++ QString txt = msg;
++#endif
++ printToConsole(type, txt);
++ appendToFile(type, txt);
++}
++
++void CLogHandler::printLoggerInfo()
++{
++ qDebug() << "Log configuration:" << "log file=" << logFile.fileName() << "write to file=" << writeToFile <<
++ "debug output=" << debugOutput;
++}
++
++QString CLogHandler::logfileName()
++{
++ QStringList domainSplit = QCoreApplication::organizationDomain().split(".");
++ QString fileName;
++ for(const QString &part : domainSplit)
++ {
++ fileName = fileName.insert(0, part + ".");
++ }
++ fileName.append(QCoreApplication::applicationName() + ".log");
++ return fileName;
++}
++
++
++void CLogHandler::appendToFile(QtMsgType type, QString formatedMsg)
++{
++ Q_UNUSED(type);
++ if (writeToFile)
++ {
++ fileStream << formatedMsg << endl;
++ }
++}
++
++
++void CLogHandler::printToConsole(QtMsgType type, QString formatedMsg)
++{
++ switch (type)
++ {
++ case QtDebugMsg:
++ if (debugOutput)
++ {
++ std::cout << formatedMsg.toUtf8().constData() << std::endl;
++ }
++ break;
++
++#if QT_VERSION >= 0x050500
++ case QtInfoMsg:
++ std::cout << formatedMsg.toUtf8().constData() << std::endl;
++ break;
++
++#endif
++ case QtWarningMsg:
++ std::cerr << formatedMsg.toUtf8().constData() << std::endl;
++ break;
++
++ case QtCriticalMsg:
++ std::cerr << formatedMsg.toUtf8().constData() << std::endl;
++ break;
++
++ case QtFatalMsg:
++ std::cerr << formatedMsg.toUtf8().constData() << std::endl;
++ abort();
++ break;
++ }
++}
++
++static CLogHandler* logHandler = nullptr;
++
++static void logCallback(QtMsgType type, const QMessageLogContext &context, const QString &msg)
++{
++ logHandler->log(type, context, msg);
++}
++
++
++void CLogHandler::initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput)
++{
++ logHandler = new CLogHandler(logDirectory, writeToFile, debugOutput);
++ qInstallMessageHandler(logCallback);
++ logHandler->printLoggerInfo();
++}
++
++
+diff --git a/src/qmaptool/setup/CLogHandler.h b/src/qmaptool/setup/CLogHandler.h
+new file mode 100644
+index 00000000..f544e3e3
+--- /dev/null
++++ b/src/qmaptool/setup/CLogHandler.h
+@@ -0,0 +1,47 @@
++/**********************************************************************************************
++ Copyright (C) 2015 Ivo Kronenberg
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CLOGHANDLER_H
++#define CLOGHANDLER_H
++
++#include <QtCore>
++
++class CLogHandler
++{
++public:
++ static void initLogHandler(QString logDirectory, bool writeToFile, bool debugOutput);
++
++ void log(QtMsgType type, const QMessageLogContext &context, const QString &msg);
++
++private:
++ CLogHandler(QString logDirectory, bool writeToFile, bool debugOutput);
++ void printLoggerInfo();
++
++ void appendToFile(QtMsgType type, QString formatedMsg);
++ void printToConsole(QtMsgType type, QString formatedMsg);
++
++ QString logfileName();
++
++ bool writeToFile;
++ bool debugOutput;
++ QFile logFile;
++ QTextStream fileStream;
++};
++
++#endif // CLOGHANDLER_H
++
+diff --git a/src/qmaptool/setup/CSetupExtTools.cpp b/src/qmaptool/setup/CSetupExtTools.cpp
+new file mode 100644
+index 00000000..54c37142
+--- /dev/null
++++ b/src/qmaptool/setup/CSetupExtTools.cpp
+@@ -0,0 +1,93 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "setup/CSetupExtTools.h"
++#include "setup/IAppSetup.h"
++
++#include <QtWidgets>
++
++using std::bind;
++
++#define slot1(name, method) \
++ std::bind(&CSetupExtTools::slotSetPathXOverride, this, name, [](const QString& path){IAppSetup::self().method(path); })
++
++#define slot2(method) \
++ std::bind(&CSetupExtTools::slotResetPathXOverride, this, [](){IAppSetup::self().method(); })
++
++CSetupExtTools::CSetupExtTools(QWidget *parent)
++ : QDialog(parent)
++{
++ setupUi(this);
++ setupGui();
++
++ connect(toolPathGdaladdo, &QToolButton::pressed, this, slot1("gdaladdo", setGdaladdoOverride));
++ connect(toolPathGdaltranslate, &QToolButton::pressed, this, slot1("gdal_translate", setGdaltranslateOverride));
++ connect(toolPathGdalwarp, &QToolButton::pressed, this, slot1("gdalwarp", setGdalwarpOverride));
++ connect(toolPathGdalbuildvrt, &QToolButton::pressed, this, slot1("gdalbuildvrt", setGdalbuildvrtOverride));
++ connect(toolPathQmtrgb2pct, &QToolButton::pressed, this, slot1("qmt_rgb2pct", setQmtrgb2pctOverride));
++ connect(toolPathQmtmap2jnx, &QToolButton::pressed, this, slot1("qmt_map2jnx", setQmtmap2jnxOverride));
++
++ connect(toolResetGdaladdo, &QToolButton::pressed, this, slot2(resetGdaladdoOverride));
++ connect(toolResetGdaltranslate, &QToolButton::pressed, this, slot2(resetGdaltranslateOverride));
++ connect(toolResetGdalwarp, &QToolButton::pressed, this, slot2(resetGdalwarpOverride));
++ connect(toolResetGdalbuildvrt, &QToolButton::pressed, this, slot2(resetGdalbuildvrtOverride));
++ connect(toolResetQmtrgb2pct, &QToolButton::pressed, this, slot2(resetQmtrgb2pctOverride));
++ connect(toolResetQmtmap2jnx, &QToolButton::pressed, this, slot2(resetQmtmap2jnxOverride));
++}
++
++void CSetupExtTools::setupGui()
++{
++ const IAppSetup& setup = IAppSetup::self();
++ const QString& gdaladdo = setup.getGdaladdo();
++ const QString& gdaltranslate = setup.getGdaltranslate();
++ const QString& gdalwarp = setup.getGdalwarp();
++ const QString& gdalbuildvrt = setup.getGdalbuildvrt();
++ const QString& qmtrgb2pct = setup.getQmtrgb2pct();
++ const QString& qmtmap2jnx = setup.getQmtmap2jnx();
++
++ labelPathGdaladdo->setText(gdaladdo.isEmpty() ? tr("<b style='color: red;'>not found</b>") : gdaladdo);
++ labelPathGdaltranslate->setText(gdaltranslate.isEmpty() ? tr("<b style='color: red;'>not found</b>") : gdaltranslate);
++ labelPathGdalwarp->setText(gdalwarp.isEmpty() ? tr("<b style='color: red;'>not found</b>") : gdalwarp);
++ labelPathGdalbuildvrt->setText(gdalbuildvrt.isEmpty() ? tr("<b style='color: red;'>not found</b>") : gdalbuildvrt);
++ labelPathQmtrgb2pct->setText(qmtrgb2pct.isEmpty() ? tr("<b style='color: red;'>not found</b>") : qmtrgb2pct);
++ labelPathQmtmap2jnx->setText(qmtmap2jnx.isEmpty() ? tr("<b style='color: red;'>not found</b>") : qmtmap2jnx);
++
++ toolResetGdaladdo->setEnabled(setup.isGdaladdoOverride());
++ toolResetGdaltranslate->setEnabled(setup.isGdaltranslateOverride());
++ toolResetGdalwarp->setEnabled(setup.isGdalwarpOverride());
++ toolResetGdalbuildvrt->setEnabled(setup.isGdalbuildvrtOverride());
++ toolResetQmtrgb2pct->setEnabled(setup.isQmtrgb2pctOverride());
++ toolResetQmtmap2jnx->setEnabled(setup.isQmtmap2jnxOverride());
++}
++
++void CSetupExtTools::slotSetPathXOverride(const QString& name, fSetPath setPath)
++{
++ const QString& path = QFileDialog::getOpenFileName(this, tr("Select %1 binary...").arg(name), QDir::rootPath());
++ if(path.isEmpty())
++ {
++ return;
++ }
++ setPath(path);
++ setupGui();
++}
++
++void CSetupExtTools::slotResetPathXOverride(fResetPath resetPath)
++{
++ resetPath();
++ setupGui();
++}
+diff --git a/src/qmaptool/setup/CSetupExtTools.h b/src/qmaptool/setup/CSetupExtTools.h
+new file mode 100644
+index 00000000..f93c264f
+--- /dev/null
++++ b/src/qmaptool/setup/CSetupExtTools.h
+@@ -0,0 +1,46 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CSETUPEXTTOOLS_H
++#define CSETUPEXTTOOLS_H
++
++#include <functional>
++#include <QDialog>
++
++#include "ui_ISetupExtTools.h"
++
++using fResetPath = std::function<void()>;
++using fSetPath = std::function<void(const QString&)>;
++
++class CSetupExtTools : public QDialog, private Ui::ISetupExtTools
++{
++ Q_OBJECT
++public:
++ CSetupExtTools(QWidget * parent);
++ virtual ~CSetupExtTools() = default;
++
++private slots:
++ void slotSetPathXOverride(const QString& name, fSetPath setPath);
++ void slotResetPathXOverride(fResetPath resetPath);
++
++private:
++ void setupGui();
++};
++
++#endif //CSETUPEXTTOOLS_H
++
+diff --git a/src/qmaptool/setup/IAppSetup.cpp b/src/qmaptool/setup/IAppSetup.cpp
+new file mode 100644
+index 00000000..912dc0ef
+--- /dev/null
++++ b/src/qmaptool/setup/IAppSetup.cpp
+@@ -0,0 +1,161 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++
++#include "setup/CCommandProcessor.h"
++#include "setup/CLogHandler.h"
++#include "setup/IAppSetup.h"
++
++#include "setup/CAppSetupLinux.h"
++#include "setup/CAppSetupMac.h"
++#include "setup/CAppSetupWin.h"
++
++#include "helpers/CSettings.h"
++
++#include <gdal.h>
++
++
++IAppSetup* IAppSetup::pSelf = nullptr;
++
++IAppSetup& IAppSetup::self()
++{
++ return *pSelf;
++}
++
++IAppSetup::~IAppSetup()
++{
++ SETTINGS;
++ cfg.setValue("ExtTools/pathGdaladdoOverride",pathGdaladdoOverride);
++ cfg.setValue("ExtTools/pathGdaltranslateOverride",pathGdaltranslateOverride);
++ cfg.setValue("ExtTools/pathGdalwarpOverride",pathGdalwarpOverride);
++ cfg.setValue("ExtTools/pathGdalbuildvrtOverride",pathGdalbuildvrtOverride);
++ cfg.setValue("ExtTools/pathQmtrgb2pctOverride",pathQmtrgb2pctOverride);
++ cfg.setValue("ExtTools/pathQmtmap2jnxOverride",pathQmtmap2jnxOverride);
++}
++
++IAppSetup& IAppSetup::createInstance(QObject * parent)
++{
++ if(pSelf != nullptr)
++ {
++ return self();
++ }
++#if defined(Q_OS_MAC)
++ new CAppSetupMac(parent);
++#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(Q_OS_CYGWIN)
++ new CAppSetupLinux(parent);
++#elif defined (Q_OS_WIN32)
++ new CAppSetupWin(parent);
++#else
++ #error OS not supported
++#endif
++ return self();
++}
++
++void IAppSetup::prepareToolPaths()
++{
++ pathGdaladdo = this->findExecutable("gdaladdo");
++ pathGdaltranslate = this->findExecutable("gdal_translate");
++ pathGdalwarp = this->findExecutable("gdalwarp");
++ pathGdalbuildvrt = this->findExecutable("gdalbuildvrt");
++ pathQmtrgb2pct = this->findExecutable("qmt_rgb2pct");
++ pathQmtmap2jnx = this->findExecutable("qmt_map2jnx");
++
++ SETTINGS;
++ pathGdaladdoOverride = cfg.value("ExtTools/pathGdaladdoOverride",pathGdaladdoOverride).toString();
++ pathGdaltranslateOverride = cfg.value("ExtTools/pathGdaltranslateOverride",pathGdaltranslateOverride).toString();
++ pathGdalwarpOverride = cfg.value("ExtTools/pathGdalwarpOverride",pathGdalwarpOverride).toString();
++ pathGdalbuildvrtOverride = cfg.value("ExtTools/pathGdalbuildvrtOverride", pathGdalbuildvrtOverride).toString();
++ pathQmtrgb2pctOverride = cfg.value("ExtTools/pathQmtrgb2pctOverride", pathQmtrgb2pctOverride).toString();
++ pathQmtmap2jnxOverride = cfg.value("ExtTools/pathQmtmap2jnxOverride", pathQmtmap2jnxOverride).toString();
++}
++
++void IAppSetup::prepareGdal(QString gdalDir, QString projDir)
++{
++ if(!gdalDir.isEmpty())
++ {
++ qputenv("GDAL_DATA", gdalDir.toUtf8());
++ qDebug() << "GDAL_DATA directory set to " + gdalDir;
++ }
++
++ if(!projDir.isEmpty())
++ {
++ qputenv("PROJ_LIB", projDir.toUtf8());
++ qDebug() << "PROJ_LIB directory set to " + projDir;
++ }
++
++ GDALAllRegister();
++}
++
++
++QString IAppSetup::path(QString path, QString subdir, bool mkdir, QString debugName)
++{
++ QDir pathDir(path);
++
++ if(subdir != 0)
++ {
++ pathDir = QDir(pathDir.absoluteFilePath(subdir));
++ }
++ if(mkdir && !pathDir.exists())
++ {
++ pathDir.mkpath(pathDir.absolutePath());
++ qDebug() << debugName << "path created" << pathDir.absolutePath();
++ }
++ else if (debugName != 0)
++ {
++ qDebug() << debugName << "path" << pathDir.absolutePath();
++ }
++ return pathDir.absolutePath();
++}
++
++
++void IAppSetup::prepareTranslator(QString translationPath, QString translationPrefix)
++{
++ QString locale = QLocale::system().name();
++ QDir dir(translationPath);
++ if(!QFile::exists(dir.absoluteFilePath(translationPrefix + locale)))
++ {
++ locale = locale.left(2);
++ }
++ qDebug() << "locale" << locale;
++
++ QApplication* app = (QApplication*) QCoreApplication::instance();
++ QTranslator *qtTranslator = new QTranslator(app);
++ if (qtTranslator->load(translationPrefix + locale, translationPath))
++ {
++ app->installTranslator(qtTranslator);
++ qDebug() << "using file '"+ translationPath + "/" + translationPrefix + locale + ".qm' for translations.";
++ }
++ else
++ {
++ qWarning() << "no file found for translations '"+ translationPath + "/" + translationPrefix + locale + "' (using default).";
++ }
++}
++
++
++void IAppSetup::initLogHandler()
++{
++ CLogHandler::initLogHandler(logDir(), qlOpts->logfile, qlOpts->debug);
++}
++
++CAppOpts *qlOpts = nullptr;
++
++void IAppSetup::processArguments()
++{
++ CCommandProcessor cmdParse;
++ qlOpts = cmdParse.processOptions(QCoreApplication::instance()->arguments());
++}
+diff --git a/src/qmaptool/setup/IAppSetup.h b/src/qmaptool/setup/IAppSetup.h
+new file mode 100644
+index 00000000..6718332c
+--- /dev/null
++++ b/src/qmaptool/setup/IAppSetup.h
+@@ -0,0 +1,210 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef IAPPSETUP_H
++#define IAPPSETUP_H
++
++#include "CAppOpts.h"
++#include <QApplication>
++#include <QtCore>
++
++
++class IAppSetup : public QObject
++{
++ Q_OBJECT
++public:
++ static IAppSetup& self();
++ static IAppSetup &createInstance(QObject * parent);
++
++ virtual ~IAppSetup();
++
++ virtual void initQMapTool() = 0;
++ void initLogHandler();
++ void processArguments();
++
++ virtual QString defaultCachePath() = 0;
++ virtual QString userDataPath(QString subdir = 0) = 0;
++ virtual QString logDir() = 0;
++ virtual QString findExecutable(const QString &name) = 0;
++
++ QString getGdaladdo() const
++ {
++ return QFile::exists(pathGdaladdoOverride) ? pathGdaladdoOverride : QFile::exists(pathGdaladdo) ? pathGdaladdo : "";
++ }
++
++ QString getGdaltranslate() const
++ {
++ return QFile::exists(pathGdaltranslateOverride) ? pathGdaltranslateOverride : QFile::exists(pathGdaltranslate) ? pathGdaltranslate : "";
++ }
++
++ QString getGdalwarp() const
++ {
++ return QFile::exists(pathGdalwarpOverride) ? pathGdalwarpOverride : QFile::exists(pathGdalwarp) ? pathGdalwarp : "";
++ }
++
++ QString getGdalbuildvrt() const
++ {
++ return QFile::exists(pathGdalbuildvrtOverride) ? pathGdalbuildvrtOverride : QFile::exists(pathGdalbuildvrt) ? pathGdalbuildvrt : "";
++ }
++
++ QString getQmtrgb2pct() const
++ {
++ return QFile::exists(pathQmtrgb2pctOverride) ? pathQmtrgb2pctOverride : QFile::exists(pathQmtrgb2pct) ? pathQmtrgb2pct : "";
++ }
++
++ QString getQmtmap2jnx() const
++ {
++ return QFile::exists(pathQmtmap2jnxOverride) ? pathQmtmap2jnxOverride : QFile::exists(pathQmtmap2jnx) ? pathQmtmap2jnx : "";
++ }
++
++ void setGdaladdoOverride(const QString& path)
++ {
++ pathGdaladdoOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void setGdaltranslateOverride(const QString& path)
++ {
++ pathGdaltranslateOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void setGdalwarpOverride(const QString& path)
++ {
++ pathGdalwarpOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void setGdalbuildvrtOverride(const QString& path)
++ {
++ pathGdalbuildvrtOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void setQmtrgb2pctOverride(const QString& path)
++ {
++ pathQmtrgb2pctOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void setQmtmap2jnxOverride(const QString& path)
++ {
++ pathQmtmap2jnxOverride = path;
++ emit sigSetupChanged();
++ }
++
++ void resetGdaladdoOverride()
++ {
++ pathGdaladdoOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ void resetGdaltranslateOverride()
++ {
++ pathGdaltranslateOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ void resetGdalwarpOverride()
++ {
++ pathGdalwarpOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ void resetGdalbuildvrtOverride()
++ {
++ pathGdalbuildvrtOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ void resetQmtrgb2pctOverride()
++ {
++ pathQmtrgb2pctOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ void resetQmtmap2jnxOverride()
++ {
++ pathQmtmap2jnxOverride.clear();
++ emit sigSetupChanged();
++ }
++
++ bool isGdaladdoOverride() const
++ {
++ return !pathGdaladdoOverride.isEmpty();
++ }
++
++ bool isGdaltranslateOverride() const
++ {
++ return !pathGdaltranslateOverride.isEmpty();
++ }
++
++ bool isGdalwarpOverride() const
++ {
++ return !pathGdalwarpOverride.isEmpty();
++ }
++
++ bool isGdalbuildvrtOverride() const
++ {
++ return !pathGdalbuildvrtOverride.isEmpty();
++ }
++
++ bool isQmtrgb2pctOverride() const
++ {
++ return !pathQmtrgb2pctOverride.isEmpty();
++ }
++
++ bool isQmtmap2jnxOverride() const
++ {
++ return !pathQmtmap2jnxOverride.isEmpty();
++ }
++
++signals:
++ void sigSetupChanged();
++
++protected:
++ static IAppSetup* pSelf;
++
++ IAppSetup(QObject * parent)
++ : QObject(parent)
++ {
++ pSelf = this;
++ }
++
++ void prepareGdal(QString gdalDir, QString projDir);
++ void prepareTranslator(QString translationPath, QString translationPrefix);
++ void prepareToolPaths();
++
++ QString path(QString path, QString subdir, bool mkdir, QString debugName);
++
++ QString pathGdaladdo;
++ QString pathGdaltranslate;
++ QString pathGdalwarp;
++ QString pathGdalbuildvrt;
++ QString pathQmtrgb2pct;
++ QString pathQmtmap2jnx;
++
++ QString pathGdaladdoOverride;
++ QString pathGdaltranslateOverride;
++ QString pathGdalwarpOverride;
++ QString pathGdalbuildvrtOverride;
++ QString pathQmtrgb2pctOverride;
++ QString pathQmtmap2jnxOverride;
++};
++
++#endif // IAPPSETUP_H
+diff --git a/src/qmaptool/setup/ISetupExtTools.ui b/src/qmaptool/setup/ISetupExtTools.ui
+new file mode 100644
+index 00000000..59a4db1e
+--- /dev/null
++++ b/src/qmaptool/setup/ISetupExtTools.ui
+@@ -0,0 +1,360 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>ISetupExtTools</class>
++ <widget class="QDialog" name="ISetupExtTools">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>348</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Setup Ext. Tools</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QGridLayout" name="gridLayout">
++ <item row="3" column="1">
++ <widget class="QLabel" name="labelPathGdalbuildvrt">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="2">
++ <widget class="QToolButton" name="toolPathGdalwarp">
++ <property name="toolTip">
++ <string>Setup user defined path.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="0">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string>gdalbuildvrt</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="3">
++ <widget class="QToolButton" name="toolResetGdaladdo">
++ <property name="toolTip">
++ <string>Reset user defined path setup.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="4" column="1">
++ <widget class="QLabel" name="labelPathQmtrgb2pct">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="3">
++ <widget class="QToolButton" name="toolResetGdalbuildvrt">
++ <property name="toolTip">
++ <string>Reset user defined path setup.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="3">
++ <widget class="QToolButton" name="toolResetGdaltranslate">
++ <property name="toolTip">
++ <string>Reset user defined path setup.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QLabel" name="labelPathGdaltranslate">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_3">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>gdal_translate:</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="0">
++ <widget class="QLabel" name="label_5">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>gdalwarp:</string>
++ </property>
++ </widget>
++ </item>
++ <item row="4" column="2">
++ <widget class="QToolButton" name="toolPathQmtrgb2pct">
++ <property name="toolTip">
++ <string>Setup user defined path.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="4" column="3">
++ <widget class="QToolButton" name="toolResetQmtrgb2pct">
++ <property name="toolTip">
++ <string>Reset user defined path setup.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>gdaladdo:</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="QLabel" name="labelPathGdaladdo">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="2">
++ <widget class="QToolButton" name="toolPathGdaladdo">
++ <property name="toolTip">
++ <string>Setup user defined path.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="1">
++ <widget class="QLabel" name="labelPathGdalwarp">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="4" column="0">
++ <widget class="QLabel" name="label_6">
++ <property name="text">
++ <string>qmt_rgb2pct</string>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="2">
++ <widget class="QToolButton" name="toolPathGdalbuildvrt">
++ <property name="toolTip">
++ <string>Setup user defined path.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="2">
++ <widget class="QToolButton" name="toolPathGdaltranslate">
++ <property name="toolTip">
++ <string>Setup user defined path.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="3">
++ <widget class="QToolButton" name="toolResetGdalwarp">
++ <property name="toolTip">
++ <string>Reset user defined path setup.</string>
++ </property>
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="5" column="0">
++ <widget class="QLabel" name="label_7">
++ <property name="text">
++ <string>qmt_map2jnx</string>
++ </property>
++ </widget>
++ </item>
++ <item row="5" column="1">
++ <widget class="QLabel" name="labelPathQmtmap2jnx">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;not found&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ <item row="5" column="2">
++ <widget class="QToolButton" name="toolPathQmtmap2jnx">
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item row="5" column="3">
++ <widget class="QToolButton" name="toolResetQmtmap2jnx">
++ <property name="text">
++ <string>...</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Reset.png</normaloff>:/icons/32x32/Reset.png</iconset>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>&lt;b&gt;Note:&lt;/b&gt; Usually QMapTool should detect all external tools by itself. If it does not, it's a bad setup and you should fix the PATH variable of your system. You can setup the paths manually, too, if you know what you are doing. But please keep in mind that GDAL needs a proper environment setup to function properly. If it's not setup properly you might get results but these can be off grid.</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignJustify|Qt::AlignVCenter</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources>
++ <include location="../../qmapshack/resources.qrc"/>
++ </resources>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>ISetupExtTools</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>ISetupExtTools</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++</ui>
+diff --git a/src/qmaptool/shell/CShell.cpp b/src/qmaptool/shell/CShell.cpp
+new file mode 100644
+index 00000000..e124adba
+--- /dev/null
++++ b/src/qmaptool/shell/CShell.cpp
+@@ -0,0 +1,198 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "shell/CShell.h"
++
++#include <QtWidgets>
++
++CShell * CShell::pSelf = nullptr;
++
++CShell::CShell(QWidget *parent)
++ : QTextBrowser(parent)
++{
++ pSelf = this;
++
++ connect(&cmd, &QProcess::readyReadStandardError, this, &CShell::slotStderr);
++ connect(&cmd, &QProcess::readyReadStandardOutput, this, &CShell::slotStdout);
++
++ connect(&cmd, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &CShell::slotFinished);
++ connect(&cmd, static_cast<void (QProcess::*)(QProcess::ProcessError) >(&QProcess::error), this, &CShell::slotError);
++}
++
++void CShell::slotError(QProcess::ProcessError error)
++{
++ setTextColor(Qt::red);
++ insertPlainText(QString(tr("Execution of external program `%1` failed: ")).arg(cmd.program()));
++ switch(error)
++ {
++ case QProcess::FailedToStart:
++ insertPlainText(QString(tr("Process cannot be started.\n")));
++ insertPlainText(QString(tr("Make sure the required packages are installed, `%1` exists and is executable.\n")).arg(cmd.program()));
++ break;
++
++ case QProcess::Crashed:
++ insertPlainText(QString(tr("External process crashed.\n")));
++ break;
++
++ default:
++ insertPlainText(QString(tr("An unknown error occurred.\n")));
++ break;
++ }
++}
++
++void CShell::slotStderr()
++{
++ QString str;
++ setTextColor(Qt::red);
++ str = cmd.readAllStandardError();
++
++ if(str[0] == '\r')
++ {
++#ifdef WIN32
++ if(str.contains("\n"))
++ {
++ insertPlainText("\n");
++ }
++ else
++#endif // WIN32
++ {
++ moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
++ moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
++ moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
++ textCursor().removeSelectedText();
++ }
++
++
++#ifdef WIN32
++ str = str.split("\r").last().remove("\r").remove("\n");
++#else
++ str = str.split("\r").last();
++#endif
++ }
++
++ insertPlainText(str);
++ verticalScrollBar()->setValue(verticalScrollBar()->maximum());
++}
++
++void CShell::slotStdout()
++{
++ QString str;
++ setTextColor(Qt::blue);
++ str = cmd.readAllStandardOutput();
++
++ if(str[0] == '\r')
++ {
++#ifdef WIN32
++ if(str.contains("\n"))
++ {
++ insertPlainText("\n");
++ }
++ else
++#endif // WIN32
++ {
++ moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
++ moveCursor( QTextCursor::StartOfLine, QTextCursor::MoveAnchor );
++ moveCursor( QTextCursor::End, QTextCursor::KeepAnchor );
++ textCursor().removeSelectedText();
++ }
++
++#ifdef WIN32
++ str = str.split("\r").last().remove("\r").remove("\n");
++#else
++ str = str.split("\r").last();
++#endif
++ }
++
++ insertPlainText(str);
++ verticalScrollBar()->setValue(verticalScrollBar()->maximum());
++}
++
++void CShell::stdOut(const QString& str)
++{
++ setTextColor(Qt::black);
++ append(str);
++}
++
++
++void CShell::stdErr(const QString& str)
++{
++ setTextColor(Qt::red);
++ append(str);
++}
++
++
++void CShell::slotFinished(int exitCode, QProcess::ExitStatus status)
++{
++ if(exitCode || status)
++ {
++ emit sigFinishedJob(jobId);
++ setTextColor(Qt::red);
++ append(tr("!!! failed !!!\n"));
++ return;
++ }
++
++ ++idxCommand;
++ nextCommand();
++}
++
++void CShell::slotCancel()
++{
++ if(cmd.state() == QProcess::NotRunning)
++ {
++ return;
++ }
++
++ stdOut(tr("\nCanceled by user's request.\n"));
++ cmd.kill();
++ cmd.waitForFinished(10000);
++}
++
++int CShell::execute(QList<CShellCmd> cmds)
++{
++ CMainWindow::self().makeShellVisible();
++
++ if(cmd.state() != QProcess::NotRunning)
++ {
++ return -1;
++ }
++
++ clear();
++
++ idxCommand = 0;
++ commands = cmds;
++
++ nextCommand();
++ return ++jobId;
++}
++
++
++void CShell::nextCommand()
++{
++ if(idxCommand >= commands.size())
++ {
++ emit sigFinishedJob(jobId);
++ setTextColor(Qt::darkGreen);
++ append(tr("!!! done !!!\n"));
++ return;
++ }
++
++ const CShellCmd& command = commands[idxCommand];
++ stdOut(command.getCmd() + " " + command.getArgs().join(" ") + "\n");
++ cmd.start(command.getCmd(), command.getArgs());
++}
+diff --git a/src/qmaptool/shell/CShell.h b/src/qmaptool/shell/CShell.h
+new file mode 100644
+index 00000000..b4330c78
+--- /dev/null
++++ b/src/qmaptool/shell/CShell.h
+@@ -0,0 +1,75 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CSHELL_H
++#define CSHELL_H
++
++#include "shell/CShellCmd.h"
++
++#include <QList>
++#include <QProcess>
++#include <QTextBrowser>
++
++class CShell : public QTextBrowser
++{
++ Q_OBJECT
++public:
++ static CShell& self()
++ {
++ return *pSelf;
++ }
++
++ virtual ~CShell() = default;
++
++ int execute(QList<CShellCmd> cmds);
++signals:
++ void sigFinishedJob(qint32 jobId);
++
++public slots:
++ void slotCancel();
++
++protected slots:
++ /// read the stderr from the process and paste it into the text browser
++ void slotStderr();
++ /// read the stdout from the process and paste it into the text browser
++ void slotStdout();
++ void slotError(QProcess::ProcessError error);
++ virtual void slotFinished(int exitCode, QProcess::ExitStatus status);
++
++protected:
++ void nextCommand();
++
++ /// write text to stdout color channel of the text browser
++ void stdOut(const QString& str);
++ /// write text to stderr color channel of the text browser
++ void stdErr(const QString& str);
++
++ QProcess cmd;
++
++ QList<CShellCmd> commands;
++ qint32 idxCommand = 0;
++ qint32 jobId = 0;
++
++private:
++ friend class Ui_IMainWindow;
++ CShell(QWidget * parent);
++ static CShell * pSelf;
++};
++
++#endif //CSHELL_H
++
+diff --git a/src/qmaptool/shell/CShellCmd.cpp b/src/qmaptool/shell/CShellCmd.cpp
+new file mode 100644
+index 00000000..25980d7c
+--- /dev/null
++++ b/src/qmaptool/shell/CShellCmd.cpp
+@@ -0,0 +1,27 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "shell/CShellCmd.h"
++
++CShellCmd::CShellCmd(const QString &cmd, const QStringList &args)
++ : cmd(cmd)
++ , args(args)
++{
++}
++
++
+diff --git a/src/qmaptool/shell/CShellCmd.h b/src/qmaptool/shell/CShellCmd.h
+new file mode 100644
+index 00000000..f440325e
+--- /dev/null
++++ b/src/qmaptool/shell/CShellCmd.h
+@@ -0,0 +1,47 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CSHELLCMD_H
++#define CSHELLCMD_H
++
++#include <QString>
++#include <QStringList>
++
++class CShellCmd
++{
++public:
++ CShellCmd(const QString& cmd, const QStringList& args);
++ virtual ~CShellCmd() = default;
++
++ const QString& getCmd() const
++ {
++ return cmd;
++ }
++
++ const QStringList& getArgs() const
++ {
++ return args;
++ }
++
++private:
++ QString cmd;
++ QStringList args;
++};
++
++#endif //CSHELLCMD_H
++
+diff --git a/src/qmaptool/tool/CToolAddOverview.cpp b/src/qmaptool/tool/CToolAddOverview.cpp
+new file mode 100644
+index 00000000..88b8b712
+--- /dev/null
++++ b/src/qmaptool/tool/CToolAddOverview.cpp
+@@ -0,0 +1,225 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "items/CItemFile.h"
++#include "setup/IAppSetup.h"
++#include "tool/CToolAddOverview.h"
++
++CToolAddOverview::CToolAddOverview(QWidget *parent)
++ : IToolGui(parent)
++{
++ setupUi(this);
++ setObjectName(tr("Add Overviews"));
++
++ labelHelp->setText(tr("Raster map files consume quite some memory if a larger area is displayed. "
++ "Pre-calculated overview levels help to speed up loading and displaying the "
++ "map. These overviews can be stored within the map file as well as an external "
++ "file. GDAL can remove internally stored overviews, however it will not free "
++ "the used space in the file. Therefore it's size will remain large. If you "
++ "do not like that use the external option."));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolAddOverview::slotAddItem);
++ connect(checkBy2, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkBy4, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkBy8, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkBy16, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkBy32, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkBy64, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++ connect(checkRemove, &QCheckBox::stateChanged, this, &CToolAddOverview::slotSelectionChanged);
++
++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolAddOverview::slotMapSelectionChanged);
++
++ connect(pushStart, &QPushButton::clicked, this, &CToolAddOverview::slotStart);
++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel);
++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolAddOverview::slotFinished);
++
++
++ setupChanged();
++
++ SETTINGS;
++ cfg.beginGroup("ToolAddOverview");
++ itemList->loadSettings(cfg);
++ checkBy2->setChecked(cfg.value("by2", false).toBool());
++ checkBy4->setChecked(cfg.value("by4", false).toBool());
++ checkBy8->setChecked(cfg.value("by8", false).toBool());
++ checkBy16->setChecked(cfg.value("by16", false).toBool());
++ checkBy32->setChecked(cfg.value("by32", false).toBool());
++ checkBy64->setChecked(cfg.value("by64", false).toBool());
++ checkExternal->setChecked(cfg.value("useExternal", true).toBool());
++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool());
++ cfg.endGroup();
++}
++
++CToolAddOverview::~CToolAddOverview()
++{
++ SETTINGS;
++ cfg.beginGroup("ToolAddOverview");
++ cfg.remove("");
++ itemList->saveSettings(cfg);
++ cfg.setValue("by2", checkBy2->isChecked());
++ cfg.setValue("by4", checkBy4->isChecked());
++ cfg.setValue("by8", checkBy8->isChecked());
++ cfg.setValue("by16", checkBy16->isChecked());
++ cfg.setValue("by32", checkBy32->isChecked());
++ cfg.setValue("by64", checkBy64->isChecked());
++ cfg.setValue("useExternal", checkExternal->isChecked());
++ cfg.setValue("allFiles", checkAllFiles->isChecked());
++ cfg.endGroup();
++}
++
++
++void CToolAddOverview::setupChanged()
++{
++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty();
++ labelNoGdaladdo->setVisible(!hasGdaladdo);
++ frame->setVisible(hasGdaladdo);
++}
++
++void CToolAddOverview::slotAddItem(const QString& filename, QListWidget * list)
++{
++ CItemFile * item = new CItemFile(filename, list);
++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged);
++}
++
++void CToolAddOverview::slotMapSelectionChanged()
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++ slotSelectionChanged();
++}
++
++void CToolAddOverview::slotSelectionChanged()
++{
++ bool enable = checkBy2->isChecked()|checkBy4->isChecked()|checkBy8->isChecked()|checkBy16->isChecked()|checkBy32->isChecked()|checkBy64->isChecked()|checkRemove->isChecked();
++ pushStart->setEnabled(enable && itemList->count());
++
++ bool isRemove = checkRemove->isChecked();
++ frameLevels->setDisabled(isRemove);
++ checkExternal->setDisabled(isRemove);
++}
++
++void CToolAddOverview::buildCmd(QList<CShellCmd>& cmds, const IItem *iitem)
++{
++ const CItemFile * item = dynamic_cast<const CItemFile*>(iitem);
++ if(nullptr == item)
++ {
++ return;
++ }
++
++ item->getDrawContext()->unload();
++
++ // remove previous overview
++ QStringList args;
++ if(checkRemove->isChecked())
++ {
++ args << "-clean" << item->getFilename();
++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args);
++ /// @todo: shrink the file
++ }
++ else
++ {
++ IDrawContext * context = item->getDrawContext();
++
++ // add new ones
++ args.clear();
++ args << "-r";
++ args << (context->is32BitRgb() ? "cubic" : "nearest");
++
++ if(checkExternal->isChecked())
++ {
++ args << "-ro";
++ }
++
++ args << item->getFilename();
++ if(checkBy2->isChecked())
++ {
++ args << "2";
++ }
++ if(checkBy4->isChecked())
++ {
++ args << "4";
++ }
++ if(checkBy8->isChecked())
++ {
++ args << "8";
++ }
++ if(checkBy16->isChecked())
++ {
++ args << "16";
++ }
++ if(checkBy32->isChecked())
++ {
++ args << "32";
++ }
++ if(checkBy64->isChecked())
++ {
++ args << "64";
++ }
++
++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args);
++ }
++}
++
++void CToolAddOverview::slotStart()
++{
++ start(itemList, checkAllFiles->isChecked());
++ if(jobId > 0)
++ {
++ itemList->setEnabled(false);
++ frameInput->setEnabled(false);
++ pushStart->setEnabled(false);
++ pushCancel->setEnabled(true);
++ }
++}
++
++void CToolAddOverview::slotFinished(qint32 id)
++{
++ if(finished(id))
++ {
++ itemList->setEnabled(true);
++ frameInput->setEnabled(true);
++ pushStart->setEnabled(true);
++ pushCancel->setEnabled(false);
++ }
++
++ if(checkAllFiles->isChecked())
++ {
++ const int N = itemList->count();
++ for(int n = 0; n < N; n++)
++ {
++ IItem * item = itemList->item(n);
++ if(nullptr != item)
++ {
++ item->reload();
++ }
++ }
++ }
++ else
++ {
++ IItem * item = itemList->currentItem();
++ if(nullptr != item)
++ {
++ item->reload();
++ }
++ }
++}
+diff --git a/src/qmaptool/tool/CToolAddOverview.h b/src/qmaptool/tool/CToolAddOverview.h
+new file mode 100644
+index 00000000..902c64aa
+--- /dev/null
++++ b/src/qmaptool/tool/CToolAddOverview.h
+@@ -0,0 +1,51 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLADDOVERVIEW_H
++#define CTOOLADDOVERVIEW_H
++
++#include "items/IItem.h"
++#include "tool/ITool.h"
++#include "tool/IToolGui.h"
++#include "ui_IToolAddOverview.h"
++
++
++class CToolAddOverview : public IToolGui, public ITool, private Ui::IToolAddOverview
++{
++ Q_OBJECT
++public:
++ CToolAddOverview(QWidget * parent);
++ virtual ~CToolAddOverview();
++
++ void setupChanged() override;
++
++ FORWARD_LIST_ALL(itemList)
++
++private slots:
++ void slotAddItem(const QString& filename, QListWidget * list);
++ void slotMapSelectionChanged();
++ void slotSelectionChanged();
++ void slotStart();
++ void slotFinished(qint32 id);
++
++protected:
++ void buildCmd(QList<CShellCmd>& cmds, const IItem * iitem) override;
++};
++
++#endif //CTOOLADDOVERVIEW_H
++
+diff --git a/src/qmaptool/tool/CToolBox.cpp b/src/qmaptool/tool/CToolBox.cpp
+new file mode 100644
+index 00000000..c154280a
+--- /dev/null
++++ b/src/qmaptool/tool/CToolBox.cpp
+@@ -0,0 +1,44 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "tool/CToolBox.h"
++
++CToolBox::CToolBox(QWidget *parent)
++ : QToolBox(parent)
++{
++ connect(this, &CToolBox::currentChanged, this, &CToolBox::slotToolChanged);
++}
++
++void CToolBox::setupChanged()
++{
++ const int N = count();
++ for(int n = 0; n < N; n++)
++ {
++ ITool * tool = dynamic_cast<ITool*>(widget(n));
++ if(nullptr != tool)
++ {
++ tool->setupChanged();
++ }
++ }
++}
++
++void CToolBox::slotToolChanged(int idx)
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++}
+diff --git a/src/qmaptool/tool/CToolBox.h b/src/qmaptool/tool/CToolBox.h
+new file mode 100644
+index 00000000..d357d903
+--- /dev/null
++++ b/src/qmaptool/tool/CToolBox.h
+@@ -0,0 +1,40 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLBOX_H
++#define CTOOLBOX_H
++
++#include "tool/ITool.h"
++#include <QToolBox>
++
++class CToolBox : public ITool, public QToolBox
++{
++public:
++ CToolBox(QWidget * parent);
++ virtual ~CToolBox() = default;
++
++ void setupChanged() override;
++
++ FORWARD_WIDGET_ALL()
++
++private slots:
++ void slotToolChanged(int idx);
++};
++
++#endif //CTOOLBOX_H
++
+diff --git a/src/qmaptool/tool/CToolCutMap.cpp b/src/qmaptool/tool/CToolCutMap.cpp
+new file mode 100644
+index 00000000..a835230d
+--- /dev/null
++++ b/src/qmaptool/tool/CToolCutMap.cpp
+@@ -0,0 +1,202 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "items/CItemCutMap.h"
++#include "setup/IAppSetup.h"
++#include "tool/CToolCutMap.h"
++
++CToolCutMap::CToolCutMap(QWidget *parent)
++ : IToolGui(parent)
++{
++ setupUi(this);
++ setObjectName(tr("Cut Map"));
++
++ labelHelp->setText(tr("Paper maps usually have a border you don't want to have. To combine "
++ "maps seamlessly you have to cut that border, replacing it by transparent "
++ "pixel. This tool allows you to define a cut line and it will add an alpha "
++ "channel for transparency to your map."));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolCutMap::slotAddItem);
++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolCutMap::slotMapSelectionChanged);
++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolCutMap::slotSomethingChanged);
++
++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolCutMap::slotSomethingChanged);
++
++ connect(pushStart, &QPushButton::clicked, this, &CToolCutMap::slotStart);
++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel);
++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolCutMap::slotFinished);
++
++ setupChanged();
++
++ SETTINGS;
++ cfg.beginGroup("ToolCutMap");
++ itemList->loadSettings(cfg);
++ groupOverviews->loadSettings(cfg);
++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool());
++ lineSuffix->setText(cfg.value("suffix","_cut").toString());
++ cfg.endGroup();
++
++ slotSomethingChanged();
++}
++
++CToolCutMap::~CToolCutMap()
++{
++ SETTINGS;
++ cfg.beginGroup("ToolCutMap");
++ cfg.remove("");
++ itemList->saveSettings(cfg);
++ groupOverviews->saveSettings(cfg);
++ cfg.setValue("allFiles", checkAllFiles->isChecked());
++ cfg.setValue("suffix", lineSuffix->text());
++ cfg.endGroup();
++}
++
++void CToolCutMap::setupChanged()
++{
++ bool hasGdalwarp = !IAppSetup::self().getGdalwarp().isEmpty();
++ labelNoGdalwarp->setVisible(!hasGdalwarp);
++
++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty();
++ labelNoGdaladdo->setVisible(!hasGdaladdo);
++
++ frame->setVisible(hasGdalwarp && hasGdaladdo);
++}
++
++void CToolCutMap::slotAddItem(const QString& filename, QListWidget * list)
++{
++ CItemCutMap * item = new CItemCutMap(filename, stackedWidget, list);
++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged);
++}
++
++void CToolCutMap::slotMapSelectionChanged()
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++ slotSomethingChanged();
++}
++
++void CToolCutMap::slotSomethingChanged()
++{
++ IItem * item = itemList->currentItem();
++ if(item != nullptr)
++ {
++ bool ok = item->isOk();
++ if(lineSuffix->text().isEmpty())
++ {
++ ok = false;
++ }
++ pushStart->setEnabled(ok);
++ }
++ else
++ {
++ pushStart->setEnabled(false);
++ }
++}
++
++
++void CToolCutMap::buildCmd(QList<CShellCmd>& cmds, const IItem *iitem)
++{
++ const CItemCutMap * item = dynamic_cast<const CItemCutMap*>(iitem);
++ if(nullptr == item)
++ {
++ return;
++ }
++
++ // ---- command 1 ----------------------
++ const IDrawContext * context = item->getDrawContext();
++ QStringList args;
++ // --- overwrite last output file ---
++ args << "-overwrite";
++ // --- use all CPU cores when possible ---
++ args << "-multi";
++ args << "-wo";
++ args << "NUM_THREADS=ALL_CPUS";
++
++ if(context->getProjection().isEmpty())
++ {
++ // --- if the source in not referenced ---
++ args << "-to";
++ args << "SRC_METHOD=NO_GEOTRANSFORM";
++ args << "-to";
++ args << "DST_METHOD=NO_GEOTRANSFORM";
++ }
++ else
++ {
++ // --- this only works for referenced sources ---
++ args << "-crop_to_cutline";
++ }
++
++ // --- define transparent color ---
++ if(context->getRasterBandCount() == 1)
++ {
++ if(!context->getNoData())
++ {
++ // --- use no data value for destination, too ---
++ args << "-dstnodata" << "255";
++ }
++ }
++ else if(context->getRasterBandCount() == 3)
++ {
++ // --- add alpha channel to files with just RGB ---
++ args << "-dstalpha";
++ }
++
++ QString wktFilename = createTempFile("csv");
++ item->saveShape(wktFilename);
++ QString inFilename = item->getFilename();
++ QFileInfo fi(inFilename);
++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix());
++
++ args << "-cutline";
++ args << wktFilename;
++ args << inFilename;
++ args << outFilename;
++
++ cmds << CShellCmd(IAppSetup::self().getGdalwarp(), args);
++
++ // ---- command 2 ----------------------
++ groupOverviews->buildCmd(cmds, outFilename, context->is32BitRgb() ? "cubic" : "nearest");
++}
++
++void CToolCutMap::slotStart()
++{
++ start(itemList, checkAllFiles->isChecked());
++ if(jobId > 0)
++ {
++ itemList->setEnabled(false);
++ frameInput->setEnabled(false);
++ pushStart->setEnabled(false);
++ pushCancel->setEnabled(true);
++ }
++}
++
++void CToolCutMap::slotFinished(qint32 id)
++{
++ if(finished(id))
++ {
++ itemList->setEnabled(true);
++ frameInput->setEnabled(true);
++ pushStart->setEnabled(true);
++ pushCancel->setEnabled(false);
++ }
++}
+diff --git a/src/qmaptool/tool/CToolCutMap.h b/src/qmaptool/tool/CToolCutMap.h
+new file mode 100644
+index 00000000..c2f94938
+--- /dev/null
++++ b/src/qmaptool/tool/CToolCutMap.h
+@@ -0,0 +1,51 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLCUTMAP_H
++#define CTOOLCUTMAP_H
++
++#include "items/IItem.h"
++#include "tool/ITool.h"
++#include "tool/IToolGui.h"
++#include "ui_IToolCutMap.h"
++
++class CToolCutMap : public IToolGui, public ITool, private Ui::IToolCutMap
++{
++ Q_OBJECT
++public:
++ CToolCutMap(QWidget * parent);
++ virtual ~CToolCutMap();
++
++ void setupChanged() override;
++
++ FORWARD_LIST_ALL(itemList)
++
++
++private slots:
++ void slotAddItem(const QString& filename, QListWidget * list);
++ void slotMapSelectionChanged();
++ void slotSomethingChanged();
++ void slotStart();
++ void slotFinished(qint32 id);
++
++private:
++ void buildCmd(QList<CShellCmd>& cmds, const IItem *iitem) override;
++};
++
++#endif //CTOOLCUTMAP_H
++
+diff --git a/src/qmaptool/tool/CToolExport.cpp b/src/qmaptool/tool/CToolExport.cpp
+new file mode 100644
+index 00000000..41ae83f5
+--- /dev/null
++++ b/src/qmaptool/tool/CToolExport.cpp
+@@ -0,0 +1,193 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "items/CItemMap.h"
++#include "tool/CToolExport.h"
++
++#include <QtWidgets>
++
++CToolExport::CToolExport(QWidget *parent)
++ : IToolGui(parent)
++{
++ setupUi(this);
++ setObjectName(tr("Export Maps"));
++ lineTragetFile->addAction(actionTargetFilename,QLineEdit::TrailingPosition);
++
++ labelHelp->setText(tr("To use the maps on your device you have to export them to the proprietary "
++ "format supported by the device. Depending on the device this can vary from "
++ "a single layer map to a map stack with maps of different scale."
++ ));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ labelNote->setText(tr("Note: This tool will use all files in the list as a input. "
++ "This will only work if all files have the same projection."
++ ));
++ labelNote->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelNote, &QLabel::setVisible);
++
++ connect(itemTree, &CItemTreeWidget::sigSelectionChanged, this, &CToolExport::slotMapSelectionChanged);
++ connect(itemTree, &CItemTreeWidget::sigChanged, this, &CToolExport::slotSomethingChanged);
++ connect(lineTragetFile, &QLineEdit::textChanged, this, &CToolExport::slotSomethingChanged);
++ connect(actionTargetFilename, &QAction::triggered, this, &CToolExport::slotSelectFilename);
++ connect(comboExport, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), stackedWidget, &QStackedWidget::setCurrentIndex);
++
++ connect(pushStart, &QPushButton::clicked, this, &CToolExport::slotStart);
++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel);
++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolExport::slotFinished);
++
++
++ setupChanged();
++
++ SETTINGS;
++ cfg.beginGroup("ToolExport");
++ itemTree->loadSettings(cfg);
++
++ comboExport->setCurrentIndex(cfg.value("current",0).toInt());
++ lineTragetFile->setText(cfg.value("targetFile", "").toString());
++ cfg.endGroup();
++}
++
++CToolExport::~CToolExport()
++{
++ SETTINGS;
++ cfg.beginGroup("ToolExport");
++ cfg.remove("");
++ itemTree->saveSettings(cfg);
++ cfg.setValue("current", comboExport->currentIndex());
++ cfg.setValue("targetFile", lineTragetFile->text());
++ cfg.endGroup();
++}
++
++
++void CToolExport::setupChanged()
++{
++ bool hasMap2jnx = !IAppSetup::self().getQmtmap2jnx().isEmpty();
++ labelNoMap2jnx->setVisible(!hasMap2jnx);
++
++ frame->setVisible(hasMap2jnx);
++}
++
++void CToolExport::slotMapSelectionChanged()
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++ slotSomethingChanged();
++}
++
++
++void CToolExport::slotSomethingChanged()
++{
++ bool ok = true;
++ if(itemTree->topLevelItemCount() == 0)
++ {
++ ok = false;
++ }
++ if(lineTragetFile->text().isEmpty())
++ {
++ ok = false;
++ }
++ pushStart->setEnabled(ok);
++}
++
++void CToolExport::slotSelectFilename()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString();
++ QString filename = QFileDialog::getSaveFileName(this, tr("Select filename..."), path);
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/mapInput", QFileInfo(filename).absolutePath());
++
++ lineTragetFile->setText(filename);
++}
++
++
++void CToolExport::buildCmd(QList<CShellCmd>& cmds, const IItem * iitem)
++{
++ inputFiles << iitem->getFilename();
++}
++
++void CToolExport::buildCmdFinal(QList<CShellCmd>& cmds)
++{
++ switch(comboExport->currentIndex())
++ {
++ case eTypeJnx:
++ buildCmdFinalJnx(cmds);
++ break;
++
++ case eTypeRmap:
++ buildCmdFinalRmap(cmds);
++ break;
++ }
++}
++
++void CToolExport::buildCmdFinalJnx(QList<CShellCmd>& cmds)
++{
++ QStringList args;
++ args << "-q" << pageBirdsEyeJnx->getJpegQuality();
++ args << "-s" << pageBirdsEyeJnx->getJpegSubsampling();
++ args << "-p" << pageBirdsEyeJnx->getProductId();
++ args << "-m" << pageBirdsEyeJnx->getProductName();
++ args << "-n" << pageBirdsEyeJnx->getDescription();
++ args << "-c" << pageBirdsEyeJnx->getCopyright();
++ args << "-z" << pageBirdsEyeJnx->getZOrder();
++ args += inputFiles;
++
++ QString targetFile = lineTragetFile->text();
++ QFileInfo fi(targetFile);
++ if(fi.suffix().toUpper() != "JNX")
++ {
++ targetFile += ".jnx";
++ }
++ args << targetFile;
++ cmds << CShellCmd(IAppSetup::self().getQmtmap2jnx(), args);
++}
++
++void CToolExport::buildCmdFinalRmap(QList<CShellCmd>& cmds)
++{
++}
++
++
++void CToolExport::slotStart()
++{
++ inputFiles.clear();
++
++ start(itemTree);
++ if(jobId > 0)
++ {
++ itemTree->setEnabled(false);
++ pushStart->setEnabled(false);
++ pushCancel->setEnabled(true);
++ }
++}
++
++void CToolExport::slotFinished(qint32 id)
++{
++ if(finished(id))
++ {
++ itemTree->setEnabled(true);
++ pushStart->setEnabled(true);
++ pushCancel->setEnabled(false);
++ }
++}
++
+diff --git a/src/qmaptool/tool/CToolExport.h b/src/qmaptool/tool/CToolExport.h
+new file mode 100644
+index 00000000..560370c8
+--- /dev/null
++++ b/src/qmaptool/tool/CToolExport.h
+@@ -0,0 +1,63 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLEXPORT_H
++#define CTOOLEXPORT_H
++
++#include "items/IItem.h"
++#include "tool/ITool.h"
++#include "tool/IToolGui.h"
++#include "ui_IToolExport.h"
++
++class CToolExport : public IToolGui, public ITool, private Ui::IToolExport
++{
++ Q_OBJECT
++public:
++ CToolExport(QWidget * parent);
++ virtual ~CToolExport();
++
++ void setupChanged() override;
++
++ FORWARD_TREE_ALL(itemTree)
++
++private slots:
++ void slotMapSelectionChanged();
++ void slotSomethingChanged();
++ void slotStart();
++ void slotFinished(qint32 id);
++
++ void slotSelectFilename();
++
++private:
++ void buildCmd(QList<CShellCmd>& cmds, const IItem * iitem) override;
++ void buildCmdFinal(QList<CShellCmd>& cmds) override;
++
++ void buildCmdFinalJnx(QList<CShellCmd>& cmds);
++ void buildCmdFinalRmap(QList<CShellCmd>& cmds);
++
++ enum type_e
++ {
++ eTypeJnx = 0
++ , eTypeRmap = 1
++ };
++
++ QStringList inputFiles;
++};
++
++#endif //CTOOLEXPORT_H
++
+diff --git a/src/qmaptool/tool/CToolGrid.cpp b/src/qmaptool/tool/CToolGrid.cpp
+new file mode 100644
+index 00000000..c232340a
+--- /dev/null
++++ b/src/qmaptool/tool/CToolGrid.cpp
+@@ -0,0 +1,124 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "items/CItemRefMap.h"
++#include "overlay/COverlayRefMap.h"
++#include "tool/CToolGrid.h"
++
++#include <QtWidgets>
++
++#define TESTITEM(cmd) \
++ if(nullptr == item) \
++ { \
++ return cmd; \
++ } \
++
++
++CToolGrid::CToolGrid(QWidget *parent)
++ : QWidget(parent)
++{
++ setupUi(this);
++ labelHelp->setText(tr("By placing 4 reference points at the corners of a grid "
++ "square and referencing them by their top left corner, "
++ "the width and height, all the other grid points can be "
++ "estimated."));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ connect(pushOk, &QPushButton::clicked, this, &CToolGrid::slotOk);
++ connect(pushCancel, &QPushButton::clicked, this, &CToolGrid::slotCancel);
++ connect(overlay, &COverlayGridTool::sigChanged, pushOk, &QPushButton::setEnabled);
++ connect(pushReset, &QPushButton::clicked, overlay, &COverlayGridTool::slotReset);
++}
++
++void CToolGrid::registerItem(CItemRefMap * item)
++{
++ this->item = item;
++ overlay->registerItem(item);
++}
++
++bool CToolGrid::drawFx(QPainter& p, CCanvas::redraw_e needsRedraw)
++{
++ TESTITEM(false)
++ item->drawFx(p, needsRedraw);
++ overlay->drawFx(p, needsRedraw);
++
++ return true;
++}
++
++void CToolGrid::mousePressEventFx(QMouseEvent *e)
++{
++ TESTITEM()
++ item->CItemFile::mousePressEventFx(e);
++}
++
++void CToolGrid::mouseMoveEventFx(QMouseEvent *e)
++{
++ TESTITEM()
++ item->CItemFile::mouseMoveEventFx(e);
++ if(!item->getMapIsMoving())
++ {
++ overlay->mouseMoveEventFx(e);
++ }
++}
++
++void CToolGrid::mouseReleaseEventFx(QMouseEvent *e)
++{
++ TESTITEM()
++ if(!item->getMapDidMove())
++ {
++ overlay->mouseReleaseEventFx(e);
++ }
++ item->CItemFile::mouseReleaseEventFx(e);
++}
++
++void CToolGrid::wheelEventFx(QWheelEvent *e)
++{
++ TESTITEM()
++ item->CItemFile::wheelEventFx(e);
++}
++
++void CToolGrid::leaveEventFx(QEvent *e)
++{
++ TESTITEM()
++ item->CItemFile::leaveEventFx(e);
++ overlay->leaveEventFx(e);
++}
++
++QCursor CToolGrid::getCursorFx()
++{
++ TESTITEM(Qt::ArrowCursor)
++ return overlay->getCursorFx();
++}
++
++
++void CToolGrid::slotOk()
++{
++ TESTITEM()
++ item->addRefPoints(overlay->getRefPoints());
++ slotCancel();
++}
++
++
++void CToolGrid::slotCancel()
++{
++ CMainWindow::self().showToolBox();
++ registerItem(nullptr);
++}
+diff --git a/src/qmaptool/tool/CToolGrid.h b/src/qmaptool/tool/CToolGrid.h
+new file mode 100644
+index 00000000..4dd970ce
+--- /dev/null
++++ b/src/qmaptool/tool/CToolGrid.h
+@@ -0,0 +1,57 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLGRID_H
++#define CTOOLGRID_H
++
++#include "tool/ITool.h"
++#include "ui_IToolGrid.h"
++
++class CItemRefMap;
++
++class CToolGrid : public QWidget, public ITool, private Ui::IToolGrid
++{
++ Q_OBJECT
++public:
++ virtual ~CToolGrid() = default;
++
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override;
++ void mousePressEventFx(QMouseEvent *e) override;
++ void mouseMoveEventFx(QMouseEvent *e) override;
++ void mouseReleaseEventFx(QMouseEvent *e) override;
++ void wheelEventFx(QWheelEvent *e) override;
++ void leaveEventFx(QEvent *e) override;
++ QCursor getCursorFx() override;
++
++ void setupChanged() override {}
++
++ void registerItem(CItemRefMap * item);
++
++private slots:
++ void slotOk();
++ void slotCancel();
++
++private:
++ friend class CMainWindow;
++ CToolGrid(QWidget * parent);
++
++ CItemRefMap * item = nullptr;
++};
++
++#endif //CTOOLGRID_H
++
+diff --git a/src/qmaptool/tool/CToolOverviewGroupBox.cpp b/src/qmaptool/tool/CToolOverviewGroupBox.cpp
+new file mode 100644
+index 00000000..4ea7d417
+--- /dev/null
++++ b/src/qmaptool/tool/CToolOverviewGroupBox.cpp
+@@ -0,0 +1,95 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "setup/IAppSetup.h"
++#include "tool/CToolOverviewGroupBox.h"
++
++#include <QtWidgets>
++
++CToolOverviewGroupBox::CToolOverviewGroupBox(QWidget *parent)
++ : QGroupBox(parent)
++{
++ setupUi(this);
++}
++
++void CToolOverviewGroupBox::saveSettings(QSettings& cfg)
++{
++ cfg.setValue("createOverviews", isChecked());
++ cfg.setValue("by2", checkBy2->isChecked());
++ cfg.setValue("by4", checkBy4->isChecked());
++ cfg.setValue("by8", checkBy8->isChecked());
++ cfg.setValue("by16", checkBy16->isChecked());
++ cfg.setValue("by32", checkBy32->isChecked());
++ cfg.setValue("by64", checkBy64->isChecked());
++ cfg.setValue("useExternal", checkExternal->isChecked());
++}
++
++void CToolOverviewGroupBox::loadSettings(QSettings& cfg)
++{
++ setChecked(cfg.value("createOverviews", false).toBool());
++ checkBy2->setChecked(cfg.value("by2", false).toBool());
++ checkBy4->setChecked(cfg.value("by4", false).toBool());
++ checkBy8->setChecked(cfg.value("by8", false).toBool());
++ checkBy16->setChecked(cfg.value("by16", false).toBool());
++ checkBy32->setChecked(cfg.value("by32", false).toBool());
++ checkBy64->setChecked(cfg.value("by64", false).toBool());
++ checkExternal->setChecked(cfg.value("useExternal", true).toBool());
++}
++
++
++void CToolOverviewGroupBox::buildCmd(QList<CShellCmd>& cmds, const QString& filename, const QString& resampling)
++{
++ if(isChecked())
++ {
++ QStringList args;
++ if(checkExternal->isChecked())
++ {
++ args << "-ro";
++ }
++
++ args << "-r";
++ args << resampling;
++
++ args << filename;
++ if(checkBy2->isChecked())
++ {
++ args << "2";
++ }
++ if(checkBy4->isChecked())
++ {
++ args << "4";
++ }
++ if(checkBy8->isChecked())
++ {
++ args << "8";
++ }
++ if(checkBy16->isChecked())
++ {
++ args << "16";
++ }
++ if(checkBy32->isChecked())
++ {
++ args << "32";
++ }
++ if(checkBy64->isChecked())
++ {
++ args << "64";
++ }
++ cmds << CShellCmd(IAppSetup::self().getGdaladdo(), args);
++ }
++}
+diff --git a/src/qmaptool/tool/CToolOverviewGroupBox.h b/src/qmaptool/tool/CToolOverviewGroupBox.h
+new file mode 100644
+index 00000000..776a8a50
+--- /dev/null
++++ b/src/qmaptool/tool/CToolOverviewGroupBox.h
+@@ -0,0 +1,43 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLOVERVIEWGROUPBOX_H
++#define CTOOLOVERVIEWGROUPBOX_H
++
++#include "shell/CShellCmd.h"
++
++#include "ui_IToolOverviewGroupBox.h"
++
++class QSettings;
++
++class CToolOverviewGroupBox : public QGroupBox, private Ui::IToolOverviewGroupBox
++{
++ Q_OBJECT
++public:
++ CToolOverviewGroupBox(QWidget * parent);
++ virtual ~CToolOverviewGroupBox() = default;
++
++ void saveSettings(QSettings& cfg);
++ void loadSettings(QSettings& cfg);
++
++
++ void buildCmd(QList<CShellCmd>& cmds, const QString& filename, const QString &resampling);
++};
++
++#endif //CTOOLOVERVIEWGROUPBOX_H
++
+diff --git a/src/qmaptool/tool/CToolPalettize.cpp b/src/qmaptool/tool/CToolPalettize.cpp
+new file mode 100644
+index 00000000..fd266c12
+--- /dev/null
++++ b/src/qmaptool/tool/CToolPalettize.cpp
+@@ -0,0 +1,319 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "helpers/CSettings.h"
++#include "items/CItemFile.h"
++#include "tool/CToolPalettize.h"
++
++#include <QtWidgets>
++
++CToolPalettize::CToolPalettize(QWidget *parent)
++ : IToolGui(parent)
++{
++ setupUi(this);
++ setObjectName(tr("Add Color Palette"));
++
++ lineFilename->addAction(actionFilename,QLineEdit::TrailingPosition);
++
++ labelHelp->setText(tr("Usually you use RGBA color while referencing a map because the large "
++ "color space allows you to scale and rotate the map without any loss "
++ "of quality. But it results into rather large files. The file size can "
++ "be optimized by using a color palette instead of the RGBA color space. "
++ "The impact on quality is low as long as you do not want to scale or "
++ "rotate the map. If you want to combine files with a color palette all "
++ "files need to have the same palette."
++ ));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ labelNote->setText(tr("Note: This tool will use all files in the list as a combined input "
++ "to derive an optimal palette. This will only work if all files have "
++ "the same projection and scale."
++ ));
++ labelNote->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelNote, &QLabel::setVisible);
++
++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolPalettize::slotAddItem);
++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolPalettize::slotMapSelectionChanged);
++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolPalettize::slotSomethingChanged);
++
++ connect(radioSingle, &QRadioButton::toggled, lineSuffix, &QLineEdit::setEnabled);
++ connect(radioSingle, &QRadioButton::toggled, this, &CToolPalettize::slotSomethingChanged);
++ connect(radioCombined, &QRadioButton::toggled, lineFilename, &QLineEdit::setEnabled);
++ connect(radioCombined, &QRadioButton::toggled, this, &CToolPalettize::slotSomethingChanged);
++
++ connect(actionFilename, &QAction::triggered, this, &CToolPalettize::slotSelectFilename);
++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolPalettize::slotSomethingChanged);
++ connect(lineFilename, &QLineEdit::textChanged, this, &CToolPalettize::slotSomethingChanged);
++
++ connect(pushStart, &QPushButton::clicked, this, &CToolPalettize::slotStart);
++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel);
++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolPalettize::slotFinished);
++
++ setupChanged();
++
++ SETTINGS;
++ cfg.beginGroup("ToolPalettize");
++ itemList->loadSettings(cfg);
++ checkCreateVrt->setChecked(cfg.value("createVrt", false).toBool());
++ groupOverviews->loadSettings(cfg);
++ radioSingle->setChecked(cfg.value("singleFiles", true).toBool());
++ radioCombined->setChecked(cfg.value("combinedFile", false).toBool());
++ lineFilename->setText(cfg.value("filename","").toString());
++ lineSuffix->setText(cfg.value("suffix","_8bit").toString());
++ cfg.endGroup();
++
++ lineFilename->setEnabled(radioCombined->isChecked());
++ lineSuffix->setEnabled(radioSingle->isChecked());
++
++ inputFileList1 = new QTemporaryFile(this);
++ inputFileList2 = new QTemporaryFile(this);
++}
++
++CToolPalettize::~CToolPalettize()
++{
++ SETTINGS;
++ cfg.beginGroup("ToolPalettize");
++ cfg.remove("");
++ itemList->saveSettings(cfg);
++ cfg.setValue("createVrt", checkCreateVrt->isChecked());
++ groupOverviews->saveSettings(cfg);
++ cfg.setValue("singleFiles", radioSingle->isChecked());
++ cfg.setValue("combinedFile", radioCombined->isChecked());
++ cfg.setValue("filename", lineFilename->text());
++ cfg.setValue("suffix", lineSuffix->text());
++ cfg.endGroup();
++}
++
++void CToolPalettize::slotSelectFilename()
++{
++ SETTINGS;
++ QString path = cfg.value("Path/mapInput", QDir::homePath()).toString();
++ QString filename = QFileDialog::getSaveFileName(this, tr("Select filename..."), path);
++ if(filename.isEmpty())
++ {
++ return;
++ }
++ cfg.setValue("Path/mapInput", QFileInfo(filename).absolutePath());
++
++ if(!filename.toUpper().endsWith(".TIF"))
++ {
++ filename += ".tif";
++ }
++
++ lineFilename->setText(filename);
++}
++
++void CToolPalettize::setupChanged()
++{
++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty();
++ labelNoGdaladdo->setVisible(!hasGdaladdo);
++
++ bool hasGdaltranslate = !IAppSetup::self().getGdaltranslate().isEmpty();
++ labelNoGdaltranslate->setVisible(!hasGdaltranslate);
++
++ bool hasQmtrgb2pct = !IAppSetup::self().getQmtrgb2pct().isEmpty();
++ labelNoQmtrgb2pct->setVisible(!hasQmtrgb2pct);
++
++ frame->setVisible(hasGdaladdo && hasQmtrgb2pct && hasGdaltranslate);
++}
++
++void CToolPalettize::slotAddItem(const QString& filename, QListWidget * list)
++{
++ CItemFile * item = new CItemFile(filename, list);
++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged);
++}
++
++void CToolPalettize::slotMapSelectionChanged()
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++ slotSomethingChanged();
++}
++
++void CToolPalettize::slotSomethingChanged()
++{
++ bool ok = itemList->count() > 0;
++ if(radioSingle->isChecked() && lineSuffix->text().isEmpty())
++ {
++ ok = false;
++ }
++ if(radioCombined->isChecked() && lineFilename->text().isEmpty())
++ {
++ ok = false;
++ }
++
++ pushStart->setEnabled(ok);
++}
++
++void CToolPalettize::buildCmd(QList<CShellCmd>& cmds, const IItem * iitem)
++{
++ inputFileList1->open();
++ QTextStream stream(inputFileList1);
++ stream << iitem->getFilename() << endl;
++ inputFileList1->close();
++}
++
++void CToolPalettize::buildCmdFinal(QList<CShellCmd>& cmds)
++{
++ QStringList args;
++
++ // ---- command 1 ----------------------
++ QString vrtFilename = createTempFile("vrt");
++ args.clear();
++ args << vrtFilename;
++ args << "-input_file_list" << inputFileList1->fileName();
++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args);
++
++ // ---- command 2 ----------------------
++ QString pctFilename = createTempFile("vrt");
++ args.clear();
++ args << "--sct" << pctFilename;
++ args << vrtFilename;
++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args);
++
++ // ---- command 2..2 + N ----------------------
++ if(radioCombined->isChecked())
++ {
++ inputFileList2->open();
++ QTextStream stream(inputFileList2);
++
++ const int N = itemList->count();
++ for(int n = 0; n < N; n++)
++ {
++ const IItem * item = dynamic_cast<const IItem*>(itemList->item(n));
++ if(nullptr == item)
++ {
++ continue;
++ }
++ QString inFilename = item->getFilename();
++ QString outFilename = createTempFile("tif");
++
++ stream << outFilename << endl;
++
++ args.clear();
++ args << "--pct" << pctFilename;
++ args << inFilename;
++ args << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args);
++ }
++
++ inputFileList2->close();
++
++ // ---- command 2 + N + 1 ----------------------
++ QString vrtFilename = createTempFile("vrt");
++ args.clear();
++ args << vrtFilename;
++ args << "-input_file_list" << inputFileList2->fileName();
++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args);
++
++ // ---- command 2 + N + 2 ----------------------
++ QString outFilename = lineFilename->text();
++ if(!outFilename.toUpper().endsWith(".TIF"))
++ {
++ outFilename += ".tif";
++ }
++
++ args.clear();
++ args << "-co" << "TILED=YES";
++ args << "-co" << "COMPRESS=LZW";
++ args << vrtFilename;
++ args << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args);
++
++ QString lastOutFilname = outFilename;
++ // ---- command 2 + N + 3 ----------------------
++ if(checkCreateVrt->isChecked())
++ {
++ QFileInfo fi(outFilename);
++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt");
++ args.clear();
++ args << vrtFilename << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args);
++ lastOutFilname = vrtFilename;
++ }
++
++ // ---- command 2 + N + 4 ----------------------
++ groupOverviews->buildCmd(cmds, lastOutFilname, "nearest");
++ }
++ else
++ {
++ // ---- command 3..3*N ----------------------
++ const int N = itemList->count();
++ for(int n = 0; n < N; n++)
++ {
++ const IItem * item = dynamic_cast<const IItem*>(itemList->item(n));
++ if(nullptr == item)
++ {
++ continue;
++ }
++ QString inFilename = item->getFilename();
++ QFileInfo fi(inFilename);
++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix());
++
++ // ---- command n*3 ----------------------
++ args.clear();
++ args << "--pct" << pctFilename;
++ args << inFilename;
++ args << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getQmtrgb2pct(), args);
++
++ QString lastOutFilname = outFilename;
++ // ---- command n*3 + 1 ----------------------
++ if(checkCreateVrt->isChecked())
++ {
++ QFileInfo fi(outFilename);
++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt");
++ args.clear();
++ args << vrtFilename << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args);
++ lastOutFilname = vrtFilename;
++ }
++
++ // ---- command n*3 + 2 ----------------------
++ groupOverviews->buildCmd(cmds, lastOutFilname, "nearest");
++ }
++ }
++}
++
++void CToolPalettize::slotStart()
++{
++ // reset file with list of input files
++ inputFileList1->open();
++ inputFileList1->resize(0);
++ inputFileList1->close();
++
++ start(itemList, true);
++ if(jobId > 0)
++ {
++ itemList->setEnabled(false);
++ pushStart->setEnabled(false);
++ pushCancel->setEnabled(true);
++ }
++}
++
++void CToolPalettize::slotFinished(qint32 id)
++{
++ if(finished(id))
++ {
++ itemList->setEnabled(true);
++ pushStart->setEnabled(true);
++ pushCancel->setEnabled(false);
++ }
++}
+diff --git a/src/qmaptool/tool/CToolPalettize.h b/src/qmaptool/tool/CToolPalettize.h
+new file mode 100644
+index 00000000..d518faf7
+--- /dev/null
++++ b/src/qmaptool/tool/CToolPalettize.h
+@@ -0,0 +1,57 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLPALETTIZE_H
++#define CTOOLPALETTIZE_H
++
++#include "items/IItem.h"
++#include "tool/ITool.h"
++#include "tool/IToolGui.h"
++#include "ui_IToolPalettize.h"
++
++class CToolPalettize : public IToolGui, public ITool, private Ui::IToolPalettize
++{
++ Q_OBJECT
++public:
++ CToolPalettize(QWidget * parent);
++ virtual ~CToolPalettize();
++
++ void setupChanged() override;
++
++ FORWARD_LIST_ALL(itemList)
++
++private slots:
++ void slotAddItem(const QString& filename, QListWidget * list);
++ void slotMapSelectionChanged();
++ void slotSomethingChanged();
++ void slotStart();
++ void slotFinished(qint32 id);
++
++ void slotSelectFilename();
++
++private:
++ void buildCmd(QList<CShellCmd>& cmds, const IItem * iitem) override;
++ void buildCmdFinal(QList<CShellCmd>& cmds) override;
++
++ //QStringList inputFiles;
++ QTemporaryFile * inputFileList1;
++ QTemporaryFile * inputFileList2;
++};
++
++#endif //CTOOLPALETTIZE_H
++
+diff --git a/src/qmaptool/tool/CToolRefMap.cpp b/src/qmaptool/tool/CToolRefMap.cpp
+new file mode 100644
+index 00000000..5b1b87b4
+--- /dev/null
++++ b/src/qmaptool/tool/CToolRefMap.cpp
+@@ -0,0 +1,257 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "CMainWindow.h"
++#include "CToolRefMap.h"
++#include "helpers/CSettings.h"
++#include "items/CItemRefMap.h"
++#include "overlay/refmap/COverlayRefMapPoint.h"
++#include "setup/IAppSetup.h"
++#include "shell/CShell.h"
++
++#include <proj_api.h>
++
++CToolRefMap::CToolRefMap(QWidget *parent)
++ : IToolGui(parent)
++{
++ setupUi(this);
++ setObjectName(tr("Reference Map"));
++
++ labelHelp->setText(tr("A scan of a paper map can be converted to a referenced raster map if "
++ "you place at least three reference points on the map. The more points "
++ "the better the result. If your map has a grid you can place points on "
++ "that grid with the grid tool."));
++
++ labelHelp->setVisible(CMainWindow::self().showToolHelp()->isChecked());
++ connect(CMainWindow::self().showToolHelp(), &QAction::toggled, labelHelp, &QLabel::setVisible);
++
++ connect(itemList, &CItemListWidget::sigAddItem, this, &CToolRefMap::slotAddItem);
++ connect(itemList, &CItemListWidget::sigSelectionChanged, this, &CToolRefMap::slotMapSelectionChanged);
++ connect(itemList, &CItemListWidget::sigChanged, this, &CToolRefMap::slotSomethingChanged);
++
++ connect(lineSuffix, &QLineEdit::textChanged, this, &CToolRefMap::slotSomethingChanged);
++
++ connect(pushStart, &QPushButton::clicked, this, &CToolRefMap::slotStart);
++ connect(pushCancel, &QPushButton::clicked, &CShell::self(), &CShell::slotCancel);
++ connect(&CShell::self(), &CShell::sigFinishedJob, this, &CToolRefMap::slotFinished);
++
++ setupChanged();
++
++ SETTINGS;
++ cfg.beginGroup("ToolRefMap");
++ itemList->loadSettings(cfg);
++ checkCreateVrt->setChecked(cfg.value("createVrt", false).toBool());
++ groupOverviews->loadSettings(cfg);
++ checkAllFiles->setChecked(cfg.value("allFiles", false).toBool());
++ lineSuffix->setText(cfg.value("suffix","_ref").toString());
++ cfg.endGroup();
++
++ slotSomethingChanged();
++
++ adjustSize();
++}
++
++CToolRefMap::~CToolRefMap()
++{
++ SETTINGS;
++ cfg.beginGroup("ToolRefMap");
++ cfg.remove("");
++ itemList->saveSettings(cfg);
++ cfg.setValue("createVrt", checkCreateVrt->isChecked());
++ groupOverviews->saveSettings(cfg);
++ cfg.setValue("allFiles", checkAllFiles->isChecked());
++ cfg.setValue("suffix", lineSuffix->text());
++ cfg.endGroup();
++}
++
++
++void CToolRefMap::setupChanged()
++{
++ bool hasGdalwarp = !IAppSetup::self().getGdalwarp().isEmpty();
++ labelNoGdalwarp->setVisible(!hasGdalwarp);
++
++ bool hasGdaltranslate = !IAppSetup::self().getGdaltranslate().isEmpty();
++ labelNoGdalTranslate->setVisible(!hasGdaltranslate);
++
++ bool hasGdaladdo = !IAppSetup::self().getGdaladdo().isEmpty();
++ labelNoGdaladdo->setVisible(!hasGdaladdo);
++
++ frame->setVisible(hasGdalwarp && hasGdaltranslate && hasGdaladdo);
++
++ checkCreateVrt->setVisible(!IAppSetup::self().getGdalbuildvrt().isEmpty());
++}
++
++void CToolRefMap::slotAddItem(const QString& filename, QListWidget * list)
++{
++ CItemRefMap * item = new CItemRefMap(filename, stackedWidget, list);
++ connect(item, &CItemFile::sigChanged, itemList, &CItemListWidget::sigChanged);
++}
++
++void CToolRefMap::slotMapSelectionChanged()
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++ slotSomethingChanged();
++}
++
++void CToolRefMap::slotSomethingChanged()
++{
++ IItem * item = itemList->currentItem();
++ if(item != nullptr)
++ {
++ bool ok = item->isOk();
++ if(lineSuffix->text().isEmpty())
++ {
++ ok = false;
++ }
++ pushStart->setEnabled(ok);
++ }
++ else
++ {
++ pushStart->setEnabled(false);
++ }
++}
++
++void CToolRefMap::buildCmd(QList<CShellCmd>& cmds, const IItem *iitem)
++{
++ const CItemRefMap * item = dynamic_cast<const CItemRefMap*>(iitem);
++ if(nullptr == item)
++ {
++ return;
++ }
++
++ projPJ pjsrc = pj_init_plus("+proj=longlat +datum=WGS84 +no_defs");
++ if(pjsrc == nullptr)
++ {
++ return;
++ }
++
++ projPJ pjtar = pj_init_plus(item->getMapProjection().toLatin1());
++ if(pjtar == nullptr)
++ {
++ pj_free(pjsrc);
++ return;
++ }
++
++ // ---- command 1 ----------------------
++ QStringList args;
++ args << "-a_srs" << item->getMapProjection();
++
++ const QList<COverlayRefMapPoint*>& points = item->getRefPoints();
++ for(const COverlayRefMapPoint* pt : points)
++ {
++ qreal lon = pt->getPtRef().x() * DEG_TO_RAD;
++ qreal lat = pt->getPtRef().y() * DEG_TO_RAD;
++ pj_transform(pjsrc, pjtar, 1, 0, &lon, &lat, 0);
++
++ args << "-gcp";
++ args << QString::number(pt->getPtPtx().x());
++ args << QString::number(pt->getPtPtx().y());
++
++ args << QString::number(lon,'f',6);
++ args << QString::number(lat,'f',6);
++ args << "0";
++ }
++
++ QString tmpname1 = createTempFile("tif");
++ QString inFilename = item->getFilename();
++ args << inFilename << tmpname1;
++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args);
++
++ // ---- command 2 ----------------------
++ IDrawContext * context = item->getDrawContext();
++ args.clear();
++ // --- set re-sampling method ---
++ args << "-r";
++ args << (context->is32BitRgb() ? "cubic" : "near");
++ // --- overwrite last output file ---
++ args << "-overwrite";
++ // --- use all CPU cores when possible ---
++ args << "-multi";
++ args << "-wo";
++ args << "NUM_THREADS=ALL_CPUS";
++ // --- define transparent color ---
++ if(context->getRasterBandCount() == 1)
++ {
++ if(!context->getNoData())
++ {
++ // --- use no data value for destination, too ---
++ args << "-dstnodata" << "255";
++ }
++ }
++ else if(context->getRasterBandCount() == 3)
++ {
++ // --- add alpha channel to files with just RGB ---
++ args << "-dstalpha";
++ }
++
++ QString tmpname2 = createTempFile("tif");
++ args << tmpname1 << tmpname2;
++ cmds << CShellCmd(IAppSetup::self().getGdalwarp(), args);
++
++ // ---- command 3 ----------------------
++ QFileInfo fi(inFilename);
++ QString outFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + lineSuffix->text() + "." + fi.suffix());
++
++ args.clear();
++ args << "-co" << "tiled=yes" << "-co" << "compress=deflate";
++ args << tmpname2 << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getGdaltranslate(), args);
++
++ QString lastOutFilname = outFilename;
++ // ---- command 4 ----------------------
++ if(checkCreateVrt->isChecked())
++ {
++ QFileInfo fi(outFilename);
++ QString vrtFilename = fi.absoluteDir().absoluteFilePath(fi.completeBaseName() + ".vrt");
++ args.clear();
++ args << vrtFilename << outFilename;
++ cmds << CShellCmd(IAppSetup::self().getGdalbuildvrt(), args);
++ lastOutFilname = vrtFilename;
++ }
++
++ // ---- command 5 ----------------------
++ groupOverviews->buildCmd(cmds, lastOutFilname, context->is32BitRgb() ? "cubic" : "nearest");
++
++ pj_free(pjsrc);
++ pj_free(pjtar);
++}
++
++void CToolRefMap::slotStart()
++{
++ start(itemList, checkAllFiles->isChecked());
++ if(jobId > 0)
++ {
++ itemList->setEnabled(false);
++ frameInput->setEnabled(false);
++ pushStart->setEnabled(false);
++ pushCancel->setEnabled(true);
++ }
++}
++
++void CToolRefMap::slotFinished(qint32 id)
++{
++ if(finished(id))
++ {
++ itemList->setEnabled(true);
++ frameInput->setEnabled(true);
++ pushStart->setEnabled(true);
++ pushCancel->setEnabled(false);
++ }
++}
++
+diff --git a/src/qmaptool/tool/CToolRefMap.h b/src/qmaptool/tool/CToolRefMap.h
+new file mode 100644
+index 00000000..2f009b34
+--- /dev/null
++++ b/src/qmaptool/tool/CToolRefMap.h
+@@ -0,0 +1,52 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLREFMAP_H
++#define CTOOLREFMAP_H
++
++#include "items/IItem.h"
++#include "tool/ITool.h"
++#include "tool/IToolGui.h"
++#include "ui_IToolRefMap.h"
++
++
++class CToolRefMap : public IToolGui, public ITool, private Ui::IToolRefMap
++{
++ Q_OBJECT
++public:
++ CToolRefMap(QWidget * parent);
++ virtual ~CToolRefMap();
++
++ void setupChanged() override;
++
++ FORWARD_LIST_ALL(itemList)
++
++
++private slots:
++ void slotAddItem(const QString& filename, QListWidget * list);
++ void slotMapSelectionChanged();
++ void slotSomethingChanged();
++ void slotStart();
++ void slotFinished(qint32 id);
++
++private:
++ void buildCmd(QList<CShellCmd>& cmds, const IItem * iitem) override;
++};
++
++#endif //CTOOLREFMAP_H
++
+diff --git a/src/qmaptool/tool/CToolStack.cpp b/src/qmaptool/tool/CToolStack.cpp
+new file mode 100644
+index 00000000..47cc916d
+--- /dev/null
++++ b/src/qmaptool/tool/CToolStack.cpp
+@@ -0,0 +1,44 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "tool/CToolStack.h"
++
++CToolStack::CToolStack(QWidget * parent)
++ : QStackedWidget(parent)
++{
++ connect(this, &CToolStack::currentChanged, this, &CToolStack::slotToolChanged);
++}
++
++void CToolStack::setupChanged()
++{
++ const int N = count();
++ for(int n = 0; n < N; n++)
++ {
++ ITool * tool = dynamic_cast<ITool*>(widget(n));
++ if(nullptr != tool)
++ {
++ tool->setupChanged();
++ }
++ }
++}
++
++void CToolStack::slotToolChanged(int idx)
++{
++ CMainWindow::self().getCanvas()->slotTriggerCompleteUpdate(CCanvas::eRedrawAll);
++}
+diff --git a/src/qmaptool/tool/CToolStack.h b/src/qmaptool/tool/CToolStack.h
+new file mode 100644
+index 00000000..f0af7d28
+--- /dev/null
++++ b/src/qmaptool/tool/CToolStack.h
+@@ -0,0 +1,41 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLSTACK_H
++#define CTOOLSTACK_H
++
++
++#include "tool/ITool.h"
++#include <QStackedWidget>
++
++class CToolStack : public ITool, public QStackedWidget
++{
++public:
++ CToolStack(QWidget * parent);
++ virtual ~CToolStack() = default;
++
++ void setupChanged() override;
++
++ FORWARD_WIDGET_ALL()
++
++private slots:
++ void slotToolChanged(int idx);
++};
++
++#endif //CTOOLSTACK_H
++
+diff --git a/src/qmaptool/tool/ITool.cpp b/src/qmaptool/tool/ITool.cpp
+new file mode 100644
+index 00000000..157c999a
+--- /dev/null
++++ b/src/qmaptool/tool/ITool.cpp
+@@ -0,0 +1,20 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "tool/ITool.h"
++
+diff --git a/src/qmaptool/tool/ITool.h b/src/qmaptool/tool/ITool.h
+new file mode 100644
+index 00000000..b2c43672
+--- /dev/null
++++ b/src/qmaptool/tool/ITool.h
+@@ -0,0 +1,234 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef ITOOL_H
++#define ITOOL_H
++
++#include "canvas/CCanvas.h"
++#include "setup/IAppSetup.h"
++#include "shell/CShellCmd.h"
++#include <QCursor>
++#include <QWidget>
++class QPainter;
++class QMouseEvent;
++class QWheelEvent;
++class QEvent;
++class CItemListWidget;
++class IItem;
++
++#define FORWARD_WIDGET_VOID(cmd) \
++ ITool * tool = dynamic_cast<ITool*>(currentWidget()); \
++ if(nullptr != tool) \
++ { \
++ tool->cmd; \
++ } \
++
++#define FORWARD_WIDGET_RETURN(cmd, def) \
++ ITool * tool = dynamic_cast<ITool*>(currentWidget()); \
++ if(nullptr != tool) \
++ { \
++ return tool->cmd; \
++ } \
++ return def; \
++
++#define FORWARD_WIDGET_ALL() \
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \
++ { \
++ FORWARD_WIDGET_RETURN(drawFx(p, needsRedraw), false) \
++ } \
++ void mousePressEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(mousePressEventFx(e)) \
++ } \
++ void mouseMoveEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(mouseMoveEventFx(e)) \
++ } \
++ void mouseReleaseEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(mouseReleaseEventFx(e)) \
++ } \
++ void mouseDoubleClickEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(mouseDoubleClickEventFx(e)) \
++ } \
++ void wheelEventFx(QWheelEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(wheelEventFx(e)) \
++ } \
++ void enterEventFx(QEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(enterEventFx(e)) \
++ } \
++ void leaveEventFx(QEvent *e) override \
++ { \
++ FORWARD_WIDGET_VOID(leaveEventFx(e)) \
++ } \
++ QCursor getCursorFx() override \
++ { \
++ FORWARD_WIDGET_RETURN(getCursorFx(), Qt::ArrowCursor) \
++ } \
++ bool keyPressEventFx(QKeyEvent * e) override \
++ { \
++ FORWARD_WIDGET_RETURN(keyPressEventFx(e), false) \
++ } \
++
++
++#define FORWARD_LIST_VOID(list, cmd) \
++ ITool * tool = dynamic_cast<ITool*>(list->currentItem()); \
++ if(nullptr != tool) \
++ { \
++ tool->cmd; \
++ } \
++
++#define FORWARD_LIST_RETURN(list, cmd, def) \
++ ITool * tool = dynamic_cast<ITool*>(list->currentItem()); \
++ if(nullptr != tool) \
++ { \
++ return tool->cmd; \
++ } \
++ return def; \
++
++
++#define FORWARD_LIST_ALL(list) \
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \
++ { \
++ FORWARD_LIST_RETURN(list, drawFx(p, needsRedraw), false) \
++ } \
++ void mousePressEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, mousePressEventFx(e)) \
++ } \
++ void mouseMoveEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, mouseMoveEventFx(e)) \
++ } \
++ void mouseReleaseEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, mouseReleaseEventFx(e)) \
++ } \
++ void mouseDoubleClickEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, mouseDoubleClickEventFx(e)) \
++ } \
++ void wheelEventFx(QWheelEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, wheelEventFx(e)) \
++ } \
++ void enterEventFx(QEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, enterEventFx(e)) \
++ } \
++ void leaveEventFx(QEvent *e) override \
++ { \
++ FORWARD_LIST_VOID(list, leaveEventFx(e)) \
++ } \
++ QCursor getCursorFx() override \
++ { \
++ FORWARD_LIST_RETURN(list, getCursorFx(), Qt::ArrowCursor) \
++ } \
++ bool keyPressEventFx(QKeyEvent * e) override \
++ { \
++ FORWARD_LIST_RETURN(list, keyPressEventFx(e), false) \
++ } \
++
++#define FORWARD_TREE_VOID(tree, cmd) \
++ ITool * tool = dynamic_cast<ITool*>(tree->currentItem()); \
++ if(nullptr != tool) \
++ { \
++ tool->cmd; \
++ } \
++
++#define FORWARD_TREE_RETURN(tree, cmd, def) \
++ ITool * tool = dynamic_cast<ITool*>(tree->currentItem()); \
++ if(nullptr != tool) \
++ { \
++ return tool->cmd; \
++ } \
++ return def; \
++
++#define FORWARD_TREE_ALL(tree) \
++ bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) override \
++ { \
++ return tree->drawFx(p, needsRedraw); \
++ } \
++ void mousePressEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, mousePressEventFx(e)) \
++ } \
++ void mouseMoveEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, mouseMoveEventFx(e)) \
++ } \
++ void mouseReleaseEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, mouseReleaseEventFx(e)) \
++ } \
++ void mouseDoubleClickEventFx(QMouseEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, mouseDoubleClickEventFx(e)) \
++ } \
++ void wheelEventFx(QWheelEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, wheelEventFx(e)) \
++ } \
++ void enterEventFx(QEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, enterEventFx(e)) \
++ } \
++ void leaveEventFx(QEvent *e) override \
++ { \
++ FORWARD_TREE_VOID(tree, leaveEventFx(e)) \
++ } \
++ QCursor getCursorFx() override \
++ { \
++ FORWARD_TREE_RETURN(tree, getCursorFx(), Qt::ArrowCursor) \
++ } \
++ bool keyPressEventFx(QKeyEvent * e) override \
++ { \
++ FORWARD_TREE_RETURN(tree, keyPressEventFx(e), false) \
++ } \
++
++class ITool
++{
++public:
++ ITool()
++ {
++ }
++ virtual ~ITool() = default;
++
++ virtual bool drawFx(QPainter& p, CCanvas::redraw_e needsRedraw) = 0;
++ virtual void setupChanged() = 0;
++
++ virtual void mousePressEventFx(QMouseEvent *e) {}
++ virtual void mouseMoveEventFx(QMouseEvent *e){}
++ virtual void mouseReleaseEventFx(QMouseEvent *e){}
++ virtual void mouseDoubleClickEventFx(QMouseEvent *e){}
++ virtual void wheelEventFx(QWheelEvent *e){}
++ virtual void enterEventFx(QEvent *e){}
++ virtual void leaveEventFx(QEvent *e){}
++ virtual bool keyPressEventFx(QKeyEvent *e){return false; }
++
++ virtual QCursor getCursorFx()
++ {
++ return Qt::ArrowCursor;
++ }
++};
++
++#endif //ITOOL_H
++
+diff --git a/src/qmaptool/tool/IToolAddOverview.ui b/src/qmaptool/tool/IToolAddOverview.ui
+new file mode 100644
+index 00000000..346fb216
+--- /dev/null
++++ b/src/qmaptool/tool/IToolAddOverview.ui
+@@ -0,0 +1,278 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolAddOverview</class>
++ <widget class="QWidget" name="IToolAddOverview">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>601</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_3">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>3</number>
++ </property>
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="rightMargin">
++ <number>3</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="textFormat">
++ <enum>Qt::RichText</enum>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CItemListWidget" name="itemList" native="true"/>
++ </item>
++ <item>
++ <widget class="QFrame" name="frameInput">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <layout class="QFormLayout" name="formLayout">
++ <item row="0" column="1">
++ <widget class="QFrame" name="frameLevels">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QCheckBox" name="checkBy2">
++ <property name="text">
++ <string>:2</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy4">
++ <property name="text">
++ <string>:4</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy8">
++ <property name="text">
++ <string>:8</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy16">
++ <property name="text">
++ <string>:16</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy32">
++ <property name="text">
++ <string>:32</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy64">
++ <property name="text">
++ <string>:64</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item row="2" column="1">
++ <widget class="QCheckBox" name="checkRemove">
++ <property name="toolTip">
++ <string>Remove all overview levels from map file.</string>
++ </property>
++ <property name="text">
++ <string>Remove</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QCheckBox" name="checkExternal">
++ <property name="toolTip">
++ <string>Do not copy the overviews into the file itself. Add them as external file.</string>
++ </property>
++ <property name="text">
++ <string>Overview as external file</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>0</width>
++ <height>0</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_3">
++ <item>
++ <widget class="QPushButton" name="pushStart">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkAllFiles">
++ <property name="text">
++ <string>For all files</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdaladdo">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CItemListWidget</class>
++ <extends>QWidget</extends>
++ <header>items/CItemListWidget.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolCutMap.ui b/src/qmaptool/tool/IToolCutMap.ui
+new file mode 100644
+index 00000000..75f9b23d
+--- /dev/null
++++ b/src/qmaptool/tool/IToolCutMap.ui
+@@ -0,0 +1,263 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolCutMap</class>
++ <widget class="QWidget" name="IToolCutMap">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>340</width>
++ <height>610</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_4">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="textFormat">
++ <enum>Qt::RichText</enum>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CItemListWidget" name="itemList" native="true"/>
++ </item>
++ <item>
++ <widget class="QFrame" name="frameInput">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QStackedWidget" name="stackedWidget">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Output filename suffix</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineSuffix">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>_cut</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="CToolOverviewGroupBox" name="groupOverviews">
++ <property name="title">
++ <string>Create overviews for result.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>0</width>
++ <height>0</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QPushButton" name="pushStart">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkAllFiles">
++ <property name="text">
++ <string>For all files</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdalwarp">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdaladdo">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CItemListWidget</class>
++ <extends>QWidget</extends>
++ <header>items/CItemListWidget.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CToolOverviewGroupBox</class>
++ <extends>QGroupBox</extends>
++ <header>tool/CToolOverviewGroupBox.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolExport.ui b/src/qmaptool/tool/IToolExport.ui
+new file mode 100644
+index 00000000..89e2cfd5
+--- /dev/null
++++ b/src/qmaptool/tool/IToolExport.ui
+@@ -0,0 +1,206 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolExport</class>
++ <widget class="QWidget" name="IToolExport">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>332</width>
++ <height>346</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CItemTreeWidget" name="itemTree" native="true"/>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNote">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QComboBox" name="comboExport">
++ <item>
++ <property name="text">
++ <string>Garmin BirdsEye (*.jnx)</string>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>TwoNav Raster (*.rmap)</string>
++ </property>
++ </item>
++ </widget>
++ </item>
++ <item>
++ <widget class="QStackedWidget" name="stackedWidget">
++ <widget class="CToolExportJnx" name="pageBirdsEyeJnx"/>
++ <widget class="QWidget" name="pageTwoNavRmap">
++ <layout class="QVBoxLayout" name="verticalLayout_3">
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>not implemented yet</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>Target File</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineTragetFile"/>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QPushButton" name="pushStart">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoMap2jnx">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;qmt_map2jnx&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ <action name="actionTargetFilename">
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ <property name="text">
++ <string>Target Filename</string>
++ </property>
++ </action>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CToolExportJnx</class>
++ <extends>QWidget</extends>
++ <header>tool/export/CToolExportJnx.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CItemTreeWidget</class>
++ <extends>QWidget</extends>
++ <header>items/CItemTreeWidget.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolGrid.ui b/src/qmaptool/tool/IToolGrid.ui
+new file mode 100644
+index 00000000..3a79eaa5
+--- /dev/null
++++ b/src/qmaptool/tool/IToolGrid.ui
+@@ -0,0 +1,158 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolGrid</class>
++ <widget class="QWidget" name="IToolGrid">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>300</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>6</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Minimum">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <property name="pixmap">
++ <pixmap resource="../resources.qrc">:/icons/32x32/GridTool.png</pixmap>
++ </property>
++ <property name="scaledContents">
++ <bool>false</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Grid Tool</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="textFormat">
++ <enum>Qt::AutoText</enum>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="COverlayGridTool" name="overlay" native="true"/>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>226</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QPushButton" name="pushOk">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Ok</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Check.png</normaloff>:/icons/32x32/Check.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushReset">
++ <property name="text">
++ <string>Reset</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Reload.png</normaloff>:/icons/32x32/Reload.png</iconset>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>COverlayGridTool</class>
++ <extends>QWidget</extends>
++ <header>overlay/COverlayGridTool.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolGui.cpp b/src/qmaptool/tool/IToolGui.cpp
+new file mode 100644
+index 00000000..fe3f5d8e
+--- /dev/null
++++ b/src/qmaptool/tool/IToolGui.cpp
+@@ -0,0 +1,111 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "canvas/IDrawContext.h"
++#include "items/CItemListWidget.h"
++#include "items/CItemMapLayer.h"
++#include "items/CItemTreeWidget.h"
++#include "items/IItem.h"
++#include "shell/CShell.h"
++#include "tool/IToolGui.h"
++
++IToolGui::IToolGui(QWidget * parent)
++ : QWidget(parent)
++{
++}
++
++QString IToolGui::createTempFile(const QString& ext)
++{
++ QTemporaryFile * tmpFile = new QTemporaryFile(QDir::temp().absoluteFilePath("QMapTool_XXXXXX." + ext));
++ tmpFile->open();
++ tmpFile->close();
++ tmpFiles << tmpFile;
++
++ return tmpFile->fileName();
++}
++
++bool IToolGui::finished(qint32 id)
++{
++ if(id == jobId)
++ {
++ jobId = 0;
++ qDeleteAll(tmpFiles);
++ tmpFiles.clear();
++ return true;
++ }
++ return false;
++}
++
++
++void IToolGui::start(CItemTreeWidget * itemTree)
++{
++ QList<CShellCmd> cmds;
++ const int N = itemTree->topLevelItemCount();
++ for(int n = 0; n < N; n++)
++ {
++ const CItemMapLayer * layer = dynamic_cast<CItemMapLayer*>(itemTree->topLevelItem(n));
++ if(layer == nullptr)
++ {
++ continue;
++ }
++ const int M = layer->childCount();
++ for(int m = 0; m < M; m++)
++ {
++ IItem * item = dynamic_cast<IItem*>(layer->child(m));
++ if(nullptr != item)
++ {
++ buildCmd(cmds, item);
++ }
++ }
++ }
++
++ buildCmdFinal(cmds);
++
++ jobId = CShell::self().execute(cmds);
++}
++
++void IToolGui::start(CItemListWidget * itemList, bool allFiles)
++{
++ QList<CShellCmd> cmds;
++
++ if(allFiles)
++ {
++ const int N = itemList->count();
++ for(int n = 0; n < N; n++)
++ {
++ const IItem * item = dynamic_cast<const IItem*>(itemList->item(n));
++ if(nullptr != item)
++ {
++ buildCmd(cmds, item);
++ }
++ }
++ }
++ else
++ {
++ const IItem * item = dynamic_cast<const IItem*>(itemList->currentItem());
++ if(nullptr != item)
++ {
++ buildCmd(cmds, item);
++ }
++ }
++
++ buildCmdFinal(cmds);
++
++ jobId = CShell::self().execute(cmds);
++}
++
+diff --git a/src/qmaptool/tool/IToolGui.h b/src/qmaptool/tool/IToolGui.h
+new file mode 100644
+index 00000000..00432901
+--- /dev/null
++++ b/src/qmaptool/tool/IToolGui.h
+@@ -0,0 +1,48 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef ITOOLGUI_H
++#define ITOOLGUI_H
++
++#include <QWidget>
++
++class CItemListWidget;
++class CItemTreeWidget;
++
++class IToolGui : public QWidget
++{
++ Q_OBJECT
++public:
++ IToolGui(QWidget * parent);
++ virtual ~IToolGui() = default;
++
++
++protected:
++ virtual void start(CItemListWidget * itemList, bool allFiles);
++ virtual void start(CItemTreeWidget * itemTree);
++ virtual bool finished(qint32 id);
++ virtual void buildCmd(QList<CShellCmd>& cmds, const IItem * iitem) = 0;
++ virtual void buildCmdFinal(QList<CShellCmd>& cmds){}
++
++ QString createTempFile(const QString &ext);
++ qint32 jobId = 0;
++ QList<QTemporaryFile*> tmpFiles;
++};
++
++#endif //ITOOLGUI_H
++
+diff --git a/src/qmaptool/tool/IToolOverviewGroupBox.ui b/src/qmaptool/tool/IToolOverviewGroupBox.ui
+new file mode 100644
+index 00000000..c127a786
+--- /dev/null
++++ b/src/qmaptool/tool/IToolOverviewGroupBox.ui
+@@ -0,0 +1,130 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolOverviewGroupBox</class>
++ <widget class="QGroupBox" name="IToolOverviewGroupBox">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>96</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>GroupBox</string>
++ </property>
++ <property name="flat">
++ <bool>false</bool>
++ </property>
++ <property name="checkable">
++ <bool>true</bool>
++ </property>
++ <property name="checked">
++ <bool>true</bool>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>9</number>
++ </property>
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="rightMargin">
++ <number>9</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frameOverviews">
++ <property name="enabled">
++ <bool>true</bool>
++ </property>
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Raised</enum>
++ </property>
++ <layout class="QHBoxLayout" name="horizontalLayout_4">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QCheckBox" name="checkBy2">
++ <property name="text">
++ <string>:2</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy4">
++ <property name="text">
++ <string>:4</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy8">
++ <property name="text">
++ <string>:8</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy16">
++ <property name="text">
++ <string>:16</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy32">
++ <property name="text">
++ <string>:32</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkBy64">
++ <property name="text">
++ <string>:64</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkExternal">
++ <property name="enabled">
++ <bool>true</bool>
++ </property>
++ <property name="toolTip">
++ <string>Do not copy the overviews into the file itself. Add them as external file.</string>
++ </property>
++ <property name="text">
++ <string>Overview as external file</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolPalettize.ui b/src/qmaptool/tool/IToolPalettize.ui
+new file mode 100644
+index 00000000..b9131bde
+--- /dev/null
++++ b/src/qmaptool/tool/IToolPalettize.ui
+@@ -0,0 +1,269 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolPalettize</class>
++ <widget class="QWidget" name="IToolPalettize">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>399</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CItemListWidget" name="itemList" native="true"/>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNote">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QRadioButton" name="radioSingle">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Single files, filename suffix</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineSuffix">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>_8bit</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <layout class="QVBoxLayout" name="verticalLayout_3">
++ <item>
++ <widget class="QRadioButton" name="radioCombined">
++ <property name="text">
++ <string>Combined file, filename:</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineFilename"/>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkCreateVrt">
++ <property name="text">
++ <string>Embed result into *.vrt file.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CToolOverviewGroupBox" name="groupOverviews">
++ <property name="title">
++ <string>Create overviews for result.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QPushButton" name="pushStart">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer_2">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdaladdo">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdaltranslate">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoQmtrgb2pct">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;qmt_rgb2pct&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ <action name="actionFilename">
++ <property name="icon">
++ <iconset resource="../../qmapshack/resources.qrc">
++ <normaloff>:/icons/32x32/PathBlue.png</normaloff>:/icons/32x32/PathBlue.png</iconset>
++ </property>
++ <property name="text">
++ <string>Select filename</string>
++ </property>
++ </action>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CItemListWidget</class>
++ <extends>QWidget</extends>
++ <header>items/CItemListWidget.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CToolOverviewGroupBox</class>
++ <extends>QGroupBox</extends>
++ <header>tool/CToolOverviewGroupBox.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../../qmapshack/resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/IToolRefMap.ui b/src/qmaptool/tool/IToolRefMap.ui
+new file mode 100644
+index 00000000..9218f5fc
+--- /dev/null
++++ b/src/qmaptool/tool/IToolRefMap.ui
+@@ -0,0 +1,276 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolRefMap</class>
++ <widget class="QWidget" name="IToolRefMap">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>596</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_4">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QFrame" name="frame">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_3">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QLabel" name="labelHelp">
++ <property name="text">
++ <string>do not translate</string>
++ </property>
++ <property name="textFormat">
++ <enum>Qt::RichText</enum>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CItemListWidget" name="itemList" native="true"/>
++ </item>
++ <item>
++ <widget class="QFrame" name="frameInput">
++ <property name="frameShape">
++ <enum>QFrame::NoFrame</enum>
++ </property>
++ <property name="frameShadow">
++ <enum>QFrame::Plain</enum>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <property name="spacing">
++ <number>0</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QStackedWidget" name="stackedWidget"/>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_3">
++ <item>
++ <widget class="QLabel" name="label_2">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>Output filename suffix</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLineEdit" name="lineSuffix">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>_ref</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignCenter</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkCreateVrt">
++ <property name="text">
++ <string>Embed result into *.vrt file.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="CToolOverviewGroupBox" name="groupOverviews">
++ <property name="title">
++ <string>Create overviews for result.</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <item>
++ <widget class="QPushButton" name="pushStart">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Start</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Apply.png</normaloff>:/icons/32x32/Apply.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QPushButton" name="pushCancel">
++ <property name="enabled">
++ <bool>false</bool>
++ </property>
++ <property name="text">
++ <string>Cancel</string>
++ </property>
++ <property name="icon">
++ <iconset resource="../resources.qrc">
++ <normaloff>:/icons/32x32/Cancel.png</normaloff>:/icons/32x32/Cancel.png</iconset>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QCheckBox" name="checkAllFiles">
++ <property name="text">
++ <string>For all files</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer_2">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdalwarp">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdalwarp&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdalTranslate">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdal_translate&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QLabel" name="labelNoGdaladdo">
++ <property name="text">
++ <string>&lt;b style='color: red;'&gt;No &quot;gdaladdo&quot; found. Please check setup!&lt;/b&gt;</string>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <customwidgets>
++ <customwidget>
++ <class>CItemListWidget</class>
++ <extends>QWidget</extends>
++ <header>items/CItemListWidget.h</header>
++ <container>1</container>
++ </customwidget>
++ <customwidget>
++ <class>CToolOverviewGroupBox</class>
++ <extends>QGroupBox</extends>
++ <header>tool/CToolOverviewGroupBox.h</header>
++ <container>1</container>
++ </customwidget>
++ </customwidgets>
++ <resources>
++ <include location="../resources.qrc"/>
++ </resources>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/tool/export/CToolExportJnx.cpp b/src/qmaptool/tool/export/CToolExportJnx.cpp
+new file mode 100644
+index 00000000..5fbe48ce
+--- /dev/null
++++ b/src/qmaptool/tool/export/CToolExportJnx.cpp
+@@ -0,0 +1,28 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "tool/export/CToolExportJnx.h"
++
++#include <QtWidgets>
++
++CToolExportJnx::CToolExportJnx()
++{
++ setupUi(this);
++}
++
++
+diff --git a/src/qmaptool/tool/export/CToolExportJnx.h b/src/qmaptool/tool/export/CToolExportJnx.h
+new file mode 100644
+index 00000000..f1bb6619
+--- /dev/null
++++ b/src/qmaptool/tool/export/CToolExportJnx.h
+@@ -0,0 +1,68 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTOOLEXPORTJNX_H
++#define CTOOLEXPORTJNX_H
++
++#include "ui_IToolExportJnx.h"
++
++class CToolExportJnx : public QWidget, private Ui::IToolExportJnx
++{
++ Q_OBJECT
++public:
++ CToolExportJnx();
++ virtual ~CToolExportJnx() = default;
++
++ QString getProductName() const
++ {
++ return lineProductName->text();
++ }
++
++ QString getDescription() const
++ {
++ return lineDescription->text();
++ }
++
++ QString getCopyright() const
++ {
++ return lineCopyrightNotice->text();
++ }
++
++ QString getProductId() const
++ {
++ return QString::number(spinProductId->value());
++ }
++
++ QString getJpegQuality() const
++ {
++ return QString::number(spinJpegQuality->value());
++ }
++
++ QString getJpegSubsampling() const
++ {
++ return comboJpegSubSampling->currentText();
++ }
++
++ QString getZOrder() const
++ {
++ return QString::number(spinZOrder->value());
++ }
++};
++
++#endif //CTOOLEXPORTJNX_H
++
+diff --git a/src/qmaptool/tool/export/IToolExportJnx.ui b/src/qmaptool/tool/export/IToolExportJnx.ui
+new file mode 100644
+index 00000000..29ab36f6
+--- /dev/null
++++ b/src/qmaptool/tool/export/IToolExportJnx.ui
+@@ -0,0 +1,224 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IToolExportJnx</class>
++ <widget class="QWidget" name="IToolExportJnx">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>400</width>
++ <height>321</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Form</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <property name="spacing">
++ <number>3</number>
++ </property>
++ <property name="leftMargin">
++ <number>0</number>
++ </property>
++ <property name="topMargin">
++ <number>0</number>
++ </property>
++ <property name="rightMargin">
++ <number>0</number>
++ </property>
++ <property name="bottomMargin">
++ <number>0</number>
++ </property>
++ <item>
++ <widget class="QGroupBox" name="groupBox">
++ <property name="title">
++ <string>BirdsEye</string>
++ </property>
++ <layout class="QGridLayout" name="gridLayout">
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <property name="verticalSpacing">
++ <number>3</number>
++ </property>
++ <item row="3" column="0">
++ <widget class="QLabel" name="labelProductId">
++ <property name="text">
++ <string>Product ID</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="0">
++ <widget class="QLabel" name="label_2">
++ <property name="text">
++ <string>Copyright notice</string>
++ </property>
++ </widget>
++ </item>
++ <item row="2" column="1">
++ <widget class="QLineEdit" name="lineCopyrightNotice">
++ <property name="text">
++ <string>None</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Product name</string>
++ </property>
++ </widget>
++ </item>
++ <item row="3" column="1">
++ <widget class="QSpinBox" name="spinProductId"/>
++ </item>
++ <item row="0" column="1">
++ <widget class="QLineEdit" name="lineProductName">
++ <property name="text">
++ <string>BirdsEye</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_6">
++ <property name="text">
++ <string>Description</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QLineEdit" name="lineDescription">
++ <property name="text">
++ <string>None</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QGroupBox" name="groupBox_2">
++ <property name="title">
++ <string>JPEG</string>
++ </property>
++ <layout class="QGridLayout" name="gridLayout_2">
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <property name="verticalSpacing">
++ <number>3</number>
++ </property>
++ <item row="0" column="1">
++ <widget class="QSpinBox" name="spinJpegQuality">
++ <property name="minimum">
++ <number>1</number>
++ </property>
++ <property name="maximum">
++ <number>100</number>
++ </property>
++ <property name="value">
++ <number>75</number>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label_3">
++ <property name="text">
++ <string>Quality</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="0">
++ <widget class="QLabel" name="label_4">
++ <property name="text">
++ <string>Chroma subsampling</string>
++ </property>
++ </widget>
++ </item>
++ <item row="1" column="1">
++ <widget class="QComboBox" name="comboJpegSubSampling">
++ <item>
++ <property name="text">
++ <string>411</string>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>422</string>
++ </property>
++ </item>
++ <item>
++ <property name="text">
++ <string>444</string>
++ </property>
++ </item>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <widget class="QGroupBox" name="groupBox_3">
++ <property name="title">
++ <string>Device</string>
++ </property>
++ <layout class="QGridLayout" name="gridLayout_3">
++ <property name="topMargin">
++ <number>3</number>
++ </property>
++ <property name="bottomMargin">
++ <number>3</number>
++ </property>
++ <property name="verticalSpacing">
++ <number>3</number>
++ </property>
++ <item row="0" column="0">
++ <widget class="QLabel" name="label_5">
++ <property name="text">
++ <string>Z-Order</string>
++ </property>
++ </widget>
++ </item>
++ <item row="0" column="1">
++ <widget class="QSpinBox" name="spinZOrder">
++ <property name="minimum">
++ <number>10</number>
++ </property>
++ <property name="maximum">
++ <number>100</number>
++ </property>
++ <property name="singleStep">
++ <number>10</number>
++ </property>
++ <property name="value">
++ <number>50</number>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections/>
++</ui>
+diff --git a/src/qmaptool/units/CCoordFormatSetup.cpp b/src/qmaptool/units/CCoordFormatSetup.cpp
+new file mode 100644
+index 00000000..69c7be3c
+--- /dev/null
++++ b/src/qmaptool/units/CCoordFormatSetup.cpp
+@@ -0,0 +1,67 @@
++/**********************************************************************************************
++ Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "units/CCoordFormatSetup.h"
++#include "units/IUnit.h"
++
++CCoordFormatSetup::CCoordFormatSetup(QWidget * parent)
++ : QDialog(parent)
++{
++ setupUi(this);
++
++ IUnit::coord_format_e coordFormat = IUnit::getCoordFormat();
++ switch(coordFormat)
++ {
++ case IUnit::eCoordFormat1:
++ radioFormat1->setChecked(true);
++ break;
++
++ case IUnit::eCoordFormat2:
++ radioFormat2->setChecked(true);
++ break;
++
++ case IUnit::eCoordFormat3:
++ radioFormat3->setChecked(true);
++ break;
++ }
++}
++
++CCoordFormatSetup::~CCoordFormatSetup()
++{
++}
++
++void CCoordFormatSetup::accept()
++{
++ IUnit::coord_format_e coordFormat = IUnit::eCoordFormat1;
++
++ if(radioFormat1->isChecked())
++ {
++ coordFormat = IUnit::eCoordFormat1;
++ }
++ else if(radioFormat2->isChecked())
++ {
++ coordFormat = IUnit::eCoordFormat2;
++ }
++ else if(radioFormat3->isChecked())
++ {
++ coordFormat = IUnit::eCoordFormat3;
++ }
++
++ IUnit::setCoordFormat(coordFormat);
++ QDialog::accept();
++}
+diff --git a/src/qmaptool/units/CCoordFormatSetup.h b/src/qmaptool/units/CCoordFormatSetup.h
+new file mode 100644
+index 00000000..0510ae25
+--- /dev/null
++++ b/src/qmaptool/units/CCoordFormatSetup.h
+@@ -0,0 +1,37 @@
++/**********************************************************************************************
++ Copyright (C) 2014-2015 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CCOORDFORMATSETUP_H
++#define CCOORDFORMATSETUP_H
++
++#include "ui_ICoordFormatSetup.h"
++#include <QDialog>
++
++class CCoordFormatSetup : public QDialog, private Ui::ICoordFormatSetup
++{
++ Q_OBJECT
++public:
++ CCoordFormatSetup(QWidget * parent);
++ virtual ~CCoordFormatSetup();
++
++public slots:
++ void accept() override;
++};
++
++#endif //CCOORDFORMATSETUP_H
++
+diff --git a/src/qmaptool/units/CTimeZoneSetup.cpp b/src/qmaptool/units/CTimeZoneSetup.cpp
+new file mode 100644
+index 00000000..d6f849bd
+--- /dev/null
++++ b/src/qmaptool/units/CTimeZoneSetup.cpp
+@@ -0,0 +1,105 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "units/CTimeZoneSetup.h"
++#include "units/IUnit.h"
++
++CTimeZoneSetup::CTimeZoneSetup(QWidget *parent)
++ : QDialog(parent)
++{
++ setupUi(this);
++
++ QByteArray zone;
++ IUnit::tz_mode_e mode;
++ bool useShortFormat;
++
++ IUnit::getTimeZoneSetup(mode, zone, useShortFormat);
++
++ switch(mode)
++ {
++ case IUnit::eTZUtc:
++ radioUtc->setChecked(true);
++ break;
++
++ case IUnit::eTZLocal:
++ radioLocal->setChecked(true);
++ break;
++
++ case IUnit::eTZAuto:
++ radioAutomatic->setChecked(true);
++ break;
++
++ case IUnit::eTZSelected:
++ radioSelected->setChecked(true);
++ break;
++ }
++
++ const char ** tz = IUnit::tblTimezone;
++ while(*tz)
++ {
++ comboTimeZone->addItem(*tz);
++ tz++;
++ }
++
++ if(useShortFormat)
++ {
++ radioShortFormat->setChecked(true);
++ }
++ else
++ {
++ radioLongFormat->setChecked(true);
++ }
++
++ comboTimeZone->setCurrentIndex(comboTimeZone->findText(QString(zone)));
++}
++
++CTimeZoneSetup::~CTimeZoneSetup()
++{
++}
++
++void CTimeZoneSetup::accept()
++{
++ QByteArray zone = comboTimeZone->currentText().toLatin1();
++ IUnit::tz_mode_e mode = IUnit::eTZUtc;
++ bool useShortFormat = false;
++
++ if(radioUtc->isChecked())
++ {
++ mode = IUnit::eTZUtc;
++ }
++ else if(radioLocal->isChecked())
++ {
++ mode = IUnit::eTZLocal;
++ }
++ else if(radioAutomatic->isChecked())
++ {
++ mode = IUnit::eTZAuto;
++ }
++ else if(radioSelected->isChecked())
++ {
++ mode = IUnit::eTZSelected;
++ }
++
++ if(radioShortFormat->isChecked())
++ {
++ useShortFormat = true;
++ }
++
++ IUnit::setTimeZoneSetup(mode, zone, useShortFormat);
++ QDialog::accept();
++}
+diff --git a/src/qmaptool/units/CTimeZoneSetup.h b/src/qmaptool/units/CTimeZoneSetup.h
+new file mode 100644
+index 00000000..aa06ad85
+--- /dev/null
++++ b/src/qmaptool/units/CTimeZoneSetup.h
+@@ -0,0 +1,36 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CTIMEZONESETUP_H
++#define CTIMEZONESETUP_H
++
++#include "ui_ITimeZoneSetup.h"
++#include <QDialog>
++
++class CTimeZoneSetup : public QDialog, private Ui::ITimeZoneSetup
++{
++public:
++ CTimeZoneSetup(QWidget * parent);
++ virtual ~CTimeZoneSetup();
++
++public slots:
++ void accept() override;
++};
++
++#endif //CTIMEZONESETUP_H
++
+diff --git a/src/qmaptool/units/CUnitImperial.cpp b/src/qmaptool/units/CUnitImperial.cpp
+new file mode 100644
+index 00000000..f38c73fb
+--- /dev/null
++++ b/src/qmaptool/units/CUnitImperial.cpp
+@@ -0,0 +1,113 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++
++#include "units/CUnitImperial.h"
++
++const qreal CUnitImperial::footPerMeter = 3.28084;
++const qreal CUnitImperial::milePerMeter = 0.6213699E-3;
++const qreal CUnitImperial::meterPerSecToMilePerHour = 2.23693164;
++
++CUnitImperial::CUnitImperial(QObject * parent)
++ : IUnit(eTypeImperial, "ft", footPerMeter, "ml/h", meterPerSecToMilePerHour, parent)
++{
++}
++
++
++void CUnitImperial::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.0f", meter * footPerMeter);
++ unit = "ft";
++ }
++}
++
++
++void CUnitImperial::meter2distance(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else if(meter < 10)
++ {
++ val.sprintf("%1.1f", meter * footPerMeter);
++ unit = "ft";
++ }
++ else if(meter < 1600)
++ {
++ val.sprintf("%1.0f", meter * footPerMeter);
++ unit = "ft";
++ }
++ else if(meter < 16000)
++ {
++ val.sprintf("%1.2f", meter * milePerMeter);
++ unit = "ml";
++ }
++ else if(meter < 32000)
++ {
++ val.sprintf("%1.1f", meter * milePerMeter);
++ unit = "ml";
++ }
++ else
++ {
++ val.sprintf("%1.0f", meter * milePerMeter);
++ unit = "ml";
++ }
++}
++
++void CUnitImperial::meter2area(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.2f", meter / (1/milePerMeter * 1/milePerMeter));
++ unit = "ml²";
++ }
++}
++
++qreal CUnitImperial::elevation2meter(const QString& val) const /* override */
++{
++ return val.toDouble() / footPerMeter;
++}
++
++void CUnitImperial::meter2unit(qreal meter, qreal& scale, QString& unit) const
++{
++ if(meter > 1600)
++ {
++ scale = milePerMeter;
++ unit = "ml";
++ }
++ else
++ {
++ scale = footPerMeter;
++ unit = "ft";
++ }
++}
++
+diff --git a/src/qmaptool/units/CUnitImperial.h b/src/qmaptool/units/CUnitImperial.h
+new file mode 100644
+index 00000000..e400159d
+--- /dev/null
++++ b/src/qmaptool/units/CUnitImperial.h
+@@ -0,0 +1,41 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#ifndef CUNITIMPERIAL_H
++#define CUNITIMPERIAL_H
++
++#include "IUnit.h"
++
++class CUnitImperial : public IUnit
++{
++public:
++ CUnitImperial(QObject * parent);
++ virtual ~CUnitImperial() = default;
++
++ void meter2elevation(qreal meter, QString& val, QString& unit) const override;
++ void meter2distance(qreal meter, QString& val, QString& unit) const override;
++ void meter2area(qreal meter, QString& val, QString& unit) const override;
++ qreal elevation2meter(const QString& val) const override;
++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override;
++
++private:
++ static const qreal footPerMeter;
++ static const qreal milePerMeter;
++ static const qreal meterPerSecToMilePerHour;
++};
++#endif //CUNITIMPERIAL_H
+diff --git a/src/qmaptool/units/CUnitMetric.cpp b/src/qmaptool/units/CUnitMetric.cpp
+new file mode 100644
+index 00000000..4398eef2
+--- /dev/null
++++ b/src/qmaptool/units/CUnitMetric.cpp
+@@ -0,0 +1,132 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#include "units/CUnitMetric.h"
++
++CUnitMetric::CUnitMetric(QObject * parent)
++ : IUnit(eTypeMetric, "m", 1.0, "km/h", 3.6, parent)
++{
++}
++
++
++void CUnitMetric::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT || meter == NOINT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.0f", meter);
++ unit = "m";
++ }
++}
++
++
++void CUnitMetric::meter2distance(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else if(meter < 10)
++ {
++ val.sprintf("%1.1f", meter);
++ unit = "m";
++ }
++ else if(meter < 1000)
++ {
++ val.sprintf("%1.0f", meter);
++ unit = "m";
++ }
++ else if(meter < 10000)
++ {
++ val.sprintf("%1.2f", meter / 1000);
++ unit = "km";
++ }
++ else if(meter < 20000)
++ {
++ val.sprintf("%1.1f", meter / 1000);
++ unit = "km";
++ }
++ else
++ {
++ val.sprintf("%1.0f", meter / 1000);
++ unit = "km";
++ }
++}
++
++
++void CUnitMetric::meter2speed(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else if (meter < 0.27)
++ {
++ val.sprintf("%1.0f",meter * speedfactor * 1000);
++ unit = "m/h";
++ }
++ else if (meter < 10.0)
++ {
++ val.sprintf("%1.1f",meter * speedfactor);
++ unit = speedunit;
++ }
++ else
++ {
++ val.sprintf("%1.0f",meter * speedfactor);
++ unit = speedunit;
++ }
++}
++
++void CUnitMetric::meter2area(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.2f", meter / 1000000);
++ unit = "km²";
++ }
++}
++
++qreal CUnitMetric::elevation2meter(const QString& val) const /* override */
++{
++ return val.toDouble();
++}
++
++void CUnitMetric::meter2unit(qreal meter, qreal& scale, QString& unit) const
++{
++ if(meter > 1000)
++ {
++ scale = 0.001;
++ unit = "km";
++ }
++ else
++ {
++ scale = 1.0;
++ unit = "m";
++ }
++}
+diff --git a/src/qmaptool/units/CUnitMetric.h b/src/qmaptool/units/CUnitMetric.h
+new file mode 100644
+index 00000000..3f8c74a6
+--- /dev/null
++++ b/src/qmaptool/units/CUnitMetric.h
+@@ -0,0 +1,37 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#ifndef CUNITMETRIC_H
++#define CUNITMETRIC_H
++
++#include "IUnit.h"
++
++class CUnitMetric : public IUnit
++{
++public:
++ CUnitMetric(QObject * parent);
++ virtual ~CUnitMetric() = default;
++
++ void meter2elevation(qreal meter, QString& val, QString& unit) const override;
++ void meter2distance(qreal meter, QString& val, QString& unit) const override;
++ void meter2speed(qreal meter, QString& val, QString& unit) const override;
++ void meter2area(qreal meter, QString& val, QString& unit) const override;
++ qreal elevation2meter(const QString& val) const override;
++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override;
++};
++#endif // CUNITMETRIC_H
+diff --git a/src/qmaptool/units/CUnitNautic.cpp b/src/qmaptool/units/CUnitNautic.cpp
+new file mode 100644
+index 00000000..d4f2a995
+--- /dev/null
++++ b/src/qmaptool/units/CUnitNautic.cpp
+@@ -0,0 +1,96 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++
++#include "units/CUnitNautic.h"
++
++CUnitNautic::CUnitNautic(QObject * parent)
++ : IUnit(eTypeNautic, "nm", 0.00053989, "nm/h", 1.94361780, parent)
++{
++}
++
++
++void CUnitNautic::meter2elevation(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.0f", meter);
++ unit = "m";
++ }
++}
++
++
++void CUnitNautic::meter2distance(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.2f", meter * basefactor);
++ unit = baseunit;
++ }
++}
++
++
++void CUnitNautic::meter2speed(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.2f",meter * speedfactor);
++ unit = speedunit;
++ }
++}
++
++void CUnitNautic::meter2area(qreal meter, QString& val, QString& unit) const /* override */
++{
++ if(meter == NOFLOAT)
++ {
++ val = "-";
++ unit = "";
++ }
++ else
++ {
++ val.sprintf("%1.2f", meter / (1852 * 1852));
++ unit = "nm²";
++ }
++}
++
++
++qreal CUnitNautic::elevation2meter(const QString& val) const /* override */
++{
++ return val.toDouble();
++}
++
++void CUnitNautic::meter2unit(qreal meter, qreal& scale, QString& unit) const
++{
++ scale = basefactor;
++ unit = "nm";
++}
+diff --git a/src/qmaptool/units/CUnitNautic.h b/src/qmaptool/units/CUnitNautic.h
+new file mode 100644
+index 00000000..d3afc9e6
+--- /dev/null
++++ b/src/qmaptool/units/CUnitNautic.h
+@@ -0,0 +1,37 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#ifndef CUNITNAUTIC_H
++#define CUNITNAUTIC_H
++
++#include "IUnit.h"
++
++class CUnitNautic : public IUnit
++{
++public:
++ CUnitNautic(QObject * parent);
++ virtual ~CUnitNautic() = default;
++
++ void meter2elevation(qreal meter, QString& val, QString& unit) const override;
++ void meter2distance(qreal meter, QString& val, QString& unit) const override;
++ void meter2speed(qreal meter, QString& val, QString& unit) const override;
++ void meter2area(qreal meter, QString& val, QString& unit) const override;
++ qreal elevation2meter(const QString& val) const override;
++ void meter2unit(qreal meter, qreal& scale, QString& unit) const override;
++};
++#endif //CUNITNAUTIC_H
+diff --git a/src/qmaptool/units/CUnitsSetup.cpp b/src/qmaptool/units/CUnitsSetup.cpp
+new file mode 100644
+index 00000000..8d083f69
+--- /dev/null
++++ b/src/qmaptool/units/CUnitsSetup.cpp
+@@ -0,0 +1,59 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CMainWindow.h"
++#include "units/CUnitsSetup.h"
++#include "units/IUnit.h"
++
++CUnitsSetup::CUnitsSetup(QWidget *parent)
++ : QDialog(parent)
++{
++ setupUi(this);
++
++ switch(IUnit::self().type)
++ {
++ case IUnit::eTypeMetric:
++ radioMetric->setChecked(true);
++ break;
++
++ case IUnit::eTypeImperial:
++ radioImperial->setChecked(true);
++ break;
++
++ case IUnit::eTypeNautic:
++ radioNautic->setChecked(true);
++ break;
++ }
++}
++
++void CUnitsSetup::accept()
++{
++ if(radioMetric->isChecked())
++ {
++ IUnit::setUnitType(IUnit::eTypeMetric, &CMainWindow::self());
++ }
++ else if(radioImperial->isChecked())
++ {
++ IUnit::setUnitType(IUnit::eTypeImperial, &CMainWindow::self());
++ }
++ else if(radioNautic->isChecked())
++ {
++ IUnit::setUnitType(IUnit::eTypeNautic, &CMainWindow::self());
++ }
++ QDialog::accept();
++}
+diff --git a/src/qmaptool/units/CUnitsSetup.h b/src/qmaptool/units/CUnitsSetup.h
+new file mode 100644
+index 00000000..765f7969
+--- /dev/null
++++ b/src/qmaptool/units/CUnitsSetup.h
+@@ -0,0 +1,35 @@
++/**********************************************************************************************
++ Copyright (C) 2014 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#ifndef CUNITSSETUP_H
++#define CUNITSSETUP_H
++
++#include "ui_IUnitsSetup.h"
++#include <QDialog>
++
++class CUnitsSetup : public QDialog, private Ui::IUnitsSetup
++{
++public:
++ CUnitsSetup(QWidget * parent);
++ virtual ~CUnitsSetup() = default;
++
++public slots:
++ void accept() override;
++};
++
++#endif //CUNITSSETUP_H
++
+diff --git a/src/qmaptool/units/ICoordFormatSetup.ui b/src/qmaptool/units/ICoordFormatSetup.ui
+new file mode 100644
+index 00000000..df39ec7e
+--- /dev/null
++++ b/src/qmaptool/units/ICoordFormatSetup.ui
+@@ -0,0 +1,125 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>ICoordFormatSetup</class>
++ <widget class="QDialog" name="ICoordFormatSetup">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>512</width>
++ <height>144</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Coordinate Format...</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <item>
++ <widget class="QRadioButton" name="radioFormat3">
++ <property name="text">
++ <string>N48° 53' 39.6&quot; E13° 31' 6.78&quot;</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioFormat2">
++ <property name="text">
++ <string>N48.8943° E013.51855°</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioFormat1">
++ <property name="text">
++ <string>N48° 53.660 E013° 31.113</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>ICoordFormatSetup</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>ICoordFormatSetup</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++</ui>
+diff --git a/src/qmaptool/units/ITimeZoneSetup.ui b/src/qmaptool/units/ITimeZoneSetup.ui
+new file mode 100644
+index 00000000..2313e881
+--- /dev/null
++++ b/src/qmaptool/units/ITimeZoneSetup.ui
+@@ -0,0 +1,182 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>ITimeZoneSetup</class>
++ <widget class="QDialog" name="ITimeZoneSetup">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>398</width>
++ <height>106</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Setup Time Zone ...</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_2">
++ <item>
++ <widget class="QRadioButton" name="radioUtc">
++ <property name="text">
++ <string>UTC</string>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioLocal">
++ <property name="text">
++ <string>Local</string>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioAutomatic">
++ <property name="text">
++ <string>Automatic</string>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioSelected">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string/>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <widget class="QComboBox" name="comboTimeZone"/>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout_3">
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="text">
++ <string>Print date/time in </string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioLongFormat">
++ <property name="text">
++ <string>long format, or</string>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup_2</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioShortFormat">
++ <property name="text">
++ <string>short format</string>
++ </property>
++ <attribute name="buttonGroup">
++ <string notr="true">buttonGroup_2</string>
++ </attribute>
++ </widget>
++ </item>
++ <item>
++ <spacer name="horizontalSpacer">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>40</width>
++ <height>20</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>40</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>ITimeZoneSetup</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>ITimeZoneSetup</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++ <buttongroups>
++ <buttongroup name="buttonGroup"/>
++ <buttongroup name="buttonGroup_2"/>
++ </buttongroups>
++</ui>
+diff --git a/src/qmaptool/units/IUnit.cpp b/src/qmaptool/units/IUnit.cpp
+new file mode 100644
+index 00000000..d266c6d0
+--- /dev/null
++++ b/src/qmaptool/units/IUnit.cpp
+@@ -0,0 +1,776 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#include "CMainWindow.h"
++#include "GeoMath.h"
++#include "units/CUnitImperial.h"
++#include "units/CUnitMetric.h"
++#include "units/CUnitNautic.h"
++
++#include <proj_api.h>
++#include <QtWidgets>
++const IUnit * IUnit::m_self = nullptr;
++
++const QPointF NOPOINTF(NOFLOAT, NOFLOAT);
++const QPoint NOPOINT (NOINT, NOINT);
++
++IUnit::tz_mode_e IUnit::timeZoneMode = IUnit::eTZUtc;
++IUnit::coord_format_e IUnit::coordFormat = IUnit::eCoordFormat1;
++QByteArray IUnit::timeZone = "UTC";
++bool IUnit::useShortFormat = false;
++
++const char * IUnit::tblTimezone[] =
++{
++ "Africa/Abidjan",
++ "Africa/Accra",
++ "Africa/Addis_Ababa",
++ "Africa/Algiers",
++ "Africa/Asmara",
++ "Africa/Bamako",
++ "Africa/Bangui",
++ "Africa/Banjul",
++ "Africa/Bissau",
++ "Africa/Blantyre",
++ "Africa/Brazzaville",
++ "Africa/Bujumbura",
++ "Africa/Cairo",
++ "Africa/Casablanca",
++ "Africa/Conakry",
++ "Africa/Dakar",
++ "Africa/Dar_es_Salaam",
++ "Africa/Djibouti",
++ "Africa/Douala",
++ "Africa/El_Aaiun",
++ "Africa/Freetown",
++ "Africa/Gaborone",
++ "Africa/Harare",
++ "Africa/Johannesburg",
++ "Africa/Kampala",
++ "Africa/Khartoum",
++ "Africa/Kigali",
++ "Africa/Kinshasa",
++ "Africa/Lagos",
++ "Africa/Libreville",
++ "Africa/Lome",
++ "Africa/Luanda",
++ "Africa/Lubumbashi",
++ "Africa/Lusaka",
++ "Africa/Malabo",
++ "Africa/Maputo",
++ "Africa/Maseru",
++ "Africa/Mbabane",
++ "Africa/Mogadishu",
++ "Africa/Monrovia",
++ "Africa/Nairobi",
++ "Africa/Ndjamena",
++ "Africa/Niamey",
++ "Africa/Nouakchott",
++ "Africa/Ouagadougou",
++ "Africa/Porto-Novo",
++ "Africa/Sao_Tome",
++ "Africa/Tripoli",
++ "Africa/Tunis",
++ "Africa/Windhoek",
++ "America/Adak",
++ "America/Anguilla",
++ "America/Antigua",
++ "America/Araguaina",
++ "America/Argentina/Buenos_Aires",
++ "America/Argentina/Catamarca",
++ "America/Argentina/Cordoba",
++ "America/Argentina/Jujuy",
++ "America/Argentina/La_Rioja",
++ "America/Argentina/Mendoza",
++ "America/Argentina/Rio_Gallegos",
++ "America/Argentina/San_Juan",
++ "America/Argentina/San_Luis",
++ "America/Argentina/Tucuman",
++ "America/Argentina/Ushuaia",
++ "America/Aruba",
++ "America/Asuncion",
++ "America/Atikokan",
++ "America/Bahia",
++ "America/Barbados",
++ "America/Belem",
++ "America/Belize",
++ "America/Blanc-Sablon",
++ "America/Boa_Vista",
++ "America/Bogota",
++ "America/Boise",
++ "America/Cambridge_Bay",
++ "America/Campo_Grande",
++ "America/Cancun",
++ "America/Caracas",
++ "America/Cayenne",
++ "America/Cayman",
++ "America/Chicago",
++ "America/Chihuahua",
++ "America/Coral_Harbour",
++ "America/Costa_Rica",
++ "America/Cuiaba",
++ "America/Curacao",
++ "America/Dawson",
++ "America/Dawson_Creek",
++ "America/Denver",
++ "America/Dominica",
++ "America/Edmonton",
++ "America/Eirunepe",
++ "America/El_Salvador",
++ "America/Fortaleza",
++ "America/Glace_Bay",
++ "America/Goose_Bay",
++ "America/Grand_Turk",
++ "America/Grenada",
++ "America/Guadeloupe",
++ "America/Guatemala",
++ "America/Guayaquil",
++ "America/Guyana",
++ "America/Halifax",
++ "America/Havana",
++ "America/Hermosillo",
++ "America/Indiana/Indianapolis",
++ "America/Indiana/Knox",
++ "America/Indiana/Marengo",
++ "America/Indiana/Petersburg",
++ "America/Indiana/Vevay",
++ "America/Indiana/Vincennes",
++ "America/Indiana/Winamac",
++ "America/Inuvik",
++ "America/Iqaluit",
++ "America/Jamaica",
++ "America/Juneau",
++ "America/Kentucky/Louisville",
++ "America/Kentucky/Monticello",
++ "America/La_Paz",
++ "America/Lima",
++ "America/Los_Angeles",
++ "America/Maceio",
++ "America/Managua",
++ "America/Manaus",
++ "America/Marigot",
++ "America/Martinique",
++ "America/Mazatlan",
++ "America/Menominee",
++ "America/Merida",
++ "America/Mexico_City",
++ "America/Miquelon",
++ "America/Moncton",
++ "America/Monterrey",
++ "America/Montevideo",
++ "America/Montreal",
++ "America/Montserrat",
++ "America/Nassau",
++ "America/New_York",
++ "America/Nipigon",
++ "America/Noronha",
++ "America/North_Dakota/Center",
++ "America/North_Dakota/Salem",
++ "America/Panama",
++ "America/Pangnirtung",
++ "America/Paramaribo",
++ "America/Phoenix",
++ "America/Port-au-Prince",
++ "America/Port_of_Spain",
++ "America/Porto_Velho",
++ "America/Puerto_Rico",
++ "America/Rainy_River",
++ "America/Rankin_Inlet",
++ "America/Recife",
++ "America/Regina",
++ "America/Resolute",
++ "America/Rio_Branco",
++ "America/Santarem",
++ "America/Santiago",
++ "America/Santo_Domingo",
++ "America/Sao_Paulo",
++ "America/St_Barthelemy",
++ "America/St_Johns",
++ "America/St_Kitts",
++ "America/St_Lucia",
++ "America/St_Thomas",
++ "America/St_Vincent",
++ "America/Tegucigalpa",
++ "America/Thunder_Bay",
++ "America/Tijuana",
++ "America/Toronto",
++ "America/Tortola",
++ "America/Vancouver",
++ "America/Whitehorse",
++ "America/Winnipeg",
++ "America/Yellowknife",
++ "Ameriica/Swift_Current",
++ "Arctic/Longyearbyen",
++ "Asia/Aden",
++ "Asia/Almaty",
++ "Asia/Amman",
++ "Asia/Anadyr",
++ "Asia/Aqtau",
++ "Asia/Aqtobe",
++ "Asia/Ashgabat",
++ "Asia/Baghdad",
++ "Asia/Bahrain",
++ "Asia/Baku",
++ "Asia/Bangkok",
++ "Asia/Beirut",
++ "Asia/Bishkek",
++ "Asia/Brunei",
++ "Asia/Choibalsan",
++ "Asia/Chongqing",
++ "Asia/Colombo",
++ "Asia/Damascus",
++ "Asia/Dhaka",
++ "Asia/Dili",
++ "Asia/Dubai",
++ "Asia/Dushanbe",
++ "Asia/Gaza",
++ "Asia/Harbin",
++ "Asia/Ho_Chi_Minh",
++ "Asia/Hong_Kong",
++ "Asia/Hovd",
++ "Asia/Irkutsk",
++ "Asia/Jakarta",
++ "Asia/Jayapura",
++ "Asia/Jerusalem",
++ "Asia/Kabul",
++ "Asia/Kamchatka",
++ "Asia/Karachi",
++ "Asia/Kashgar",
++ "Asia/Katmandu",
++ "Asia/Kolkata",
++ "Asia/Krasnoyarsk",
++ "Asia/Kuala_Lumpur",
++ "Asia/Kuching",
++ "Asia/Kuwait",
++ "Asia/Macau",
++ "Asia/Magadan",
++ "Asia/Makassar",
++ "Asia/Manila",
++ "Asia/Muscat",
++ "Asia/Nicosia",
++ "Asia/Novosibirsk",
++ "Asia/Omsk",
++ "Asia/Oral",
++ "Asia/Phnom_Penh",
++ "Asia/Pontianak",
++ "Asia/Pyongyang",
++ "Asia/Qatar",
++ "Asia/Qyzylorda",
++ "Asia/Rangoon",
++ "Asia/Riyadh",
++ "Asia/Sakhalin",
++ "Asia/Samarkand",
++ "Asia/Seoul",
++ "Asia/Shanghai",
++ "Asia/Singapore",
++ "Asia/Taipei",
++ "Asia/Tashkent",
++ "Asia/Tbilisi",
++ "Asia/Tehran",
++ "Asia/Thimphu",
++ "Asia/Tokyo",
++ "Asia/Ulaanbaatar",
++ "Asia/Urumqi",
++ "Asia/Vientiane",
++ "Asia/Vladivostok",
++ "Asia/Yakutsk",
++ "Asia/Yekaterinburg",
++ "Asia/Yerevan",
++ "Atlantic/Azores",
++ "Atlantic/Bermuda",
++ "Atlantic/Canary",
++ "Atlantic/Cape_Verde",
++ "Atlantic/Faroe",
++ "Atlantic/Madeira",
++ "Atlantic/Reykjavik",
++ "Atlantic/South_Georgia",
++ "Atlantic/St_Helena",
++ "Atlantic/Stanley",
++ "Australia/Adelaide",
++ "Australia/Brisbane",
++ "Australia/Broken_Hill",
++ "Australia/Currie",
++ "Australia/Darwin",
++ "Australia/Eucla",
++ "Australia/Hobart",
++ "Australia/Lindeman",
++ "Australia/Lord_Howe",
++ "Australia/Melbourne",
++ "Australia/Perth",
++ "Australia/Sydney",
++ "Europe/Amsterdam",
++ "Europe/Andorra",
++ "Europe/Athens",
++ "Europe/Belgrade",
++ "Europe/Berlin",
++ "Europe/Bratislava",
++ "Europe/Brussels",
++ "Europe/Bucharest",
++ "Europe/Budapest",
++ "Europe/Chisinau",
++ "Europe/Copenhagen",
++ "Europe/Dublin",
++ "Europe/Gibraltar",
++ "Europe/Guernsey",
++ "Europe/Helsinki",
++ "Europe/Isle_of_Man",
++ "Europe/Istanbul",
++ "Europe/Jersey",
++ "Europe/Kaliningrad",
++ "Europe/Kiev",
++ "Europe/Lisbon",
++ "Europe/Ljubljana",
++ "Europe/London",
++ "Europe/Luxembourg",
++ "Europe/Madrid",
++ "Europe/Malta",
++ "Europe/Marienhamn",
++ "Europe/Minsk",
++ "Europe/Monaco",
++ "Europe/Moscow",
++ "Europe/Oslo",
++ "Europe/Paris",
++ "Europe/Podgorica",
++ "Europe/Prague",
++ "Europe/Riga",
++ "Europe/Rome",
++ "Europe/Samara",
++ "Europe/San_Marino",
++ "Europe/Sarajevo",
++ "Europe/Simferopol",
++ "Europe/Skopje",
++ "Europe/Sofia",
++ "Europe/Stockholm",
++ "Europe/Tallinn",
++ "Europe/Tirane",
++ "Europe/Uzhgorod",
++ "Europe/Vaduz",
++ "Europe/Vatican",
++ "Europe/Vienna",
++ "Europe/Vilnius",
++ "Europe/Volgograd",
++ "Europe/Warsaw",
++ "Europe/Zagreb",
++ "Europe/Zaporozhye",
++ "Europe/Zurich",
++ "Indian/Antananarivo",
++ "Indian/Chagos",
++ "Indian/Christmas",
++ "Indian/Cocos",
++ "Indian/Comoro",
++ "Indian/Kerguelen",
++ "Indian/Mahe",
++ "Indian/Maldives",
++ "Indian/Mauritius",
++ "Indian/Mayotte",
++ "Indian/Reunion",
++ "Pacific/Apia",
++ "Pacific/Auckland",
++ "Pacific/Chatham",
++ "Pacific/Easter",
++ "Pacific/Efate",
++ "Pacific/Enderbury",
++ "Pacific/Fakaofo",
++ "Pacific/Fiji",
++ "Pacific/Funafuti",
++ "Pacific/Galapagos",
++ "Pacific/Gambier",
++ "Pacific/Guadalcanal",
++ "Pacific/Guam",
++ "Pacific/Honolulu",
++ "Pacific/Johnston",
++ "Pacific/Kiritimati",
++ "Pacific/Kosrae",
++ "Pacific/Kwajalein",
++ "Pacific/Majuro",
++ "Pacific/Marquesas",
++ "Pacific/Midway",
++ "Pacific/Nauru",
++ "Pacific/Niue",
++ "Pacific/Norfolk",
++ "Pacific/Noumea",
++ "Pacific/Pago_Pago",
++ "Pacific/Palau",
++ "Pacific/Pitcairn",
++ "Pacific/Ponape",
++ "Pacific/Port_Moresby",
++ "Pacific/Rarotonga",
++ "Pacific/Saipan",
++ "Pacific/Tahiti",
++ "Pacific/Tarawa",
++ "Pacific/Tongatapu",
++ "Pacific/Truk",
++ "Pacific/Wake",
++ "Pacific/Wallis",
++ 0
++};
++
++const int N_TIMEZONES = sizeof(IUnit::tblTimezone)/sizeof(const char*);
++
++const QRegExp IUnit::reCoord1("^\\s*([N|S]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s+([E|W|O]){1}\\W*([0-9]+)\\W*([0-9]+\\.[0-9]+)\\s*$");
++
++const QRegExp IUnit::reCoord2("^\\s*([N|S]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s+([E|W|O]){1}\\s*([0-9]+\\.[0-9]+)\\W*\\s*$");
++
++const QRegExp IUnit::reCoord3("^\\s*([-0-9]+\\.[0-9]+)\\s+([-0-9]+\\.[0-9]+)\\s*$");
++
++const QRegExp IUnit::reCoord4("^\\s*([N|S]){1}\\s*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*([E|W|O]){1}\\W*([0-9]+)\\W+([0-9]+)\\W+([0-9]+\\.[0-9]+)\\W*\\s*$");
++
++const QRegExp IUnit::reCoord5("^\\s*([-0-9]+\\.[0-9]+)([N|S])\\s+([-0-9]+\\.[0-9]+)([W|E])\\s*$");
++
++IUnit::IUnit(const type_e &type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject * parent)
++ : QObject(parent)
++ , type(type)
++ , baseunit(baseunit)
++ , basefactor(basefactor)
++ , speedunit(speedunit)
++ , speedfactor(speedfactor)
++{
++ //there can be only one...
++ if(nullptr != m_self)
++ {
++ delete m_self;
++ }
++ m_self = this;
++}
++
++
++void IUnit::setUnitType(type_e t, QObject * parent)
++{
++ switch(t)
++ {
++ case eTypeMetric:
++ new CUnitMetric(parent);
++ break;
++
++ case eTypeImperial:
++ new CUnitImperial(parent);
++ break;
++
++ case eTypeNautic:
++ new CUnitNautic(parent);
++ break;
++ }
++
++ QSettings cfg;
++ cfg.setValue("Units/type",t);
++}
++
++void IUnit::meter2speed(qreal meter, QString& val, QString& unit) const
++{
++ val.sprintf("%2.2f",meter * speedfactor);
++ unit = speedunit;
++}
++
++void IUnit::seconds2time(quint32 ttime, QString& val, QString& unit) const
++{
++ QTime time(0,0,0);
++ quint32 days = ttime / 86400;
++
++ time = time.addSecs(ttime);
++
++ if(days)
++ {
++ val = QString("%1:").arg(days) + time.toString("HH:mm:ss");
++ unit = "d";
++ }
++ else
++ {
++ val = time.toString("HH:mm:ss");
++ unit = "h";
++ }
++}
++
++bool IUnit::parseTimestamp(const QString &time, QDateTime &datetime)
++{
++ int tzoffset;
++ datetime = parseTimestamp(time, tzoffset);
++
++ return datetime.isValid();
++}
++
++
++QDateTime IUnit::parseTimestamp(const QString &timetext, int& tzoffset)
++{
++ const QRegExp tzRE("[-+]\\d\\d:\\d\\d$");
++ int i;
++
++ tzoffset = 0;
++
++ QString format = "yyyy-MM-dd'T'hh:mm:ss";
++
++ i = timetext.indexOf(".");
++ if (i != NOIDX)
++ {
++ if(timetext[i+1] == '0')
++ {
++ format += ".zzz";
++ }
++ else
++ {
++ format += ".z";
++ }
++ }
++
++ // trailing "Z" explicitly declares the timestamp to be UTC
++ if (timetext.indexOf("Z") != NOIDX)
++ {
++ format += "'Z'";
++ }
++ else if ((i = tzRE.indexIn(timetext)) != NOIDX)
++ {
++ // trailing timezone offset [-+]HH:MM present
++ // This does not match the original intentions of the GPX
++ // file format but appears to be found occasionally in
++ // the wild. Try our best parsing it.
++
++ // add the literal string to the format so fromString()
++ // will succeed
++ format += "'";
++ format += timetext.right(6);
++ format += "'";
++
++ // calculate the offset
++ int offsetHours(timetext.mid(i + 1, 2).toUInt());
++ int offsetMinutes(timetext.mid(i + 4, 2).toUInt());
++ if (timetext[i] == '-')
++ {
++ tzoffset = -(60 * offsetHours + offsetMinutes);
++ }
++ else
++ {
++ tzoffset = 60 * offsetHours + offsetMinutes;
++ }
++ tzoffset *= 60; // seconds
++ }
++
++ QDateTime datetime = QDateTime::fromString(timetext, format);
++ datetime.setOffsetFromUtc(tzoffset);
++
++ return datetime;
++}
++
++QString IUnit::datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos)
++{
++ QTimeZone tz;
++
++ tz_mode_e tmpMode = (pos != NOPOINTF) ? timeZoneMode : eTZLocal;
++
++ switch(tmpMode)
++ {
++ case eTZUtc:
++ tz = QTimeZone("UTC");
++ break;
++
++ case eTZLocal:
++ tz = QTimeZone(QTimeZone::systemTimeZoneId());
++ break;
++
++ case eTZAuto:
++ tz = QTimeZone(pos2timezone(pos));
++ break;
++
++ case eTZSelected:
++ tz = QTimeZone(timeZone);
++ break;
++ }
++
++ QDateTime tmp = time.toTimeZone(tz);
++ return tmp.toString((shortDate|useShortFormat) ? Qt::ISODate : Qt::SystemLocaleLongDate);
++}
++
++QByteArray IUnit::pos2timezone(const QPointF& pos)
++{
++ static QImage imgTimezone = QPixmap(":/pics/timezones.png").toImage();
++
++ int x = qRound(2048.0 / 360.0 * (180.0 + pos.x() * RAD_TO_DEG));
++ int y = qRound(1024.0 / 180.0 * (90.0 - pos.y() * RAD_TO_DEG));
++
++ QRgb rgb = imgTimezone.pixel(x,y);
++
++ if(qRed(rgb) == 0 && qGreen(rgb) == 0)
++ {
++ return "UTC";
++ }
++
++ int tz = ((qRed(rgb) & 248) << 1) + ((qGreen(rgb) >> 4) & 15);
++ if(tz >= N_TIMEZONES)
++ {
++ return 0;
++ }
++
++ return tblTimezone[tz];
++}
++
++bool IUnit::degToStr(const qreal& x, const qreal& y, QString& str)
++{
++ if(x < -180 || 180 < x)
++ {
++ return false;
++ }
++
++ if(y < -90 || 90 < y)
++ {
++ return false;
++ }
++
++ switch(coordFormat)
++ {
++ case eCoordFormat1:
++ {
++ qint32 degN,degE;
++ qreal minN,minE;
++
++ bool signLat = GPS_Math_Deg_To_DegMin(y, &degN, &minN);
++ bool signLon = GPS_Math_Deg_To_DegMin(x, &degE, &minE);
++
++ const QString &lat = signLat ? "S" : "N";
++ const QString &lng = signLon ? "W" : "E";
++ str.sprintf("%s%02d° %06.3f %s%03d° %06.3f",lat.toUtf8().data(),qAbs(degN),minN,lng.toUtf8().data(),qAbs(degE),minE);
++ break;
++ }
++
++ case eCoordFormat2:
++ {
++ const QString &lat = (y < 0) ? "S" : "N";
++ const QString &lng = (x < 0) ? "W" : "E";
++ str.sprintf("%s%02.6f° %s%03.6f°",lat.toUtf8().data(),qAbs(y),lng.toUtf8().data(),qAbs(x));
++ break;
++ }
++
++ case eCoordFormat3:
++ {
++ qint32 degN,degE;
++ qreal minN,minE;
++
++ bool signLat = GPS_Math_Deg_To_DegMin(y, &degN, &minN);
++ bool signLon = GPS_Math_Deg_To_DegMin(x, &degE, &minE);
++
++ qreal secN = (minN - qFloor(minN)) * 60;
++ qreal secE = (minE - qFloor(minE)) * 60;
++
++ const QString &lat = signLat ? "S" : "N";
++ const QString &lng = signLon ? "W" : "E";
++ str.sprintf("%s%02d° %02d' %02.2f'' %s%03d° %02d' %02.2f''",lat.toUtf8().data(),qAbs(degN),qFloor(minN),secN,lng.toUtf8().data(),qAbs(degE),qFloor(minE),secE);
++ break;
++ }
++ }
++
++ return true;
++}
++
++bool IUnit::strToDeg(const QString& str, qreal& lon, qreal& lat)
++{
++ if(reCoord2.exactMatch(str))
++ {
++ bool signLat = reCoord2.cap(1) == "S";
++ qreal absLat = reCoord2.cap(2).toDouble();
++ lat = signLat ? -absLat : absLat;
++
++ bool signLon = reCoord2.cap(3) == "W";
++ qreal absLon = reCoord2.cap(4).toDouble();
++ lon = signLon ? -absLon : absLon;
++ }
++ else if(reCoord1.exactMatch(str))
++ {
++ bool signLat = reCoord1.cap(1) == "S";
++ int degLat = reCoord1.cap(2).toInt();
++ qreal minLat = reCoord1.cap(3).toDouble();
++
++ GPS_Math_DegMin_To_Deg(signLat, degLat, minLat, lat);
++
++ bool signLon = reCoord1.cap(4) == "W";
++ int degLon = reCoord1.cap(5).toInt();
++ qreal minLon = reCoord1.cap(6).toDouble();
++
++ GPS_Math_DegMin_To_Deg(signLon, degLon, minLon, lon);
++ }
++ else if(reCoord3.exactMatch(str))
++ {
++ lat = reCoord3.cap(1).toDouble();
++ lon = reCoord3.cap(2).toDouble();
++ }
++ else if(reCoord4.exactMatch(str))
++ {
++ bool signLat = reCoord4.cap(1) == "S";
++ int degLat = reCoord4.cap(2).toInt();
++ int minLat = reCoord4.cap(3).toInt();
++ qreal secLat = reCoord4.cap(4).toFloat();
++
++ GPS_Math_DegMinSec_To_Deg(signLat, degLat, minLat, secLat, lat);
++
++ bool signLon = reCoord4.cap(5) == "W";
++ int degLon = reCoord4.cap(6).toInt();
++ int minLon = reCoord4.cap(7).toInt();
++ qreal secLon = reCoord4.cap(8).toFloat();
++
++ GPS_Math_DegMinSec_To_Deg(signLon, degLon, minLon, secLon, lon);
++ }
++ else if(reCoord5.exactMatch(str))
++ {
++ bool signLon = reCoord4.cap(4) == "W";
++ bool signLat = reCoord4.cap(2) == "S";
++ lat = reCoord5.cap(1).toDouble();
++ lon = reCoord5.cap(3).toDouble();
++
++ if(signLon)
++ {
++ lon = -lon;
++ }
++ if(signLat)
++ {
++ lat = -lat;
++ }
++ }
++ else
++ {
++ QMessageBox::warning(&CMainWindow::self(),tr("Error"),tr("Bad position format. Must be: \"[N|S] ddd mm.sss [W|E] ddd mm.sss\" or \"[N|S] ddd.ddd [W|E] ddd.ddd\""),QMessageBox::Ok,QMessageBox::NoButton);
++ return false;
++ }
++
++ if(fabs(lon) > 180.0 || fabs(lat) > 90.0)
++ {
++ QMessageBox::warning(&CMainWindow::self(),tr("Error"),tr("Position values out of bounds. "),QMessageBox::Ok,QMessageBox::NoButton);
++ return false;
++ }
++
++ return true;
++}
++
++bool IUnit::isValidCoordString(const QString& str)
++{
++ if(reCoord1.exactMatch(str))
++ {
++ return true;
++ }
++ else if(reCoord2.exactMatch(str))
++ {
++ return true;
++ }
++ else if(reCoord3.exactMatch(str))
++ {
++ return true;
++ }
++ else if(reCoord4.exactMatch(str))
++ {
++ return true;
++ }
++ else if(reCoord5.exactMatch(str))
++ {
++ return true;
++ }
++ return false;
++}
+diff --git a/src/qmaptool/units/IUnit.h b/src/qmaptool/units/IUnit.h
+new file mode 100644
+index 00000000..f88077ac
+--- /dev/null
++++ b/src/qmaptool/units/IUnit.h
+@@ -0,0 +1,153 @@
++/**********************************************************************************************
++ Copyright (C) 2008 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
++
++**********************************************************************************************/
++#ifndef IUNIT_H
++#define IUNIT_H
++#include <QObject>
++#include <QTimeZone>
++
++
++#define NOFLOAT 1000000000000.0
++#define NOINT 0x7FFFFFFF
++#define NOTIME 0xFFFFFFFF
++#define NOIDX (-1)
++
++extern const QPointF NOPOINTF;
++extern const QPoint NOPOINT;
++
++class IUnit : public QObject
++{
++ Q_OBJECT
++public:
++ virtual ~IUnit() = default;
++
++ static const IUnit& self()
++ {
++ return *m_self;
++ }
++
++ /// convert meter of elevation into a value and unit string
++ virtual void meter2elevation(qreal meter, QString& val, QString& unit) const = 0;
++ /// convert meter of distance into a value and unit string
++ virtual void meter2distance(qreal meter, QString& val, QString& unit) const = 0;
++ /// convert meter per second to a speed value string and unit label
++ virtual void meter2speed(qreal meter, QString& val, QString& unit) const;
++ /// convert square meter to string and unit label
++ virtual void meter2area(qreal meter, QString& val, QString& unit) const = 0;
++ /// convert seconds to a timespan of days, hours, minutes and seconds
++ virtual void seconds2time(quint32 ttime, QString& val, QString& unit) const;
++ /// convert an elevation string to a float
++ virtual qreal elevation2meter(const QString& val) const = 0;
++ /// convert a range in meter into a scale and a matching unit
++ virtual void meter2unit(qreal meter, qreal& scale, QString& unit) const = 0;
++
++
++ enum type_e {eTypeMetric, eTypeImperial, eTypeNautic};
++ /// instantiate the correct unit object
++ static void setUnitType(type_e t, QObject * parent);
++
++ /// parse a string for a timestamp
++ static bool parseTimestamp(const QString &time, QDateTime &datetime);
++
++ /**
++ @brief Convert date time object to string using the current timezone configuration
++
++
++ @param time the date/time object
++ @param shortDate set true to get a short ISO time string
++ @param pos optional a position attached to the date/time object [rad]
++ @return A time string.
++ */
++ static QString datetime2string(const QDateTime& time, bool shortDate, const QPointF& pos = NOPOINTF);
++
++ /// find the timezone setup by position
++ static QByteArray pos2timezone(const QPointF& pos);
++
++ const type_e type;
++ const QString baseunit;
++ const qreal basefactor;
++ const QString speedunit;
++ const qreal speedfactor;
++ static const char *tblTimezone[];
++
++ enum tz_mode_e
++ {
++ eTZUtc
++ ,eTZLocal
++ ,eTZAuto
++ ,eTZSelected
++ };
++
++ static void getTimeZoneSetup(tz_mode_e& mode, QByteArray& zone, bool& format)
++ {
++ mode = timeZoneMode;
++ zone = timeZone;
++ format = useShortFormat;
++ }
++
++ static void setTimeZoneSetup(tz_mode_e mode, const QByteArray& zone, bool format)
++ {
++ timeZoneMode = mode;
++ timeZone = zone;
++ useShortFormat = format;
++ }
++
++ enum coord_format_e
++ {
++ eCoordFormat1
++ ,eCoordFormat2
++ ,eCoordFormat3
++ };
++
++ static enum coord_format_e getCoordFormat()
++ {
++ return coordFormat;
++ }
++
++ static void setCoordFormat(const coord_format_e format)
++ {
++ coordFormat = format;
++ }
++
++ static bool degToStr(const qreal& x, const qreal& y, QString& str);
++
++ static bool strToDeg(const QString& str, qreal& lon, qreal& lat);
++
++ static bool isValidCoordString(const QString& str);
++
++protected:
++ IUnit(const type_e& type, const QString& baseunit, const qreal basefactor, const QString& speedunit, const qreal speedfactor, QObject *parent);
++
++ static QDateTime parseTimestamp(const QString &timetext, int& tzoffset);
++
++ static tz_mode_e timeZoneMode;
++ static QByteArray timeZone;
++ static bool useShortFormat;
++
++ static coord_format_e coordFormat;
++
++private:
++ static const IUnit * m_self;
++
++ static const QRegExp reCoord1;
++ static const QRegExp reCoord2;
++ static const QRegExp reCoord3;
++ static const QRegExp reCoord4;
++ static const QRegExp reCoord5;
++};
++#endif //IUNIT_H
+diff --git a/src/qmaptool/units/IUnitsSetup.ui b/src/qmaptool/units/IUnitsSetup.ui
+new file mode 100644
+index 00000000..4ccb69fd
+--- /dev/null
++++ b/src/qmaptool/units/IUnitsSetup.ui
+@@ -0,0 +1,125 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<ui version="4.0">
++ <class>IUnitsSetup</class>
++ <widget class="QDialog" name="IUnitsSetup">
++ <property name="geometry">
++ <rect>
++ <x>0</x>
++ <y>0</y>
++ <width>432</width>
++ <height>147</height>
++ </rect>
++ </property>
++ <property name="windowTitle">
++ <string>Setup units...</string>
++ </property>
++ <layout class="QVBoxLayout" name="verticalLayout">
++ <item>
++ <layout class="QHBoxLayout" name="horizontalLayout">
++ <item>
++ <layout class="QVBoxLayout" name="verticalLayout_2">
++ <item>
++ <widget class="QRadioButton" name="radioNautic">
++ <property name="text">
++ <string>Nautical</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioImperial">
++ <property name="text">
++ <string>Imperial</string>
++ </property>
++ </widget>
++ </item>
++ <item>
++ <widget class="QRadioButton" name="radioMetric">
++ <property name="text">
++ <string>Metric</string>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <widget class="QLabel" name="label">
++ <property name="sizePolicy">
++ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
++ <horstretch>0</horstretch>
++ <verstretch>0</verstretch>
++ </sizepolicy>
++ </property>
++ <property name="text">
++ <string>&lt;b&gt;Note:&lt;/b&gt; For some GUI elements changing the units will not take effect until you restart QMapTool.</string>
++ </property>
++ <property name="alignment">
++ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
++ </property>
++ <property name="wordWrap">
++ <bool>true</bool>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </item>
++ <item>
++ <spacer name="verticalSpacer">
++ <property name="orientation">
++ <enum>Qt::Vertical</enum>
++ </property>
++ <property name="sizeHint" stdset="0">
++ <size>
++ <width>20</width>
++ <height>7</height>
++ </size>
++ </property>
++ </spacer>
++ </item>
++ <item>
++ <widget class="QDialogButtonBox" name="buttonBox">
++ <property name="orientation">
++ <enum>Qt::Horizontal</enum>
++ </property>
++ <property name="standardButtons">
++ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
++ </property>
++ </widget>
++ </item>
++ </layout>
++ </widget>
++ <resources/>
++ <connections>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>accepted()</signal>
++ <receiver>IUnitsSetup</receiver>
++ <slot>accept()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>248</x>
++ <y>254</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>157</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ <connection>
++ <sender>buttonBox</sender>
++ <signal>rejected()</signal>
++ <receiver>IUnitsSetup</receiver>
++ <slot>reject()</slot>
++ <hints>
++ <hint type="sourcelabel">
++ <x>316</x>
++ <y>260</y>
++ </hint>
++ <hint type="destinationlabel">
++ <x>286</x>
++ <y>274</y>
++ </hint>
++ </hints>
++ </connection>
++ </connections>
++</ui>
+diff --git a/src/qmaptool/version.h b/src/qmaptool/version.h
+new file mode 100644
+index 00000000..5e1ba038
+--- /dev/null
++++ b/src/qmaptool/version.h
+@@ -0,0 +1,33 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef VERSION_H
++#define VERSION_H
++
++#ifndef _MKSTR_1
++#define _MKSTR_1(x) #x
++#define _MKSTR(x) _MKSTR_1(x)
++#endif
++
++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR (VER_MINOR) "." _MKSTR (VER_STEP)
++#define VER_SUFFIX _MKSTR(VER_TWEAK)
++
++#define WHAT_STR "QMapTool, Version " VER_STR
++
++#endif //VERSION_H
++
diff --git a/gis/qmapshack/line_3px_horizontal.png b/gis/qmapshack/line_3px_horizontal.png
new file mode 100644
index 0000000000000..02c89c8dc461b
--- /dev/null
+++ b/gis/qmapshack/line_3px_horizontal.png
Binary files differ
diff --git a/gis/qmapshack/line_3px_vertical.png b/gis/qmapshack/line_3px_vertical.png
new file mode 100644
index 0000000000000..f0f447c29133f
--- /dev/null
+++ b/gis/qmapshack/line_3px_vertical.png
Binary files differ
diff --git a/gis/qmapshack/qmapshack.SlackBuild b/gis/qmapshack/qmapshack.SlackBuild
index af723abc20b7c..e8e62e063298e 100644
--- a/gis/qmapshack/qmapshack.SlackBuild
+++ b/gis/qmapshack/qmapshack.SlackBuild
@@ -10,7 +10,7 @@
# http://sam.zoy.org/wtfpl/COPYING for more details.
PRGNAM=qmapshack
-VERSION=${VERSION:-1.13.1}
+VERSION=${VERSION:-1.13.2}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
@@ -48,7 +48,18 @@ mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
tar xvf $CWD/$PRGNAM-$VERSION.tar.gz
-cd $PRGNAM-$VERSION
+cd ${PRGNAM}-V_${VERSION}
+
+# Patches provided in the source tree
+patch -p1 < FindPROJ4.patch
+patch -p1 < FindQuaZip5.patch
+# Further patches and graphics required to build
+patch -p1 < ${CWD}/addqmaptool.patch
+patch -p1 < ${CWD}/qmt_map2jnx.patch
+patch -p1 < ${CWD}/rgb2pct.patch
+mkdir -p src/qmaptool/pic
+cp ${CWD}/splash.png ${CWD}/line_3px_horizontal.png ${CWD}/line_3px_vertical.png src/qmaptool/pic
+
chown -R root:root .
find -L . \
@@ -57,10 +68,6 @@ find -L . \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
-# Qmapshack expects proj to provide package information files created by cmake, the proj version on slackbuilds.org, however, is
-# built using autotools, thus the config script fails. Again, thx to pAcAs for the hint.
-cat $CWD/FindPROJ4.cmake > cmake/Modules/FindPROJ4.cmake
-
mkdir -p build
cd build
cmake \
diff --git a/gis/qmapshack/qmapshack.info b/gis/qmapshack/qmapshack.info
index 7dd12a7a81980..ce1f5e3073288 100644
--- a/gis/qmapshack/qmapshack.info
+++ b/gis/qmapshack/qmapshack.info
@@ -1,10 +1,10 @@
PRGNAM="qmapshack"
-VERSION="1.13.1"
+VERSION="1.13.2"
HOMEPAGE="https://bitbucket.org/maproom/qmapshack/wiki/Home"
DOWNLOAD="UNSUPPORTED"
MD5SUM=""
-DOWNLOAD_x86_64="https://bitbucket.org/maproom/qmapshack/downloads/qmapshack-1.13.1.tar.gz"
-MD5SUM_x86_64="5632d8318a93850b4cce731443aa64fe"
+DOWNLOAD_x86_64="https://github.com/Maproom/qmapshack/archive/V_1.13.2/qmapshack-1.13.2.tar.gz"
+MD5SUM_x86_64="1892583083d339bc393ce06919b7c4d9"
REQUIRES="gdal qt5-webkit routino quazip-qt5"
MAINTAINER="Daniel Stolarski"
EMAIL="daniel.stolarski@gmail.com"
diff --git a/gis/qmapshack/qmt_map2jnx.patch b/gis/qmapshack/qmt_map2jnx.patch
new file mode 100644
index 0000000000000..50d5a2666626f
--- /dev/null
+++ b/gis/qmapshack/qmt_map2jnx.patch
@@ -0,0 +1,1199 @@
+From 79a266943a40bee8fa5e71776c6a76c4d46bfbf8 Mon Sep 17 00:00:00 2001
+From: Oliver Eichler <oliver.eichler@dspsolutions.de>
+Date: Thu, 12 Sep 2019 20:31:26 +0200
+Subject: [PATCH] [QMS-3] Add qmt_map2jnx from former sub-repo
+
+---
+ src/qmt_map2jnx/CMakeLists.txt | 59 ++
+ src/qmt_map2jnx/argv.cpp | 45 ++
+ src/qmt_map2jnx/argv.h | 16 +
+ src/qmt_map2jnx/main.cpp | 1039 ++++++++++++++++++++++++++++++++
+ 4 files changed, 1159 insertions(+)
+ create mode 100644 src/qmt_map2jnx/CMakeLists.txt
+ create mode 100644 src/qmt_map2jnx/argv.cpp
+ create mode 100644 src/qmt_map2jnx/argv.h
+ create mode 100644 src/qmt_map2jnx/main.cpp
+
+diff --git a/src/qmt_map2jnx/CMakeLists.txt b/src/qmt_map2jnx/CMakeLists.txt
+new file mode 100644
+index 00000000..12b29d94
+--- /dev/null
++++ b/src/qmt_map2jnx/CMakeLists.txt
+@@ -0,0 +1,59 @@
++
++
++set(APPLICATION_NAME qmt_map2jnx)
++set(MAP2JNX_VERSION_MAJOR 1)
++set(MAP2JNX_VERSION_MINOR 0)
++set(MAP2JNX_VERSION_PATCH 0)
++
++add_definitions(
++ -DVER_MAJOR=${MAP2JNX_VERSION_MAJOR}
++ -DVER_MINOR=${MAP2JNX_VERSION_MINOR}
++ -DVER_STEP=${MAP2JNX_VERSION_PATCH}
++ -DVER_TWEAK=${VERSION_SUFFIX}
++ -DAPPLICATION_NAME=${APPLICATION_NAME}
++)
++
++
++#if you don't want the full compiler output, remove the following line
++SET(CMAKE_VERBOSE_MAKEFILE ON)
++SET(SRCS main.cpp argv.cpp)
++SET(HDRS argv.h)
++
++
++include_directories(
++ ${CMAKE_BINARY_DIR}
++ ${CMAKE_CURRENT_BINARY_DIR}
++ ${GDAL_INCLUDE_DIRS}
++ ${PROJ4_INCLUDE_DIRS}
++ ${JPEG_INCLUDE_DIRS}
++)
++
++if(APPLE)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework)
++endif(APPLE)
++
++if(WIN32)
++ include_directories(
++ ${CMAKE_SOURCE_DIR}/Win32/
++ )
++endif(WIN32)
++
++#list all source files here
++ADD_EXECUTABLE( ${APPLICATION_NAME} ${SRCS} ${HDRS})
++
++#add definitions, compiler switches, etc.
++IF(UNIX)
++ ADD_DEFINITIONS(-Wall)
++ENDIF(UNIX)
++
++IF(WIN32)
++ ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
++ENDIF(WIN32)
++
++TARGET_LINK_LIBRARIES(${APPLICATION_NAME} ${GDAL_LIBRARIES} ${PROJ4_LIBRARIES} ${JPEG_LIBRARIES})
++
++install(
++ TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR}
++)
++
+diff --git a/src/qmt_map2jnx/argv.cpp b/src/qmt_map2jnx/argv.cpp
+new file mode 100644
+index 00000000..a7f7939c
+--- /dev/null
++++ b/src/qmt_map2jnx/argv.cpp
+@@ -0,0 +1,45 @@
++/**********************************************************************************************
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++#include <stdlib.h>
++#include <string.h>
++
++#ifdef WIN32
++#include <windows.h>
++#endif
++
++char* get_argv(const int index, char** argv)
++{
++ char* result = NULL;
++ int len;
++
++#ifdef WIN32
++ int numargs;
++ wchar_t** argw = CommandLineToArgvW(GetCommandLineW(), &numargs);
++
++ // determine the buffer length first (including the trailing null)
++ len = WideCharToMultiByte(CP_UTF8, 0, argw[index], -1, NULL, 0, NULL, NULL);
++ result = (char*)calloc(len, 1);
++ WideCharToMultiByte(CP_UTF8, 0, argw[index], -1, result, len, NULL, NULL);
++
++ GlobalFree(argw);
++#else
++ len = strlen(argv[index]) + 1;
++ result = (char*)calloc(len, 1);
++ strcpy(result, argv[index]);
++#endif
++
++ return result;
++}
+diff --git a/src/qmt_map2jnx/argv.h b/src/qmt_map2jnx/argv.h
+new file mode 100644
+index 00000000..0967d0b7
+--- /dev/null
++++ b/src/qmt_map2jnx/argv.h
+@@ -0,0 +1,16 @@
++/**********************************************************************************************
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++char* get_argv(const int index, char** argv);
+diff --git a/src/qmt_map2jnx/main.cpp b/src/qmt_map2jnx/main.cpp
+new file mode 100644
+index 00000000..bef9cc43
+--- /dev/null
++++ b/src/qmt_map2jnx/main.cpp
+@@ -0,0 +1,1039 @@
++/**********************************************************************************************
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "config.h"
++
++#ifdef _MSC_VER
++#define fseeko _fseeki64
++#define ftello _ftelli64
++#else
++#define _FILE_OFFSET_BITS 64
++#endif //
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <math.h>
++#include <wctype.h>
++
++
++#include <list>
++#include <string>
++#include <vector>
++
++#include <gdal_priv.h>
++#include <proj_api.h>
++#include <ogr_spatialref.h>
++
++extern "C"
++{
++#include <jpeglib.h>
++}
++
++#include "argv.h"
++
++
++#ifndef _MKSTR_1
++#define _MKSTR_1(x) #x
++#define _MKSTR(x) _MKSTR_1(x)
++#endif
++
++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR(VER_MINOR) "." _MKSTR(VER_STEP)
++#define WHAT_STR "qmt_map2jnx, Version " VER_STR
++
++#define JNX_MAX_TILES 50000 //6250
++#define JNX_MAX_TILE_SIZE 1024
++
++#define JPG_BLOCK_SIZE (JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE)
++
++#define HEADER_BLOCK_SIZE 1024
++
++#pragma pack(1)
++
++struct jnx_hdr_t
++{
++ jnx_hdr_t(): version(0x00000004), devid(0), expire(0), productId(0), crc(0), signature(0), signature_offset(0), zorder(25){}
++ uint32_t version; // byte 00000000..00000003
++ uint32_t devid; // byte 00000004..00000007
++ int32_t top; // byte 00000014..00000017
++ int32_t right; // byte 00000010..00000013
++ int32_t bottom; // byte 0000000C..0000000F
++ int32_t left; // byte 00000008..0000000B
++ uint32_t details; // byte 00000018..0000001B
++ uint32_t expire; // byte 0000001C..0000001F
++ uint32_t productId; // byte 00000020..00000023
++ uint32_t crc; // byte 00000024..00000027
++ uint32_t signature; // byte 00000028..0000002B
++ uint32_t signature_offset; // byte 0000002C..0000002F
++ uint32_t zorder; // byte 00000030..00000033
++};
++
++
++struct jnx_level_t
++{
++ jnx_level_t(): nTiles(0), offset(0), scale(0), dummy(2){}
++
++ uint32_t nTiles;
++ uint32_t offset;
++ uint32_t scale;
++ uint32_t dummy;
++};
++
++struct jnx_tile_t
++{
++ jnx_tile_t() : top(0), right(0), bottom(0), left(0), width(0), height(0), size(0), offset(0){}
++ int32_t top;
++ int32_t right;
++ int32_t bottom;
++ int32_t left;
++ uint16_t width;
++ uint16_t height;
++ uint32_t size;
++ uint32_t offset;
++};
++
++
++#ifdef WIN32
++#pragma pack()
++#else
++#pragma pack(0)
++#endif
++
++struct file_t
++{
++ file_t(): dataset(0), pj(0){memset(colortable,0, sizeof(colortable));}
++ ~file_t()
++ {
++ //if(dataset) delete dataset;
++ if(pj) pj_free(pj);
++ }
++
++ bool operator<(const file_t& other) const
++ {
++ return (xscale > other.xscale);
++ }
++
++ std::string filename;
++ std::string projection;
++ GDALDataset * dataset;
++ projPJ pj;
++ uint32_t width;
++ uint32_t height;
++ double xscale;
++ double yscale;
++ double scale;
++ double xref1;
++ double yref1;
++ double xref2;
++ double yref2;
++
++ double lon1;
++ double lat1;
++ double lon2;
++ double lat2;
++
++ uint32_t colortable[256];
++
++};
++
++struct level_t : public jnx_level_t
++{
++ std::list<file_t *> files;
++ uint32_t tileSize;
++};
++
++struct scale_t
++{
++ double scale;
++ uint32_t jnxScale;
++};
++
++/// number of used levels
++static int32_t nLevels;
++/// up to five levels. nLevels gives the actual count
++static level_t levels[5];
++/// information about all files
++static std::list<file_t> files;
++/// the target lon/lat WGS84 projection
++static projPJ wgs84;
++/// the JNX file header to be copied to the outfile
++static jnx_hdr_t jnx_hdr;
++/// the tile information table for all 5 levels
++static jnx_tile_t tileTable[JNX_MAX_TILES * 5];
++/// tile buffer for 8 bit palette tiles, private to readTile
++static uint8_t tileBuf8Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE] = {0};
++/// tile buffer for 24 bit raw RGB tiles, private to writeTile
++static uint8_t tileBuf24Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE * 3] = {0};
++/// tile buffer for 32 bit raw RGBA tiles
++static uint32_t tileBuf32Bit[JNX_MAX_TILE_SIZE * JNX_MAX_TILE_SIZE] = {0};
++/// internal jpeg buffer used by write tile.
++static std::vector<JOCTET> jpgbuf;
++
++static void prinfFileinfo(const file_t& file)
++{
++ printf("\n\n----------------------");
++ printf("\n%s:", file.filename.c_str());
++ printf("\nprojection: %s", file.projection.c_str());
++ printf("\nwidth: %i pixel height: %i pixel", file.width, file.height);
++
++ if(pj_is_latlong(file.pj))
++ {
++ printf("\narea (top/left, bottom/right): %f %f, %f %f", file.lat1, file.lon1, file.lat2, file.lon2);
++ printf("\nxscale: %f °/px, yscale: %f °/px", file.xscale, file.yscale);
++ }
++ else
++ {
++ printf("\narea (top/left, bottom/right): %f %f, %f %f", file.lat1, file.lon1, file.lat2, file.lon2);
++ printf("\nxscale: %f m/px, yscale: %f m/px", file.xscale, file.yscale);
++ }
++ printf("\nreal scale: %f m/px", file.scale);
++}
++
++bool readTile(uint32_t xoff, uint32_t yoff, uint32_t xsize, uint32_t ysize, file_t& file, uint32_t * output)
++{
++ GDALDataset * dataset = file.dataset;
++ int32_t rasterBandCount = dataset->GetRasterCount();
++
++ memset(output,-1, sizeof(uint32_t) * xsize * ysize);
++
++ if(rasterBandCount == 1)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(1);
++ if(pBand->RasterIO(GF_Read,(int)xoff,(int)yoff, xsize, ysize, tileBuf8Bit,xsize,ysize,GDT_Byte,0,0) == CE_Failure)
++ {
++ return false;
++ }
++
++ for(unsigned int i = 0; i < (xsize * ysize); i++)
++ {
++ output[i] = file.colortable[tileBuf8Bit[i]];
++ }
++ }
++ else
++ {
++ for(int b = 1; b <= rasterBandCount; ++b)
++ {
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(b);
++
++ uint32_t mask = ~(0x000000FF << (8*(b-1)));
++
++ if(pBand->RasterIO(GF_Read,(int)xoff,(int)yoff, xsize, ysize, tileBuf8Bit,xsize,ysize,GDT_Byte,0,0) == CE_Failure)
++ {
++ return false;
++ }
++
++ for(unsigned int i = 0; i < (xsize * ysize); i++)
++ {
++ uint32_t pixel = output[i];
++
++ pixel &= mask;
++ pixel |= tileBuf8Bit[i] << (8*(b-1));
++ output[i] = pixel;
++ }
++ }
++ }
++
++ return true;
++}
++
++
++
++static void init_destination (j_compress_ptr cinfo)
++{
++ jpgbuf.resize(JPG_BLOCK_SIZE);
++ cinfo->dest->next_output_byte = &jpgbuf[0];
++ cinfo->dest->free_in_buffer = jpgbuf.size();
++}
++
++static boolean empty_output_buffer (j_compress_ptr cinfo)
++{
++ size_t oldsize = jpgbuf.size();
++ jpgbuf.resize(oldsize + JPG_BLOCK_SIZE);
++ cinfo->dest->next_output_byte = &jpgbuf[oldsize];
++ cinfo->dest->free_in_buffer = jpgbuf.size() - oldsize;
++ return true;
++}
++
++static void term_destination (j_compress_ptr cinfo)
++{
++ jpgbuf.resize(jpgbuf.size() - cinfo->dest->free_in_buffer);
++}
++
++
++static uint32_t writeTile(uint32_t xsize, uint32_t ysize, uint32_t * raw_image, FILE * fid, int quality, int subsampling)
++{
++ uint32_t size = 0;
++ struct jpeg_compress_struct cinfo;
++ struct jpeg_error_mgr jerr;
++ JSAMPROW row_pointer[1];
++
++ jpeg_destination_mgr destmgr = {0};
++ destmgr.init_destination = init_destination;
++ destmgr.empty_output_buffer = empty_output_buffer;
++ destmgr.term_destination = term_destination;
++
++ // convert from RGBA to RGB
++ for(uint32_t r = 0; r < ysize; r++)
++ {
++ for(uint32_t c = 0; c < xsize; c++)
++ {
++ uint32_t pixel = raw_image[r * xsize + c];
++ tileBuf24Bit[r * xsize * 3 + c * 3] = pixel & 0x0FF;
++ tileBuf24Bit[r * xsize * 3 + c * 3 + 1] = (pixel >> 8) & 0x0FF;
++ tileBuf24Bit[r * xsize * 3 + c * 3 + 2] = (pixel >> 16) & 0x0FF;
++ }
++ }
++
++ cinfo.err = jpeg_std_error( &jerr );
++ jpeg_create_compress(&cinfo);
++
++ cinfo.dest = &destmgr;
++ cinfo.image_width = xsize;
++ cinfo.image_height = ysize;
++ cinfo.input_components = 3;
++ cinfo.in_color_space = JCS_RGB;
++
++ jpeg_set_defaults( &cinfo );
++
++ if (subsampling != -1)
++ {
++ switch (subsampling)
++ {
++ case 422: // 2x1, 1x1, 1x1 (4:2:2) : Medium
++ {
++ cinfo.comp_info[0].h_samp_factor = 2;
++ cinfo.comp_info[0].v_samp_factor = 1;
++ cinfo.comp_info[1].h_samp_factor = 1;
++ cinfo.comp_info[1].v_samp_factor = 1;
++ cinfo.comp_info[2].h_samp_factor = 1;
++ cinfo.comp_info[2].v_samp_factor = 1;
++ break;
++ }
++ case 411: // 2x2, 1x1, 1x1 (4:1:1) : High
++ {
++ cinfo.comp_info[0].h_samp_factor = 2;
++ cinfo.comp_info[0].v_samp_factor = 2;
++ cinfo.comp_info[1].h_samp_factor = 1;
++ cinfo.comp_info[1].v_samp_factor = 1;
++ cinfo.comp_info[2].h_samp_factor = 1;
++ cinfo.comp_info[2].v_samp_factor = 1;
++ break;
++ }
++ case 444: // 1x1 1x1 1x1 (4:4:4) : None
++ {
++ cinfo.comp_info[0].h_samp_factor = 1;
++ cinfo.comp_info[0].v_samp_factor = 1;
++ cinfo.comp_info[1].h_samp_factor = 1;
++ cinfo.comp_info[1].v_samp_factor = 1;
++ cinfo.comp_info[2].h_samp_factor = 1;
++ cinfo.comp_info[2].v_samp_factor = 1;
++ break;
++ }
++ }
++ }
++
++ if (quality != -1)
++ {
++ jpeg_set_quality( &cinfo, quality, TRUE );
++ }
++
++ jpeg_start_compress( &cinfo, TRUE );
++
++ while( cinfo.next_scanline < cinfo.image_height )
++ {
++ row_pointer[0] = (JSAMPLE*)&tileBuf24Bit[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
++ jpeg_write_scanlines( &cinfo, row_pointer, 1 );
++ }
++ /* similar to read file, clean up after we're done compressing */
++ jpeg_finish_compress( &cinfo );
++ jpeg_destroy_compress( &cinfo );
++
++ // write data to output file
++ size = jpgbuf.size() - 2;
++ fwrite(&jpgbuf[2], size, 1, fid);
++
++ return size;
++}
++
++static double distance(const double u1, const double v1, const double u2, const double v2)
++{
++ double dU = u2 - u1; // lambda
++ double dV = v2 - v1; // roh
++
++ double d = 2*asin(sqrt(sin(dV/2) * sin(dV/2) + cos(v1) * cos(v2) * sin(dU/2) * sin(dU/2)));
++
++ return 6371010 * d;
++}
++
++static uint32_t scale2jnx(double scale)
++{
++ /*
++ Ok, I've made some calculations, and got the following formula to
++ calculate the JNX scale (S) depending on the map's meters/pixel
++ ratio (R):
++
++ S(R) =
++ qRound(
++ 76437 *
++ exp(
++ ln(2.000032708011) *
++ qRound(
++ ln(R * 130.2084 / 76437) /
++ ln(2.000032708011)
++ )
++ )
++ )
++
++
++ where
++ qRound - is a function which returns the closest integer from
++ floating point value, [unfortunately its defined in C99 but not standard C++]
++ exp - exponent,
++ ln - natural logarithm.
++
++ Magic number 130.2084 - is an average value for
++ (JNX scale) / (maps meters per pixel)
++ ratio among all zoom levels in metric system.
++
++ Magic number 2.000032708011 is a ratio on which our standard scale
++ table is built. It is (76437 / 4777) ^ (1/4).
++ */
++
++ return (uint32_t)floor(0.5 + 76437 * exp(log(2.000032708011) * floor(0.5 + log(scale * 10 * 130.2084 / 76437) / log(2.000032708011) ) ) );
++}
++
++static char randChar()
++{
++ char buf[2];
++#if defined(HAVE_ARC4RANDOM)
++ int r = (int)((arc4random() * 16.0) / UINT_MAX);
++#else
++ int r = (int)((rand() * 16.0) / RAND_MAX);
++#endif
++ sprintf(buf,"%X", r & 0x0F);
++ return buf[0];
++}
++
++static void createGUID(char * guid)
++{
++#if !defined(HAVE_ARC4RANDOM)
++ srand((unsigned int)time(0));
++#endif
++
++ guid[0] = randChar();
++ guid[1] = randChar();
++ guid[2] = randChar();
++ guid[3] = randChar();
++ guid[4] = randChar();
++ guid[5] = randChar();
++ guid[6] = randChar();
++ guid[7] = randChar();
++ guid[8] = '-';
++ guid[9] = randChar();
++ guid[10] = randChar();
++ guid[11] = randChar();
++ guid[12] = randChar();
++ guid[13] = '-';
++ guid[14] = randChar();
++ guid[15] = randChar();
++ guid[16] = randChar();
++ guid[17] = randChar();
++ guid[18] = '-';
++ guid[19] = randChar();
++ guid[20] = randChar();
++ guid[21] = randChar();
++ guid[22] = randChar();
++ guid[23] = '-';
++ guid[24] = randChar();
++ guid[25] = randChar();
++ guid[26] = randChar();
++ guid[27] = randChar();
++ guid[28] = randChar();
++ guid[29] = randChar();
++ guid[30] = randChar();
++ guid[31] = randChar();
++ guid[32] = randChar();
++ guid[33] = randChar();
++ guid[34] = randChar();
++ guid[35] = randChar();
++ guid[36] = 0;
++
++}
++
++/// this code is from the GDAL project
++static void printProgress(int current, int total)
++{
++ double dfComplete = double(current)/double(total);
++
++ static int nLastTick = -1;
++ int nThisTick = (int) (dfComplete * 40.0);
++
++ nThisTick = MIN(40,MAX(0,nThisTick));
++
++ // Have we started a new progress run?
++ if( nThisTick < nLastTick && nLastTick >= 39 )
++ {
++ nLastTick = -1;
++ }
++
++ if( nThisTick <= nLastTick )
++ {
++ return;
++ }
++
++ while( nThisTick > nLastTick )
++ {
++ nLastTick++;
++ if( nLastTick % 4 == 0 )
++ {
++ fprintf( stdout, "%d", (nLastTick / 4) * 10 );
++ }
++ else
++ {
++ fprintf( stdout, "." );
++ }
++ }
++
++ if( nThisTick == 40 )
++ {
++ fprintf( stdout, " - done.\n" );
++ }
++ else
++ {
++ fflush( stdout );
++ }
++
++}
++
++
++int main(int argc, char ** argv)
++{
++ uint16_t tmp16;
++ const uint8_t dummy = 0;
++ uint32_t tileTableStart = 0;
++ uint32_t tileCnt = 0;
++ uint32_t tilesTotal = 0;
++ char projstr[1024];
++ OGRSpatialReference oSRS;
++ int quality = -1;
++ int subsampling = -1;
++
++ const char *copyright = "Unknown";
++ const char *subscname = "BirdsEye";
++ const char *mapname = "Unknown";
++
++ char *copyright_buf = NULL;
++ char *subscname_buf = NULL;
++ char *mapname_buf = NULL;
++
++ std::vector<int> forced_scale_values;
++
++ printf("\n****** %s ******\n", WHAT_STR);
++
++ if(argc < 2)
++ {
++ fprintf(stderr,"\nusage: qmt_map2jnx -q <1..100> -s <411|422|444> -p <0..> -c \"copyright notice\" -m \"BirdsEye\" -n \"Unknown\" -x file1_scale,file2_scale,...,fileN_scale <file1> <file2> ... <fileN> <outputfile>\n");
++ fprintf(stderr,"\n");
++ fprintf(stderr," -q The JPEG quality from 1 to 100. Default is 75 \n");
++ fprintf(stderr," -s The chroma subsampling. Default is 411 \n");
++ fprintf(stderr," -p The product ID. Default is 0 \n");
++ fprintf(stderr," -c The copyright notice. Default is \"Unknown\" \n");
++ fprintf(stderr," -m The subscription product name. Default is \"BirdsEye\" \n");
++ fprintf(stderr," -n The map name. Default is \"Unknown\" \n");
++ fprintf(stderr," -z The z order (drawing order). Default is 25\n");
++ fprintf(stderr," -x Override levels scale. Default: autodetect\n");
++ fprintf(stderr,"\n");
++ fprintf(stderr,"\nThe projection of the input files must have the same latitude along");
++ fprintf(stderr,"\na pixel row. Mecator and Longitude/Latitude projections match this");
++ fprintf(stderr,"\nthis property. Transversal Merkator or Lambert projections do not.");
++ fprintf(stderr,"\n");
++ fprintf(stderr,"\nTo rectify a geotiff map, you can use the gdalwarp command, e.g.");
++ fprintf(stderr,"\ngdalwarp -t_srs \"EPSG:4326\" <inputfile> <outputfile>");
++ fprintf(stderr,"\n");
++ fprintf(stderr,"Scale levels must be pass in same order as level files pointed.\n");
++ fprintf(stderr,"Empty and zero values equal to autodetect. We can point only needed\n");
++ fprintf(stderr,"levels, like:\n");
++ fprintf(stderr," -x 45356,,,75; -x ,,,,75\n");
++ fprintf(stderr,"Calculated levels table can be found:\n");
++ fprintf(stderr," English: http://whiter.brinkster.net/en/JNX.shtml\n");
++ fprintf(stderr," Russian: http://whiter.brinkster.net/JNX.shtml\n");
++ fprintf(stderr,"Most common values for different map scales:\n");
++ fprintf(stderr," JNX scale Map scale\n");
++ fprintf(stderr," ------------- ---------\n");
++ fprintf(stderr," 78125-31250 1:1 000 000\n");
++ fprintf(stderr," 20834-7813 1:500 000\n");
++ fprintf(stderr," 7813-3125 1:200 000\n");
++ fprintf(stderr," 3125-2084 1:100 000\n");
++ fprintf(stderr," 2084-782 1:50 000\n");
++ fprintf(stderr," 782-32 1:25 000\n");
++ fprintf(stderr," 32-21 1:10 000\n");
++ fprintf(stderr," 21-14 1:5000, 1:2000\n");
++ fprintf(stderr,"\n");
++ fprintf(stderr,"\n");
++ exit(-1);
++ }
++
++ GDALAllRegister();
++ wgs84 = pj_init_plus("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
++
++ // read geo information from input files
++ //files.resize(argc - 2);
++ int skip_next_arg = 0;
++ int files_count = 0;
++
++ for(int i = 1; i < (argc - 1); i++)
++ {
++ if (skip_next_arg)
++ {
++ skip_next_arg = 0;
++ continue;
++ }
++
++ if (argv[i][0] == '-')
++ {
++ if (towupper(argv[i][1]) == 'Q')
++ {
++ quality = atol(argv[i+1]);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'S')
++ {
++ subsampling = atol(argv[i+1]);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'P')
++ {
++ jnx_hdr.productId = atol(argv[i+1]);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'C')
++ {
++ copyright = copyright_buf = get_argv(i + 1, argv);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'M')
++ {
++ subscname = subscname_buf = get_argv(i + 1, argv);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'N')
++ {
++ mapname = mapname_buf = get_argv(i + 1, argv);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'Z')
++ {
++ jnx_hdr.zorder = atol(argv[i+1]);
++ skip_next_arg = 1;
++ continue;
++ }
++ else if (towupper(argv[i][1]) == 'X')
++ {
++ skip_next_arg = 1;
++
++ std::string scales_buf(get_argv(i + 1, argv));
++ size_t pos = 0;
++ size_t last_pos = 0;
++
++ pos = scales_buf.find_first_of(',');
++ std::string val;
++ while (pos != std::string::npos)
++ {
++ val = scales_buf.substr(last_pos, pos - last_pos);
++ last_pos = pos + 1;
++ pos = scales_buf.find_first_of(',', pos + 1);
++
++ //printf("val: %s : %d\n", val.c_str(), pos);
++ forced_scale_values.push_back(atol(val.c_str()));
++ }
++ val = scales_buf.substr(last_pos, pos);
++ //printf("val: %s : %d\n", val.c_str(), pos);
++ forced_scale_values.push_back(atol(val.c_str()));
++
++ continue;
++ }
++
++ }
++
++ files_count++;
++ files.resize(files_count);
++
++ double dist;
++
++ GDALDataset * dataset = (GDALDataset*)GDALOpen(argv[i],GA_ReadOnly);
++ if(dataset == 0)
++ {
++ fprintf(stderr,"\nFailed to open %s\n", argv[i]);
++ exit(-1);
++ }
++
++ projPJ pj;
++ char * ptr = projstr;
++
++ if(dataset->GetProjectionRef())
++ {
++ strncpy(projstr,dataset->GetProjectionRef(),sizeof(projstr));
++ }
++ oSRS.importFromWkt(&ptr);
++ oSRS.exportToProj4(&ptr);
++
++ pj = pj_init_plus(ptr);
++ if(pj == 0)
++ {
++ fprintf(stderr,"\nUnknown projection in file %s\n", argv[i]);
++ exit(-1);
++ }
++
++ double adfGeoTransform[6];
++ dataset->GetGeoTransform( adfGeoTransform );
++
++ std::list<file_t>::iterator f = files.begin();
++ std::advance(f, files_count - 1);
++
++ file_t& file = *f;
++ file.filename = argv[i];
++ file.projection = ptr;
++ file.dataset = dataset;
++ file.pj = pj;
++ file.width = dataset->GetRasterXSize();
++ file.height = dataset->GetRasterYSize();
++ file.xscale = adfGeoTransform[1];
++ file.yscale = adfGeoTransform[5];
++ file.xref1 = adfGeoTransform[0];
++ file.yref1 = adfGeoTransform[3];
++ file.xref2 = file.xref1 + file.width * file.xscale;
++ file.yref2 = file.yref1 + file.height * file.yscale;
++
++ if(pj_is_latlong(file.pj))
++ {
++ file.lon1 = file.xref1;
++ file.lat1 = file.yref1;
++ file.lon2 = file.xref2;
++ file.lat2 = file.yref2;
++ }
++ else
++ {
++ file.lon1 = file.xref1;
++ file.lat1 = file.yref1;
++ file.lon2 = file.xref2;
++ file.lat2 = file.yref2;
++
++ pj_transform(pj,wgs84,1,0,&file.lon1,&file.lat1,0);
++ pj_transform(pj,wgs84,1,0,&file.lon2,&file.lat2,0);
++
++ file.lon1 *= RAD_TO_DEG;
++ file.lat1 *= RAD_TO_DEG;
++ file.lon2 *= RAD_TO_DEG;
++ file.lat2 *= RAD_TO_DEG;
++ }
++
++ dist = distance(file.lon1 * DEG_TO_RAD, file.lat1 * DEG_TO_RAD, file.lon2 * DEG_TO_RAD, file.lat1 * DEG_TO_RAD);
++ file.scale = dist/file.width;
++
++ // fill color table if necessary
++ GDALRasterBand * pBand;
++ pBand = dataset->GetRasterBand(1);
++
++ if(pBand->GetColorInterpretation() == GCI_PaletteIndex)
++ {
++ GDALColorTable * pct = pBand->GetColorTable();
++ for(int c=0; c < pct->GetColorEntryCount(); ++c)
++ {
++ const GDALColorEntry& e = *pct->GetColorEntry(c);
++ file.colortable[c] = e.c1 | (e.c2 << 8) | (e.c3 << 16) | (e.c4 << 24);
++ }
++ }
++ else if(pBand->GetColorInterpretation() == GCI_GrayIndex )
++ {
++ for(int c=0; c < 256; ++c)
++ {
++ file.colortable[c] = c | (c << 8) | (c << 16) | 0xFF000000;
++ }
++ }
++
++ int success = 0;
++ int idx = (int)pBand->GetNoDataValue(&success);
++
++ if(success)
++ {
++ file.colortable[idx] &= 0x00FFFFFF;
++ }
++ }
++
++ // apply sorted files to levels and extract file header data
++ double right = -180.0;
++ double top = -90.0;
++ double left = 180.0;
++ double bottom = 90.0;
++
++ double scale = 0.0;
++ files.sort();
++ std::list<file_t>::iterator f;
++ for(f = files.begin(); f != files.end(); f++)
++ {
++ file_t& file = *f;
++ prinfFileinfo(file);
++
++ if(file.lon1 < left) left = file.lon1;
++ if(file.lat1 > top) top = file.lat1;
++ if(file.lat2 < bottom) bottom = file.lat2;
++ if(file.lon2 > right) right = file.lon2;
++
++ if(scale != 0.0 && ((fabs(scale - file.xscale)) / scale) > 0.02)
++ {
++ nLevels++;
++ if(nLevels > 4)
++ {
++ fprintf(stderr,"\nToo many different detail levels.\n");
++ exit(-1);
++ }
++ }
++ scale = file.xscale;
++
++ levels[nLevels].files.push_back(&file);
++ }
++ nLevels++;
++
++ FILE * fid = fopen(argv[argc-1],"wb");
++ if(fid == 0)
++ {
++ fprintf(stderr,"\nFailed to create file %s\n", argv[argc-1]);
++ exit(-1);
++ }
++
++ jnx_hdr.left = (int32_t)((left * 0x7FFFFFFF) / 180);
++ jnx_hdr.top = (int32_t)((top * 0x7FFFFFFF) / 180);
++ jnx_hdr.right = (int32_t)((right * 0x7FFFFFFF) / 180);
++ jnx_hdr.bottom = (int32_t)((bottom * 0x7FFFFFFF) / 180);
++
++ jnx_hdr.details = nLevels;
++
++ printf("\n\n======== map header ========");
++ printf("\nmap area (top/left, bottom/right): %f %f, %f %f", left, top, right, bottom);
++ printf("\n %08X %08X, %08X %08X", jnx_hdr.left, jnx_hdr.top, jnx_hdr.right, jnx_hdr.bottom);
++ printf("\nnumber of detail levels: %i", jnx_hdr.details);
++ printf("\nz-order: %i\n", jnx_hdr.zorder);
++
++
++ for(int i=0; i<HEADER_BLOCK_SIZE; i++)
++ {
++ fwrite(&dummy, sizeof(dummy), 1, fid);
++ }
++ fseeko(fid,0,SEEK_SET);
++ fwrite(&jnx_hdr, sizeof(jnx_hdr), 1, fid);
++
++ // --------------------------------------------------------------
++ // get all information to write the table of detail levels and the dummy tile table
++ for(int i = 0; i < nLevels; i++)
++ {
++ uint32_t size = 256;
++ level_t& level = levels[i];
++ std::list<file_t *>::iterator f;
++ double scale = 0.0;
++
++ while(size <= JNX_MAX_TILE_SIZE)
++ {
++ level.nTiles = 0;
++ level.tileSize = size;
++ for(f = level.files.begin(); f != level.files.end(); f++)
++ {
++ file_t& file = *(*f);
++ double xTiles = file.width / double(size);
++ double yTiles = file.height / double(size);
++ level.nTiles += int(ceil(xTiles)) * int(ceil(yTiles));
++
++ scale = file.scale;
++ }
++
++ if(level.nTiles < JNX_MAX_TILES)
++ {
++ break;
++ }
++ size <<= 1;
++ }
++
++
++ level.offset = tilesTotal * sizeof(jnx_tile_t) + HEADER_BLOCK_SIZE; // still has to be offset by complete header
++ if (forced_scale_values.size() == 0 || (unsigned)i >= forced_scale_values.size() || forced_scale_values[i] == 0)
++ {
++ level.scale = scale2jnx(scale);
++ }
++ else
++ {
++ level.scale = forced_scale_values[i];
++ }
++ tilesTotal += level.nTiles;
++
++ fwrite(&level.nTiles, sizeof(level.nTiles), 1, fid);
++ fwrite(&level.offset, sizeof(level.offset), 1, fid);
++ fwrite(&level.scale, sizeof(level.scale), 1, fid);
++ fwrite(&level.dummy, sizeof(level.dummy), 1, fid);
++ fwrite(copyright, strlen(copyright) + 1, 1, fid);
++
++
++ printf("\n Level %i: % 5i tiles, offset %08X, scale: %i, %ix%i", i, level.nTiles, level.offset, level.scale, level.tileSize, level.tileSize);
++
++ }
++
++ // --------------------------------------------------------------
++ // write map loader info block
++ uint32_t blockVersion = 0x00000009;
++ char GUID[40];
++ createGUID(GUID);
++
++ tmp16 = jnx_hdr.productId;
++
++ fwrite(&blockVersion, sizeof(blockVersion), 1, fid);
++ fwrite(GUID, 37, 1, fid);
++ fwrite(subscname, strlen(subscname) + 1, 1, fid);
++ fwrite(&dummy, sizeof(dummy), 1, fid);
++ fwrite(&tmp16, sizeof(tmp16), 1, fid);
++ fwrite(mapname, strlen(mapname) + 1, 1, fid);
++ fwrite(&nLevels , sizeof(nLevels), 1, fid);
++ for(int i = 1; i <= nLevels; i++)
++ {
++ char str[40];
++ sprintf(str,"Level %i", i);
++ fwrite(str, strlen(str) + 1, 1, fid);
++ fwrite(str, strlen(str) + 1, 1, fid);
++ fwrite(copyright, strlen(copyright) + 1, 1, fid);
++ fwrite(&i,sizeof(i), 1, fid);
++ }
++
++ // --------------------------------------------------------------
++ // write dummy tile table
++ tileTableStart = HEADER_BLOCK_SIZE;
++ fseeko(fid, tileTableStart, SEEK_SET);
++ fwrite(tileTable, sizeof(jnx_tile_t), tilesTotal, fid);
++
++ // --------------------------------------------------------------
++ // read tiles from input files and write jpeg coded tiles to output file
++ printf("\n\nStart conversion:\n");
++ for(int l = 0; l < nLevels; l++)
++ {
++ level_t& level = levels[l];
++
++ std::list<file_t *>::iterator f;
++ for(f = level.files.begin(); f != level.files.end(); f++)
++ {
++ file_t& file = *(*f);
++
++ uint32_t xoff = 0;
++ uint32_t yoff = 0;
++
++ uint32_t xsize = level.tileSize;
++ uint32_t ysize = level.tileSize;
++
++ while(yoff < file.height)
++ {
++ if(ysize > (file.height - yoff))
++ {
++ ysize = file.height - yoff;
++ }
++
++ xsize = level.tileSize;
++ xoff = 0;
++
++ while(xoff < file.width)
++ {
++ if(xsize > (file.width - xoff))
++ {
++ xsize = (file.width - xoff);
++ }
++
++ // //
++ if(!readTile(xoff, yoff, xsize, ysize, file, tileBuf32Bit))
++ {
++ fprintf(stderr,"\nError reading tiles from map file\n");
++ exit(-1);
++ }
++
++ jnx_tile_t& tile = tileTable[tileCnt++];
++ if(pj_is_latlong(file.pj))
++ {
++
++ double u1 = file.lon1 + xoff * file.xscale;
++ double v1 = file.lat1 + yoff * file.yscale;
++ double u2 = file.lon1 + (xoff + xsize) * file.xscale;
++ double v2 = file.lat1 + (yoff + ysize) * file.yscale;
++
++
++ tile.left = (int32_t)(u1 * 0x7FFFFFFF / 180);
++ tile.top = (int32_t)(v1 * 0x7FFFFFFF / 180);
++ tile.right = (int32_t)(u2 * 0x7FFFFFFF / 180);
++ tile.bottom = (int32_t)(v2 * 0x7FFFFFFF / 180);
++
++ }
++ else
++ {
++ double u1 = file.xref1 + xoff * file.xscale;
++ double v1 = file.yref1 + yoff * file.yscale;
++ double u2 = file.xref1 + (xoff + xsize) * file.xscale;
++ double v2 = file.yref1 + (yoff + ysize) * file.yscale;
++
++ pj_transform(file.pj,wgs84,1,0,&u1,&v1,0);
++ pj_transform(file.pj,wgs84,1,0,&u2,&v2,0);
++
++ tile.left = (int32_t)((u1 * RAD_TO_DEG) * 0x7FFFFFFF / 180);
++ tile.top = (int32_t)((v1 * RAD_TO_DEG) * 0x7FFFFFFF / 180);
++ tile.right = (int32_t)((u2 * RAD_TO_DEG) * 0x7FFFFFFF / 180);
++ tile.bottom = (int32_t)((v2 * RAD_TO_DEG) * 0x7FFFFFFF / 180);
++ }
++
++ tile.width = xsize;
++ tile.height = ysize;
++ tile.offset = (uint32_t)(ftello(fid) & 0x0FFFFFFFF);
++ tile.size = writeTile(xsize, ysize, tileBuf32Bit, fid, quality, subsampling);
++
++ printProgress(tileCnt, tilesTotal);
++ // //
++ xoff += xsize;
++ }
++
++ yoff += ysize;
++ }
++ }
++ }
++
++ // terminate output file
++ fwrite("BirdsEye", 8, 1, fid);
++
++ // write final tile table
++ fseeko(fid, tileTableStart, SEEK_SET);
++ fwrite(tileTable, sizeof(jnx_tile_t), tilesTotal, fid);
++ // done
++ fclose(fid);
++
++ // clean up
++ pj_free(wgs84);
++ GDALDestroyDriverManager();
++ if (copyright_buf)
++ free(copyright_buf);
++ if (subscname_buf)
++ free(subscname_buf);
++ if (mapname_buf)
++ free(mapname_buf);
++ printf("\n\n");
++ return 0;
++}
diff --git a/gis/qmapshack/rgb2pct.patch b/gis/qmapshack/rgb2pct.patch
new file mode 100644
index 0000000000000..92c5df87762fd
--- /dev/null
+++ b/gis/qmapshack/rgb2pct.patch
@@ -0,0 +1,971 @@
+From 763cfc149566325cce9e4690cb7b5f986048f86a Mon Sep 17 00:00:00 2001
+From: Oliver Eichler <oliver.eichler@dspsolutions.de>
+Date: Thu, 12 Sep 2019 20:32:06 +0200
+Subject: [PATCH] [QMS-3] Add qmt_rgb2pct from former sub-repo
+
+---
+ src/qmt_rgb2pct/CApp.cpp | 280 +++++++++++++++++++++++
+ src/qmt_rgb2pct/CApp.h | 55 +++++
+ src/qmt_rgb2pct/CMakeLists.txt | 117 ++++++++++
+ src/qmt_rgb2pct/README.md | 5 +
+ src/qmt_rgb2pct/locale/qmt_rgb2pct.ts | 126 ++++++++++
+ src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts | 127 ++++++++++
+ src/qmt_rgb2pct/main.cpp | 155 +++++++++++++
+ src/qmt_rgb2pct/version.h | 33 +++
+ 8 files changed, 898 insertions(+)
+ create mode 100644 src/qmt_rgb2pct/CApp.cpp
+ create mode 100644 src/qmt_rgb2pct/CApp.h
+ create mode 100644 src/qmt_rgb2pct/CMakeLists.txt
+ create mode 100644 src/qmt_rgb2pct/README.md
+ create mode 100644 src/qmt_rgb2pct/locale/qmt_rgb2pct.ts
+ create mode 100644 src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts
+ create mode 100644 src/qmt_rgb2pct/main.cpp
+ create mode 100644 src/qmt_rgb2pct/version.h
+
+diff --git a/src/qmt_rgb2pct/CApp.cpp b/src/qmt_rgb2pct/CApp.cpp
+new file mode 100644
+index 00000000..993ed759
+--- /dev/null
++++ b/src/qmt_rgb2pct/CApp.cpp
+@@ -0,0 +1,280 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CApp.h"
++
++#include <gdal_alg.h>
++#include <gdal_priv.h>
++#include <iostream>
++
++const GDALColorEntry CApp::noColor = {255,255,255,0};
++
++void printStdoutQString(const QString& str)
++{
++ QByteArray array = str.toUtf8();
++ printf("%s", array.data());
++ printf("\n");
++}
++
++void printStderrQString(const QString& str)
++{
++ QByteArray array = str.toUtf8();
++ fprintf(stderr, "%s", array.data());
++ fprintf(stderr, "\n");
++}
++
++
++
++CApp::CApp(qint32 ncolors, const QString& pctFilename, const QString &sctFilename, const QString &srcFilename, const QString &tarFilename)
++ : ncolors(ncolors)
++ , pctFilename(pctFilename)
++ , sctFilename(sctFilename)
++ , srcFilename(srcFilename)
++ , tarFilename(tarFilename)
++{
++ GDALAllRegister();
++}
++
++qint32 CApp::exec()
++{
++ qint32 res = 0;
++ GDALColorTable * ct = nullptr;
++ GDALDataset * dsSrc = nullptr;
++ try
++ {
++ dsSrc = (GDALDataset*)GDALOpenShared(srcFilename.toUtf8(),GA_ReadOnly);
++ if(dsSrc == nullptr)
++ {
++ throw tr("Failed to open source file.");
++ }
++
++ if(dsSrc->GetRasterCount() < 3 || dsSrc->GetRasterCount() > 4)
++ {
++ throw tr("Raster band count of source file must be either 3 or 4.");
++ }
++
++ if(QFile(tarFilename).exists())
++ {
++ QFile::remove(tarFilename);
++ }
++
++ ct = createColorTable(ncolors, pctFilename, dsSrc);
++ saveColorTable(ct, sctFilename);
++ ditherMap(dsSrc, tarFilename, ct);
++ }
++ catch(const QString& msg)
++ {
++ printStderrQString(msg);
++ res = -1;
++ }
++
++
++ GDALClose(dsSrc);
++ delete ct;
++ return res;
++}
++
++GDALColorTable * CApp::createColorTable(qint32 ncolors, const QString& pctFilename, GDALDataset * dataset)
++{
++ GDALColorTable * ct = nullptr;
++ try
++ {
++ if(pctFilename.isEmpty())
++ {
++ ct = (GDALColorTable*)GDALCreateColorTable(GPI_RGB);
++
++ printStdoutQString(tr("Calculate optimal color table from source file"));
++
++ int ok = GDALComputeMedianCutPCT(dataset->GetRasterBand(1),
++ dataset->GetRasterBand(2),
++ dataset->GetRasterBand(3),
++ nullptr,
++ ncolors,
++ ct,
++ GDALTermProgress,
++ 0
++ );
++
++ if(ok != CE_None)
++ {
++ throw tr("Failed to create color table.");
++ }
++ }
++ else
++ {
++ GDALDataset * dsPct = (GDALDataset*)GDALOpenShared(pctFilename.toUtf8(),GA_ReadOnly);
++ if(dsPct == nullptr)
++ {
++ throw tr("Failed to open file with palette.");
++ }
++
++ GDALRasterBand * band = (GDALRasterBand*)dsPct->GetRasterBand(1);
++
++ if((dsPct->GetRasterCount() != 1) || (band->GetColorInterpretation() != GCI_PaletteIndex))
++ {
++ GDALClose(dsPct);
++ throw tr("Palette file does not have a single band with a color table");
++ }
++
++ int ok = 0;
++ band->GetNoDataValue(&ok);
++
++ if(ok || band->GetColorTable()->GetColorEntryCount() > 255)
++ {
++ GDALClose(dsPct);
++ throw tr("The color table must not contain a \"no data\" value and it's size must not exceed 255 colors.");
++ }
++
++ ct = dsPct->GetRasterBand(1)->GetColorTable()->Clone();
++ }
++ }
++ catch(const QString& msg)
++ {
++ delete ct;
++ throw msg;
++ }
++ return ct;
++}
++
++void CApp::saveColorTable(GDALColorTable * ct, QString& sctFilename)
++{
++ if(sctFilename.isEmpty())
++ {
++ return;
++ }
++
++ if(!sctFilename.endsWith(".vrt"))
++ {
++ sctFilename += ".vrt";
++ }
++
++ QByteArray buf = sctFilename.toUtf8();
++ printStdoutQString(tr("Save color table to: %1").arg(buf.data()));
++
++ GDALDriverManager * drvman = GetGDALDriverManager();
++ GDALDriver * driver = drvman->GetDriverByName("VRT");
++ GDALDataset * dataset = driver->Create(sctFilename.toUtf8(), 1, 1, 1, GDT_Byte, {});
++
++ dataset->GetRasterBand(1)->SetColorInterpretation(GCI_PaletteIndex);
++ dataset->GetRasterBand(1)->SetColorTable(ct);
++
++ dataset->FlushCache();
++ GDALClose(dataset);
++}
++
++void CApp::ditherMap(GDALDataset * dsSrc, const QString& tarFilename, GDALColorTable *ct)
++{
++ if(tarFilename.isEmpty())
++ {
++ return;
++ }
++
++ qint32 xsize = dsSrc->GetRasterBand(1)->GetXSize();
++ qint32 ysize = dsSrc->GetRasterBand(1)->GetYSize();
++
++ GDALDriverManager * drvman = nullptr;
++ GDALDriver * driver = nullptr;
++ GDALDataset * dataset = nullptr;
++
++ try
++ {
++ const char * cargs[] = {"TILED=YES","COMPRESS=LZW", 0};
++ drvman = GetGDALDriverManager();
++ driver = drvman->GetDriverByName("GTiff");
++ dataset = driver->Create(tarFilename.toUtf8(), xsize, ysize, 1, GDT_Byte, (char**)cargs);
++
++ if(dataset == nullptr)
++ {
++ throw tr("Failed to create target file.");
++ }
++
++ dataset->GetRasterBand(1)->SetColorTable(ct);
++ dataset->GetRasterBand(1)->SetNoDataValue(ct->GetColorEntryCount());
++ dataset->SetProjection(dsSrc->GetProjectionRef());
++
++ double adfGeoTransform[6] = {0};
++ dsSrc->GetGeoTransform(adfGeoTransform);
++ dataset->SetGeoTransform(adfGeoTransform);
++
++ printStdoutQString(tr("Dither source file to target file"));
++ int res = GDALDitherRGB2PCT(dsSrc->GetRasterBand(1),
++ dsSrc->GetRasterBand(2),
++ dsSrc->GetRasterBand(3),
++ dataset->GetRasterBand(1),
++ ct,
++ GDALTermProgress,
++ 0
++ );
++ if(res != CE_None)
++ {
++ throw tr("Failed to dither file.");
++ }
++
++ if(dsSrc->GetRasterCount() == 3)
++ {
++ return;
++ }
++
++ GDALRasterBand * alpha = dsSrc->GetRasterBand(4);
++ GDALRasterBand * band = dataset->GetRasterBand(1);
++
++ QByteArray buffer1(xsize, 0);
++ QByteArray buffer2(xsize, 0);
++
++ quint8 nodata = band->GetNoDataValue();
++ printStdoutQString(tr("Apply alpha channel as no data value to target file"));
++ for(int y = 0; y < ysize; y++)
++ {
++ GDALTermProgress(double(xsize * y)/(xsize*ysize),0,0);
++ res = alpha->RasterIO(GF_Read, 0, y, xsize, 1, buffer1.data(), xsize, 1, GDT_Byte, 0, 0);
++ if(res != CE_None)
++ {
++ throw tr("Failed to read from alpha channel.");
++ }
++
++ res = band->RasterIO(GF_Read, 0, y, xsize, 1, buffer2.data(), xsize, 1, GDT_Byte, 0, 0);
++ if(res != CE_None)
++ {
++ throw tr("Failed to read from target file.");
++ }
++
++ for(int x = 0; x < xsize; x++)
++ {
++ if(buffer1[x] != char(0xFF))
++ {
++ buffer2[x] = nodata;
++ }
++ }
++
++ res = band->RasterIO(GF_Write, 0, y, xsize, 1, buffer2.data(), xsize, 1, GDT_Byte, 0, 0);
++ if(res != CE_None)
++ {
++ throw tr("Failed to write to target file.");
++ }
++ }
++ GDALTermProgress(1.0,0,0);
++ }
++ catch(const QString& msg)
++ {
++ GDALClose(dataset);
++ throw msg;
++ }
++
++ dataset->FlushCache();
++ GDALClose(dataset);
++}
+diff --git a/src/qmt_rgb2pct/CApp.h b/src/qmt_rgb2pct/CApp.h
+new file mode 100644
+index 00000000..e2e0f7ca
+--- /dev/null
++++ b/src/qmt_rgb2pct/CApp.h
+@@ -0,0 +1,55 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef CAPP_H
++#define CAPP_H
++
++#include <QtCore>
++#include <gdal.h>
++
++class GDALColorTable;
++class GDALDataset;
++
++class CApp
++{
++ Q_DECLARE_TR_FUNCTIONS(CApp)
++public:
++ CApp(qint32 ncolors, const QString& pctFilename, const QString& sctFilename, const QString& srcFilename, const QString& tarFilename);
++ virtual ~CApp() = default;
++
++ qint32 exec();
++
++private:
++ static GDALColorTable * createColorTable(qint32 ncolors, const QString& pctFilename, GDALDataset *dataset);
++ static void saveColorTable(GDALColorTable *ct, QString &sctFilename);
++ static void ditherMap(GDALDataset * dsSrc, const QString& tarFilename, GDALColorTable *ct);
++
++ qint32 ncolors = 0;
++ QString pctFilename;
++ QString sctFilename;
++ QString srcFilename;
++ QString tarFilename;
++
++ static const GDALColorEntry noColor;
++};
++
++void printStdoutQString(const QString& str);
++void printStderrQString(const QString& str);
++
++#endif //CAPP_H
++
+diff --git a/src/qmt_rgb2pct/CMakeLists.txt b/src/qmt_rgb2pct/CMakeLists.txt
+new file mode 100644
+index 00000000..c763595e
+--- /dev/null
++++ b/src/qmt_rgb2pct/CMakeLists.txt
+@@ -0,0 +1,117 @@
++# Prevent custom commands/targets outputs to be deleted by make clean
++# We need this to prevent .ts files from being deleted with make clean, when
++# UPDATE_TRANSLATIONS=ON
++# WARNING: Only works with Makefile generator.
++set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE)
++# Find includes in corresponding build directories
++set(CMAKE_INCLUDE_CURRENT_DIR ON)
++# Instruct CMake to run moc automatically when needed.
++set(CMAKE_AUTOMOC ON)
++
++###############################################################################################
++# Setup application name and version tags
++###############################################################################################
++
++set(APPLICATION_NAME qmt_rgb2pct)
++set(RGB2PCT_VERSION_MAJOR 1)
++set(RGB2PCT_VERSION_MINOR 0)
++set(RGB2PCT_VERSION_PATCH 0)
++
++add_definitions(
++ -DVER_MAJOR=${RGB2PCT_VERSION_MAJOR}
++ -DVER_MINOR=${RGB2PCT_VERSION_MINOR}
++ -DVER_STEP=${RGB2PCT_VERSION_PATCH}
++ -DVER_TWEAK=${VERSION_SUFFIX}
++ -DAPPLICATION_NAME=${APPLICATION_NAME}
++)
++
++###############################################################################################
++# All source files needed to compile
++###############################################################################################
++set( SRCS
++ main.cpp
++ CApp.cpp
++)
++
++set( HDRS
++ version.h
++ CApp.h
++)
++
++set( UIS
++)
++
++set( RCS
++)
++
++###############################################################################################
++# Some Qt magic
++###############################################################################################
++
++qt5_wrap_ui(UI_HDRS ${UIS})
++qt5_add_resources(RC_SRCS ${RCS})
++
++###############################################################################################
++# Translation related stuff
++###############################################################################################
++translate_ts(${APPLICATION_NAME}_QM_FILES
++ UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS}
++ UPDATE_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}" ${KEEP_OLD_TRANSLATIONS}
++ SOURCES ${SRCS} ${HDRS} ${UIS}
++ TEMPLATE ${APPLICATION_NAME}
++ TRANSLATION_DIR "locale"
++)
++
++###############################################################################################
++# Build source file and include paths lists
++###############################################################################################
++set(MAININP
++ ${SRCS}
++ ${HDRS}
++ ${UI_HDRS}
++ ${RC_SRCS}
++ ${${APPLICATION_NAME}_QM_FILES}
++ ${${APPLICATION_NAME}_DESKTOP_FILES}
++)
++
++include_directories(
++ SYSTEM # this prevents warnings from non-QMS headers
++ ${CMAKE_BINARY_DIR}
++ ${GDAL_INCLUDE_DIRS}
++ ${PROJ4_INCLUDE_DIRS}
++)
++
++if(APPLE)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/Foundation.framework)
++ INCLUDE_DIRECTORIES(/System/Library/Frameworks/DiskArbitration.framework)
++endif(APPLE)
++
++
++###############################################################################################
++# Build the executable and define necessary libraries.
++###############################################################################################
++add_executable(${APPLICATION_NAME} WIN32 ${MAININP})
++
++target_link_libraries(${APPLICATION_NAME}
++ Qt5::Core
++ ${GDAL_LIBRARIES}
++ ${PROJ4_LIBRARIES}
++)
++
++if(APPLE)
++ target_link_libraries(${APPLICATION_NAME}
++ ${Foundation_LIBRARY}
++ ${DiskArbitration_LIBRARY}
++ )
++endif(APPLE)
++
++
++###############################################################################################
++# Install target related stuff
++###############################################################################################
++install(TARGETS ${APPLICATION_NAME} DESTINATION ${BIN_INSTALL_DIR})
++
++if (UNIX AND NOT WIN32 AND NOT APPLE)
++ install(FILES ${${APPLICATION_NAME}_QM_FILES} DESTINATION ${DATA_INSTALL_PREFIX}/${APPLICATION_NAME}/translations)
++ install(FILES ${${APPLICATION_NAME}_DESKTOP_FILES} DESTINATION ${XDG_APPS_DIR})
++endif (UNIX AND NOT WIN32 AND NOT APPLE)
+diff --git a/src/qmt_rgb2pct/README.md b/src/qmt_rgb2pct/README.md
+new file mode 100644
+index 00000000..21e6c750
+--- /dev/null
++++ b/src/qmt_rgb2pct/README.md
+@@ -0,0 +1,5 @@
++This is a sub-project of QMapShack and it's not supposed to compile on it's own. Please refere to
++
++https://bitbucket.org/maproom/qmapshack/overview
++
++to check out and compile this project.
+\ No newline at end of file
+diff --git a/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts b/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts
+new file mode 100644
+index 00000000..02904577
+--- /dev/null
++++ b/src/qmt_rgb2pct/locale/qmt_rgb2pct.ts
+@@ -0,0 +1,126 @@
++<?xml version="1.0" encoding="utf-8"?>
++<!DOCTYPE TS>
++<TS version="2.1">
++<context>
++ <name>CApp</name>
++ <message>
++ <location filename="../CApp.cpp" line="63"/>
++ <source>Failed to open source file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="68"/>
++ <source>Raster band count of source file must be either 3 or 4.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="101"/>
++ <source>Calculate optimal color table from source file</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="115"/>
++ <source>Failed to create color table.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="123"/>
++ <source>Failed to open file with palette.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="131"/>
++ <source>Palette file does not have a single band with a color table</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="140"/>
++ <source>The color table must not contain a &quot;no data&quot; value and it&apos;s size must not exceed 255 colors.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="167"/>
++ <source>Save color table to: %1</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="203"/>
++ <source>Failed to create target file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="214"/>
++ <source>Dither source file to target file</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="225"/>
++ <source>Failed to dither file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="240"/>
++ <source>Apply alpha channel as no data value to target file</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="247"/>
++ <source>Failed to read from alpha channel.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="253"/>
++ <source>Failed to read from target file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="267"/>
++ <source>Failed to write to target file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++<context>
++ <name>main</name>
++ <message>
++ <location filename="../main.cpp" line="96"/>
++ <source>
++Convert a map file with RGBA color coding to a color palette coding.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="99"/>
++ <source>Source file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="100"/>
++ <source>Target file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="104"/>
++ <source>Number of colors. (default: 255)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="107"/>
++ <source>Input palette file for color table (*.vrt)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="110"/>
++ <source>Save color table to palette file (*.vrt)</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="120"/>
++ <source>There must be a source and destination file.</source>
++ <translation type="unfinished"></translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="143"/>
++ <source>--ncolors must be an integer value less than 256</source>
++ <translation type="unfinished"></translation>
++ </message>
++</context>
++</TS>
+diff --git a/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts b/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts
+new file mode 100644
+index 00000000..9622b8d9
+--- /dev/null
++++ b/src/qmt_rgb2pct/locale/qmt_rgb2pct_de.ts
+@@ -0,0 +1,127 @@
++<?xml version="1.0" encoding="utf-8"?>
++<!DOCTYPE TS>
++<TS version="2.1" language="de_DE">
++<context>
++ <name>CApp</name>
++ <message>
++ <location filename="../CApp.cpp" line="63"/>
++ <source>Failed to open source file.</source>
++ <translation>Konnte Quelldatei nicht öffnen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="68"/>
++ <source>Raster band count of source file must be either 3 or 4.</source>
++ <translation>Die Anzahl der Rasterbänder muss entweder 3 oder 4 sein.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="101"/>
++ <source>Calculate optimal color table from source file</source>
++ <translation>Berechne die optimale Farbtabelle für die Quelldatei</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="115"/>
++ <source>Failed to create color table.</source>
++ <translation>Konnte die Farbtabelle nicht erstellen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="123"/>
++ <source>Failed to open file with palette.</source>
++ <translation>Konnte die Datei mit der Palette nicht öffnen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="131"/>
++ <source>Palette file does not have a single band with a color table</source>
++ <translation>Die Datei mit der Palette hat kein einzelnes Band mit einer Farbtabelle</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="140"/>
++ <source>The color table must not contain a &quot;no data&quot; value and it&apos;s size must not exceed 255 colors.</source>
++ <translation>Die Farbtabelle darf keinen Eintrag für &quot;no data&quot; haben und ihre Größe darf nicht 255 Farben überschreiten.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="167"/>
++ <source>Save color table to: %1</source>
++ <translation>Speichere Farbtabelle in: %1</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="203"/>
++ <source>Failed to create target file.</source>
++ <translation>Konnte Zieldatei nicht erstellen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="214"/>
++ <source>Dither source file to target file</source>
++ <translation>Wandle Quelldatei in Zieldatei um</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="225"/>
++ <source>Failed to dither file.</source>
++ <translation>Konnte die Datei nicht umwandeln.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="240"/>
++ <source>Apply alpha channel as no data value to target file</source>
++ <translation>Wandle für die Zieldatei den Alphakanal in &quot;no data&quot; Werte um </translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="247"/>
++ <source>Failed to read from alpha channel.</source>
++ <translation>Konnte den Alphakanal nicht lesen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="253"/>
++ <source>Failed to read from target file.</source>
++ <translation>Konnte die Zieldatei nicht lesen.</translation>
++ </message>
++ <message>
++ <location filename="../CApp.cpp" line="267"/>
++ <source>Failed to write to target file.</source>
++ <translation>Konnte die Zieldatei nicht schreiben.</translation>
++ </message>
++</context>
++<context>
++ <name>main</name>
++ <message>
++ <location filename="../main.cpp" line="96"/>
++ <source>
++Convert a map file with RGBA color coding to a color palette coding.</source>
++ <translation>
++Konvertiert eine Kartendatei mit RGBA Farbschema in eine Kartendatei mit Farbtabelle.</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="99"/>
++ <source>Source file.</source>
++ <translation>Quelldatei.</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="100"/>
++ <source>Target file.</source>
++ <translation>Zieldatei.</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="104"/>
++ <source>Number of colors. (default: 255)</source>
++ <translation>Anzahl an Farben (Vorgabe: 255)</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="107"/>
++ <source>Input palette file for color table (*.vrt)</source>
++ <translation>Datei mit Palette als Vorgabe für die Farbtabelle (*.vrt) </translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="110"/>
++ <source>Save color table to palette file (*.vrt)</source>
++ <translation>Farbtabelle in Datei mit Palette sichern (*.vrt)</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="120"/>
++ <source>There must be a source and destination file.</source>
++ <translation>Es muss eine Quell- und eine Zieldatei angegeben werden.</translation>
++ </message>
++ <message>
++ <location filename="../main.cpp" line="143"/>
++ <source>--ncolors must be an integer value less than 256</source>
++ <translation>--ncolors muss eine ganze Zahl kleiner 256 sein</translation>
++ </message>
++</context>
++</TS>
+diff --git a/src/qmt_rgb2pct/main.cpp b/src/qmt_rgb2pct/main.cpp
+new file mode 100644
+index 00000000..4ff9a9ae
+--- /dev/null
++++ b/src/qmt_rgb2pct/main.cpp
+@@ -0,0 +1,155 @@
++/**********************************************************************************************
++ Copyright (C) 2018 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#include "CApp.h"
++#include "version.h"
++#include <QtCore>
++
++#ifdef Q_OS_MACOS
++static QDir getApplicationDir(QString subdir)
++{
++ QDir appDir(QCoreApplication::applicationDirPath());
++ appDir.cdUp();
++ appDir.cd(subdir);
++ return appDir;
++}
++#endif
++static void prepareTranslator(QString translationPath, QString translationPrefix)
++{
++ QString locale = QLocale::system().name();
++ QDir dir(translationPath);
++ if(!QFile::exists(dir.absoluteFilePath(translationPrefix + locale)))
++ {
++ locale = locale.left(2);
++ }
++
++ QCoreApplication* app = (QCoreApplication*) QCoreApplication::instance();
++ QTranslator *qtTranslator = new QTranslator(app);
++
++ if (qtTranslator->load(translationPrefix + locale, translationPath))
++ {
++ app->installTranslator(qtTranslator);
++ }
++}
++
++static void loadTranslations()
++{
++#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(__FreeBSD_kernel__) || defined(__GNU__) || defined(Q_OS_CYGWIN)
++ QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
++ QString translationPath = QCoreApplication::applicationDirPath();
++ translationPath.replace(QRegExp("bin$"), "share/" APP_STR "/translations");
++ prepareTranslator(resourceDir, "qt_");
++ prepareTranslator(translationPath, APP_STR "_");
++#endif
++
++#ifdef Q_OS_OSX
++ // os x
++ static QString relTranslationDir = "Resources/translations"; // app
++ QString translationPath = getApplicationDir(relTranslationDir).absolutePath();
++ prepareTranslator(translationPath, "qt_");
++ prepareTranslator(translationPath, APP_STR "_");
++#endif
++
++#ifdef Q_OS_WIN
++ QString apppath = QCoreApplication::applicationDirPath();
++ apppath = apppath.replace("/", "\\");
++ QString appResourceDir = QString("%1\\translations").arg(apppath).toUtf8();
++ prepareTranslator(appResourceDir, "qtbase_");
++ prepareTranslator(appResourceDir, APP_STR "_");
++#endif
++
++}
++
++int main(int argc, char ** argv)
++{
++ QCoreApplication app(argc, argv);
++ QCoreApplication::setApplicationName(APP_STR);
++ QCoreApplication::setApplicationVersion(VER_STR);
++ if(QString(VER_SUFFIX).isEmpty())
++ {
++ QCoreApplication::setApplicationVersion(VER_STR);
++ }
++ else
++ {
++ QCoreApplication::setApplicationVersion(VER_STR "." VER_SUFFIX);
++ }
++
++
++ loadTranslations();
++
++ QCommandLineParser parser;
++ parser.setApplicationDescription(QCoreApplication::translate("main", "\nConvert a map file with RGBA color coding to a color palette coding."));
++ parser.addHelpOption();
++ parser.addVersionOption();
++ parser.addPositionalArgument("source", QCoreApplication::translate("main", "Source file."));
++ parser.addPositionalArgument("target", QCoreApplication::translate("main", "Target file."));
++
++ parser.addOptions({
++ {
++ {"n","ncolors"}, QCoreApplication::translate("main", "Number of colors. (default: 255)"), "number", "255"
++ },
++ {
++ {"p","pct"}, QCoreApplication::translate("main", "Input palette file for color table (*.vrt)"), "filename", ""
++ },
++ {
++ {"s","sct"}, QCoreApplication::translate("main", "Save color table to palette file (*.vrt)"), "filename", ""
++ },
++ });
++
++ // Process the actual command line arguments given by the user
++ parser.process(app);
++
++ if(parser.positionalArguments().count() == 1 && parser.value("sct").isEmpty())
++ {
++ printStderrQString("");
++ printStderrQString(QCoreApplication::translate("main","There must be a source and destination file."));
++ printStderrQString("");
++ parser.showHelp(-1);
++ }
++
++ if(parser.positionalArguments().isEmpty())
++ {
++ parser.showHelp(-1);
++ }
++
++ QString srcFilename = parser.positionalArguments()[0];
++ QString tarFilename;
++ if(parser.positionalArguments().count() > 1)
++ {
++ tarFilename = parser.positionalArguments()[1];
++ }
++
++
++ bool ok = false;
++ const qint32 ncolors = parser.value("ncolors").toInt(&ok);
++ if(!ok || ncolors > 255)
++ {
++ printStderrQString("");
++ printStderrQString(QCoreApplication::translate("main","--ncolors must be an integer value less than 256"));
++ printStderrQString("");
++ parser.showHelp(-1);
++ }
++
++ QString pctFilename = parser.value("pct");
++ QString sctFilename = parser.value("sct");
++
++ CApp theApp(ncolors, pctFilename, sctFilename, srcFilename, tarFilename);
++ return theApp.exec();
++}
++
++
+diff --git a/src/qmt_rgb2pct/version.h b/src/qmt_rgb2pct/version.h
+new file mode 100644
+index 00000000..60f94f71
+--- /dev/null
++++ b/src/qmt_rgb2pct/version.h
+@@ -0,0 +1,33 @@
++/**********************************************************************************************
++ Copyright (C) 2017 Oliver Eichler oliver.eichler@gmx.de
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation, either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++**********************************************************************************************/
++
++#ifndef VERSION_H
++#define VERSION_H
++
++#ifndef _MKSTR_1
++#define _MKSTR_1(x) #x
++#define _MKSTR(x) _MKSTR_1(x)
++#endif
++
++#define VER_STR _MKSTR(VER_MAJOR) "." _MKSTR (VER_MINOR) "." _MKSTR (VER_STEP)
++#define VER_SUFFIX _MKSTR(VER_TWEAK)
++#define APP_STR _MKSTR(APPLICATION_NAME)
++#define WHAT_STR _MKSTR(APPLICATION_NAME) ", Version " VER_STR
++
++#endif //VERSION_H
++
diff --git a/gis/qmapshack/splash.png b/gis/qmapshack/splash.png
new file mode 100644
index 0000000000000..8a58d5d28eb53
--- /dev/null
+++ b/gis/qmapshack/splash.png
Binary files differ