[GRASS-SVN] r70856 - grass/trunk/gui/wxpython/iimage2target

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Apr 9 14:57:39 PDT 2017


Author: ychemin
Date: 2017-04-09 14:57:38 -0700 (Sun, 09 Apr 2017)
New Revision: 70856

Added:
   grass/trunk/gui/wxpython/iimage2target/Makefile
   grass/trunk/gui/wxpython/iimage2target/__init__.py
   grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.html
   grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set_error.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_manager.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_mapdisplay.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_menustrings.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_statusbar.py
   grass/trunk/gui/wxpython/iimage2target/ii2t_toolbars.py
   grass/trunk/gui/wxpython/iimage2target/wxGUI_iimage2target_frame.jpg
Log:
Added g.gui.iimage2target first shot, GUI is mostly done, algorithm connection not working

Added: grass/trunk/gui/wxpython/iimage2target/Makefile
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/Makefile	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/Makefile	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,5 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/GuiScript.make
+
+default: guiscript

Added: grass/trunk/gui/wxpython/iimage2target/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/__init__.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/__init__.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,5 @@
+all = [
+    'ii2t_manager',
+    'ii2t_mapdisplay',
+    'ii2t_toolbars',
+]

Added: grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.html
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.html	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.html	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,318 @@
+<!-- meta page description: wxGUI GCP Manager -->
+<!-- meta page index: topic_gui|GUI -->
+<h2>DESCRIPTION</h2>
+
+The <b>GCP Manager</b> is a <em><a href="wxGUI.html">wxGUI</a></em>
+extension which allows the user to create, edit, and manage
+Ground Control Points. It is available from the menu
+"File | Manage Ground Control Points".
+
+<p>
+The <b>GCP Manager</b> provides an interactive graphical interface to
+manage and analyze Ground Control Points. A backup copy of the initial
+POINTS file is always maintained and updated only on request (Save GCPs
+to POINTS file). This guarantees that accidental changes are not
+permanent and can be undone by reloading the Ground Control Points.
+
+<p>
+The GCP Manager must be started in the target location, not in the
+source location.
+
+<p>
+The GCP Manager is structured into three panels:
+
+<ul>
+  <li>The topmost panel shows a list of Ground Control Points. Tools to
+  manipulate and analyze GCPs are provided in the toolbar. This panel can
+  be moved out of the GCP manager window by either dragging with the
+  caption or by clicking on the pin button on the right in the caption.
+  This panel can also be placed below the map displays by dragging.
+  <li>The two panels in the lower part are used for map and GCP display,
+  the left pane showing a map from the source location and the right
+  pane showing a reference map from the target location. Numbered Ground
+  Control Points are shown on both map displays.
+</ul>
+
+
+
+<h3>Components of the GCP Manager</h3>
+
+<center>
+  <br><img src="wxGUI_gcp_frame.jpg" border="0" alt="GCP Manager"><br><br>
+</center>
+
+<p>
+<em>Toolbars</em>
+<p>
+Two toolbars are provided with the GCP Manager, one for managing the map
+displays and one for managing the GCP list.
+
+<p>
+<em>List of ground control points</em>
+<p>
+The list of Ground Control Points can be sorted by clicking on a column 
+header. Clicking on a cloumn header will sort the GCPs ascending, a
+second click on the same column will sort the GCPs descending. Overall
+RMS error and individual RMS errors of all points are often improved if
+the GCP with the highest RMS error is adjusted. Individual coordinates
+can be edited by double-clicking on a row.
+<p>
+The first column holds a checkbox and displays the point number. A GCP
+is only used for RMS error calculation and georectification if its
+checkbox on the left is checked. Uncheck to deactivate a GCP (mark as
+unused GCP).
+
+<p>
+<em>Two panels for map display</em>
+<p>
+The left panel is used to display a map from the source location, the
+right panel to display a map from the target loaction. Zooming in and
+out is always possible with the mouse wheel and done for each map canvas
+separately.
+<p>
+GCPs are displayed in different colors, depending on whether a GCP has
+a high RMS error, is currently unused or is currently selected. Optionally,
+currently unused GCPs are not shown on the map display.
+
+<p>
+<em>Statusbar</em>
+<p>
+At the bottom of the GCP Manager is a statusbar providing several
+functions. The default is set to <em>Go to GCP No.</em> (see also below).
+Typing a number or using the up/down arrows will center the maps on the
+given GCP, useful with a high zoom.
+
+<h4>GCP Map Display Toolbar</h4>
+
+<dl>
+
+<dt><img src="icons/show.png" alt="icon"> 
+  <em>Display map</em></dt>
+<dd>Displays maps for source and target canvas and re-renders any layers
+that have changed since the last time the display was updated.</dd>
+
+<dt><img src="icons/layer-redraw.png" alt="icon"> 
+  <em>Re-render map</em></dt>
+<dd>Re-renders both source and target canvas regardless of whether they
+have changed or not.</dd>
+
+<dt><img src="icons/erase.png" alt="icon"> 
+  <em>Erase display</em></dt>
+<dd>Erases both source and target canvas to a white background.</dd>
+
+<dt><img src="icons/gcp-create.png" alt="icon"> 
+  <em>Define GCP (Ground Control Points)</em></dt>
+<dd>On left mouse click, coordinates are defined for the currently
+selected GCP.</dd>
+
+<dt><img src="icons/pan.png" alt="icon"> 
+  <em>Pan</em></dt>
+<dd>Interactive selection of a new center of view in the active
+display monitor. Drag the pan cursor while pressing the left mouse
+button to pan. Alternatively left-click on the new center. Panning
+changes the location of the region displayed but not the size of the
+area displayed or the resolution.</dd>
+
+<dt><img src="icons/zoom-in.png" alt="icon"> 
+  <em>Zoom in</em></dt>
+<dd>Interactive zooming with the mouse in the active map canvas (source 
+or target). Drawing a box or just a left click with the mouse and zoom-in
+cursor causes the display to zoom in so that the area defined by the box
+fills the display. The map resolution is not changed. Clicking with the
+zoom-in cursor causes the display to zoom in by 30%, centered on the
+point where the mouse is clicked. Zooming changes the display region
+extents (both size and location of area displayed).</dd>
+
+<dt><img src="icons/zoom-out.png" alt="icon"> 
+  <em>Zoom out</em></dt>
+<dd>Interactive zooming with the mouse in the active map canvas (source 
+or target). Drawing a box or just a left click with the mouse and zoom-out
+cursor causes the display to zoom out so that the area displayed
+shrinks to fill the area defined by the box. The map resolution is not
+changed. Clicking with the zoom-out cursor causes the display to zoom
+out by 30%, centered on the point where the mouse is clicked. Zooming
+changes the display region extents (both size and location of area
+displayed).</dd>
+
+<dt><img src="icons/zoom-more.png" alt="icon"> 
+  <em>Adjust display zoom</em></dt>
+<dd>Source and target display are adjusted by using the current GCPs for
+coordinate transformation:
+<br><br>
+  <dl>
+    <dt><em>Adjust source display to target display</em>
+    <dd>The extents of the source display are adjusted to the current
+    extents of the target display.
+    <dt><em>Adjust target display to source display</em>
+    <dd>The extents of the source display are adjusted to the current
+    extents of the target display.
+  </dl>
+
+<dt><em>Set active map canvas</em></dt>
+<dd>Sets the currently active map canvas (source or target). Click 
+to set active map canvas for <em>Return to previous zoom</em> or 
+<em>Zoom to extent of currently displayed map</em>. Alternatively, move
+the mouse over the map canvas to be used as active canvas.</dd>
+
+<dt><img src="icons/zoom-last.png" alt="icon"> 
+  <em>Return to previous zoom</em></dt>
+<dd>Returns to the previous zoom extent. Up to 10 levels of zoom back are
+maintained.</dd>
+
+<dt><img src="icons/zoom-extent.png" alt="icon"> 
+<em>Zoom to extent of currently displayed map</em></dt>
+<dd>Zoom to the extent of the currently displayed map in the active map
+canvas (source or target).</dd>
+
+<dt><img src="icons/settings.png" alt="icon"> 
+<em>Settings</em></dt>
+<dd>Shows a settings dialog for GCP management and display:<br><br> 
+
+  <dl>
+    <dt><em>Symbology</em></dt>
+      <dd>Settings for map and GCP display:<br><br>
+
+      <dl>
+        <dt><em>Highlight highest RMS error only</em></dt>
+          <dd>Only the GCP with the highest RMS error will be displayed in
+          a different colour, both in the list of GCPs and the GCP Map Display.
+        <dt><em>Factor for RMS error threshold = M + SD * factor:</em></dt>
+          <dd>All GCPs with an RMS error larger than mean RMS + RMS standard
+          deviation * this factor will be displayed in a different colour,
+          both in the list of GCPs and the GCP Map Display. As a rule of
+          thumb, GCPs with an RMS error larger than <em>M + SD * 2</em> are
+          most probably wrong. GCPs with an RMS error larger than
+          <em>M + SD * 1</em> are worth closer inspection. This option is
+          only available if <em>Highlight highest RMS error only</em> is
+          unchecked.</dd>
+        <dt><em>Color</em></dt>
+          <dd>Set the color for GCPs on the GCP Map Display.</dd>
+        <dt><em>Color for high RMS error</em></dt>
+          <dd>Set the color for GCPs with a high RMS error on the GCP Map
+          Display.</dd>
+        <dt><em>Color for selected GCP</em></dt>
+          <dd>Set the color for the currently selected GCP on the GCP Map
+          Display.</dd>
+        <dt><em>Show unused GCPs</em></dt>
+          <dd>If unchecked, unused GCPs will not be shown on the GCP Map
+          Display.</dd>
+        <dt><em>Color for unused GCPs</em></dt>
+          <dd>Set the color for unused GCPs on the GCP Map Display.</dd>
+        <dt><em>Symbol size</em></dt>
+          <dd>Set the symbol size for GCPs on the GCP Map Display.</dd>
+        <dt><em>Line width</em></dt>
+          <dd>Set the line width for GCPs on the GCP Map Display.</dd>
+        <dt><em>Select source map to display</em></dt>
+          <dd>Select a source map for the left pane of the GCP Map Display.</dd>
+        <dt><em>Select target map to display</em></dt>
+          <dd>Select a target map for the right pane of the GCP Map Display.</dd>
+      </dl>
+      </dd>
+
+    <dt><br><em>Rectification</em></dt>
+      <dd>Settings for georectification:<br><br>
+      <dl>
+        <dt><em>Select rectification method</em></dt>
+          <dd>Set the polynomial order for georectification. This order will
+          also be used for RMS error calculation.</dd>
+        <dt><em>Clip to computational region in target location</em></dt>
+          <dd>Clip raster maps to the current computational region in the
+          target location when georectifying.</dd>
+        <dt><em>Extension for output maps</em></dt>
+          <dd>Change the extension for output map names when doing the actual
+          georectification.</dd>
+      </dl>
+      </dd>
+  </dl><br>
+</dd>
+
+<dt><img src="icons/help.png" alt="icon"> 
+<em>Show Help</em></dt>
+<dd>Show help page for the GCP Manager.
+
+<dt><img src="icons/quit.png" alt="icon"> 
+<em>Quit</em></dt>
+<dd>Quit the GCP Manager.
+
+</dl>
+
+<h4>Toolbar for the GCP list</h4>
+
+<dl>
+
+<dt><img src="icons/gcp-save.png" alt="icon"> 
+<em>Save GCPs to POINTS file</em></dt>
+<dd>The current list of GCPs is saved to the imagery group's POINTS file
+and to a backup copy.</dd>
+
+<dt><img src="icons/gcp-add.png" alt="icon"> 
+<em>Add new GCP</em></dt>
+<dd>Adds a new Ground Control Point to the list and selects it for editing.</dd>
+
+<dt><img src="icons/gcp-delete.png" alt="icon"> 
+<em>Delete selected GCP</em></dt>
+<dd>Deletes the currently selected GCP from the list.</dd>
+
+<dt><img src="icons/gcp-remove.png" alt="icon"> 
+<em>Clear selected GCP</em></dt>
+<dd>Resets all coordinates of the currently selected GCP to 0 (zero).</dd>
+
+<dt><img src="icons/reload.png" alt="icon"> 
+<em>Reload GCPs from POINTS file</em></dt>
+<dd>Reloads GCPs from the imagery group's POINTS file.</dd>
+
+<dt><img src="icons/gcp-rms.png" alt="icon"> 
+<em>Recalculate RMS error</em></dt>
+<dd>Recalculates forward and backward RMS error for all GCP marked for
+use (activated checkbox in first row).
+</dd>
+
+<dt><img src="icons/georectify.png" alt="icon"> 
+<em>Georectify</em></dt>
+<dd>Uses <em><a href="i.rectify.html">i.rectify</a></em> to georectify
+all images in the source imagery group.
+</dd>
+
+</dl>
+
+<h4>GCP Map Display Statusbar</h4>
+
+The GCP map display statusbar is similar to the statusbar in the regular
+GRASS GIS map display with two differences, <em>Go to</em> has been
+replaced with <em>Go to GCP No.</em> and <em>Projection</em> has been
+replaced with <em>RMS error</em>.
+<p>
+If <em>Go to GCP No.</em> is selected, a GCP number can be given in the
+left side of the statusbar and the source and target map canvas will be
+centered on the given GCP. Clicking on the map canvas will update
+coordinates for this GCP.
+<p>
+If <em>RMS error</em> is selected, the overall forward and backward RMS
+error is displayed.
+
+<h2>SEE ALSO</h2>
+
+<em>
+  <a href="wxGUI.html">wxGUI</a><br>
+  <a href="wxGUI.components.html">wxGUI components</a>
+</em>
+
+<p>
+<em>
+<a href="i.rectify.html">i.rectify</a>,
+<a href="m.transform.html">m.transform</a>,
+<a href="v.rectify.html">v.rectify</a>
+</em>
+
+<p>
+See also <a href="http://grasswiki.osgeo.org/wiki/WxGUI/Video_tutorials#Georectifier">video
+tutorials</a> on GRASS Wiki.
+
+<h2>AUTHORS</h2>
+
+Markus Metz<br><br>
+<em>Based on the Georectifier (GRASS 6.4.0)</em> by Michael Barton<br>
+Martin Landa, Czech Technical University in Prague, Czech Republic
+
+<p>
+<i>$Date: 2016-09-19 11:37:30 +0200 (lun., 19 sept. 2016) $</i>

Added: grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,184 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# MODULE:    Create 3-Dimensional GCPs from elevation and target image
+# AUTHOR(S): Yann modified the code (was Markus Metz for the GCP manager)
+# PURPOSE:   Georectification and Ground Control Points management for 3D correction.
+# COPYRIGHT: (C) 2012-2017 by Markus Metz, and the GRASS Development Team
+#
+#  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.
+#
+############################################################################
+
+#%module
+#% description: Georectifies a map and allows managing Ground Control Points for 3D correction.
+#% keyword: imagery
+#% keyword: aerial
+#% keyword: photo
+#% keyword: georectification
+#% keyword: GCP
+#% keyword: GUI
+#%end
+
+##%option G_OPT_M_LOCATION
+##% key: source_location
+##% label: The name of the source location (has no projection)
+##% description: The name of the source location (has no projection)
+###% section: source
+##% required: yes
+##%end
+
+##%option G_OPT_M_MAPSET
+##% key: source_mapset
+##% label: The name of the source mapset (has no projection)
+##% description: The name of the source mapset (has no projection)
+###% section: source
+##% required: yes
+##%end
+
+##%option G_OPT_I_GROUP
+##% key: source_group
+##% required: yes
+##% section: source
+##%end
+
+##%option G_OPT_R_INPUT
+##% key: source_image
+##% required: yes
+###% section: source
+##%end
+
+##%option G_OPT_R_INPUT
+##% key: target_image
+##% label: The name of the image that is already georeferenced used to find location of GCPs
+##% description: The name of the image that is already georeferenced used to find the location of GCPs
+###% section: target
+##% required: no
+##%end
+
+##%option 
+##% key: camera
+##% type: string
+##% label: The name of the camera (generated in i.ortho.camera)
+##% description: The name of the camera (generated in i.ortho.camera)
+##% required: yes
+###% section: parameters
+##%end
+
+##%option 
+##% key: order
+##% type: string
+##% label: The rectification order 
+##% description: The rectification order 
+##% required: yes
+##% answer: 1
+###% section: parameters
+##%end
+
+##%option 
+##% key: extension
+##% type: string
+##% label: The name of the output files extension
+##% description: The name of the output files extension
+##% required: yes
+##% answer: _ii2t_out
+##% section: target
+##%end
+
+
+"""
+Module to run GCP management tool as stadalone application.
+
+ at author Vaclav Petras  <wenzeslaus gmail.com> (standalone module)
+"""
+
+import os
+
+import grass.script as gscript
+
+
+def main():
+    """
+    Sets the GRASS display driver
+    """
+    options, flags = gscript.parser()
+
+    import wx
+
+    from grass.script.setup import set_gui_path
+    set_gui_path()
+
+    from core.settings import UserSettings
+    from core.globalvar import CheckWxVersion
+    from core.giface import StandaloneGrassInterface
+    from iimage2target.ii2t_manager import GCPWizard
+
+    driver = UserSettings.Get(group='display', key='driver', subkey='type')
+    if driver == 'png':
+        os.environ['GRASS_RENDER_IMMEDIATE'] = 'png'
+    else:
+        os.environ['GRASS_RENDER_IMMEDIATE'] = 'cairo'
+
+#    if options['source_location']:
+#        src_loc = options['source_location']
+#    else:
+#        gscript.fatal(_("No georeferenced source location provided"))
+
+#    if options['source_mapset']:
+#        src_mpt = options['source_mapset']
+#    else:
+#        gscript.fatal(_("No georeferenced source mapset provided"))
+
+#    if options['source_group']:
+#        src_grp = options['source_group']
+#    else:
+#        gscript.fatal(_("Please provide a source group name to process"))
+    
+#    if options['source_image']:
+#        src_ras = options['source_image']
+#    else:
+#        gscript.fatal(_("Please provide a source image map name to process"))
+
+#    if options['target_image']:
+#        tgt_ras = options['target_image']
+#    else:
+#        gscript.fatal(_("No georeferenced target map provided"))
+
+#    if options['camera']:
+#        camera = options['camera']
+#    else:
+#        gscript.fatal(_("Please provide a camera name (generated by i.ortho.camera)"))
+
+#    if options['order']:
+#        order = options['order']
+#    else:
+#        gscript.fatal(_("Please provive an order value"))
+
+#    if options['extension']:
+#        extension = options['extension']
+#    else:
+#        gscript.fatal(_("Please provide an output file extension"))
+
+
+    app = wx.App()
+    if not CheckWxVersion([2, 9]):
+        wx.InitAllImageHandlers()
+
+#    wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface(), 
+#            srcloc=src_loc,srcmpt=src_mpt,srcgrp=src_grp,srcras=src_ras,
+#            tgtras=tgt_ras,camera=camera, order=order, extension=extension)
+
+    wizard = GCPWizard(parent=None, giface=StandaloneGrassInterface())
+    app.MainLoop()
+
+if __name__ == '__main__':
+    main()


Property changes on: grass/trunk/gui/wxpython/iimage2target/g.gui.iimage2target.py
___________________________________________________________________
Added: svn:executable
   + *

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,1185 @@
+"""
+ at package gis_set
+
+GRASS start-up screen.
+
+Initialization module for wxPython GRASS GUI.
+Location/mapset management (selection, creation, etc.).
+
+Classes:
+ - gis_set::GRASSStartup
+ - gis_set::GListBox
+ - gis_set::StartUp
+
+(C) 2006-2014 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton and Jachym Cepicky (original author)
+ at author Martin Landa <landa.martin gmail.com> (various updates)
+"""
+
+import os
+import sys
+import shutil
+import copy
+import platform
+import codecs
+import getpass
+
+from core import globalvar
+from core.utils import _
+import wx
+import wx.lib.mixins.listctrl as listmix
+
+from grass.script import core as grass
+
+from core.gcmd import GMessage, GError, DecodeString, RunCommand
+from core.utils import GetListOfLocations, GetListOfMapsets
+from location_wizard.dialogs import RegionDef
+from gui_core.dialogs import TextEntryDialog
+from gui_core.widgets import GenericValidator, StaticWrapText
+from gui_core.wrap import Button
+from gui_core.wrap import ListCtrl
+
+sys.stderr = codecs.getwriter('utf8')(sys.stderr)
+
+
+class GRASSStartup(wx.Frame):
+    exit_success = 0
+    # 2 is file not found from python interpreter
+    exit_user_requested = 5
+
+    """GRASS start-up screen"""
+
+    def __init__(self, parent=None, id=wx.ID_ANY,
+                 style=wx.DEFAULT_FRAME_STYLE):
+
+        #
+        # GRASS variables
+        #
+        self.gisbase = os.getenv("GISBASE")
+        self.grassrc = self._readGisRC()
+        self.gisdbase = self.GetRCValue("GISDBASE")
+
+        #
+        # list of locations/mapsets
+        #
+        self.listOfLocations = []
+        self.listOfMapsets = []
+        self.listOfMapsetsSelectable = []
+
+        wx.Frame.__init__(self, parent=parent, id=id, style=style)
+
+        self.locale = wx.Locale(language=wx.LANGUAGE_DEFAULT)
+
+        # scroll panel was used here but not properly and is probably not need
+        # as long as it is not high too much
+        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
+
+        # i18N
+
+        #
+        # graphical elements
+        #
+        # image
+        try:
+            if os.getenv('ISISROOT'):
+                name = os.path.join(
+                    globalvar.GUIDIR,
+                    "images",
+                    "startup_banner_isis.png")
+            else:
+                name = os.path.join(
+                    globalvar.GUIDIR, "images", "startup_banner.png")
+            self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY,
+                                           wx.Bitmap(name=name,
+                                                     type=wx.BITMAP_TYPE_PNG))
+        except:
+            self.hbitmap = wx.StaticBitmap(
+                self.panel, wx.ID_ANY, wx.BitmapFromImage(
+                    wx.EmptyImage(530, 150)))
+
+        # labels
+        # crashes when LOCATION doesn't exist
+        # get version & revision
+        versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
+        versionLine = versionFile.readline().rstrip('\n')
+        versionFile.close()
+        try:
+            grassVersion, grassRevision = versionLine.split(' ', 1)
+            if grassVersion.endswith('svn'):
+                grassRevisionStr = ' (%s)' % grassRevision
+            else:
+                grassRevisionStr = ''
+        except ValueError:
+            grassVersion = versionLine
+            grassRevisionStr = ''
+
+        self.gisdbase_box = wx.StaticBox(
+            parent=self.panel, id=wx.ID_ANY, label=" %s " %
+            _("1. Select GRASS GIS database directory"))
+        self.location_box = wx.StaticBox(
+            parent=self.panel, id=wx.ID_ANY, label=" %s " %
+            _("2. Select GRASS Location"))
+        self.mapset_box = wx.StaticBox(
+            parent=self.panel, id=wx.ID_ANY, label=" %s " %
+            _("3. Select GRASS Mapset"))
+
+        self.lmessage = wx.StaticText(parent=self.panel)
+        # It is not clear if all wx versions supports color, so try-except.
+        # The color itself may not be correct for all platforms/system settings
+        # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html
+        # there is no 'warning' color.
+        try:
+            self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0))
+        except AttributeError:
+            pass
+
+        self.gisdbase_panel = wx.Panel(parent=self.panel)
+        self.location_panel = wx.Panel(parent=self.panel)
+        self.mapset_panel = wx.Panel(parent=self.panel)
+
+        self.ldbase = wx.StaticText(
+            parent=self.gisdbase_panel, id=wx.ID_ANY,
+            label=_("GRASS GIS database directory contains Locations."))
+
+        self.llocation = StaticWrapText(
+            parent=self.location_panel, id=wx.ID_ANY,
+            label=_("All data in one Location is in the same "
+                    " coordinate reference system (projection)."
+                    " One Location can be one project."
+                    " Location contains Mapsets."),
+            style=wx.ALIGN_LEFT)
+
+        self.lmapset = StaticWrapText(
+            parent=self.mapset_panel, id=wx.ID_ANY,
+            label=_("Mapset contains GIS data related"
+                    " to one project, task within one project,"
+                    " subregion or user."),
+            style=wx.ALIGN_LEFT)
+
+        try:
+            for label in [self.ldbase, self.llocation, self.lmapset]:
+                label.SetForegroundColour(
+                    wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+        except AttributeError:
+            # for explanation of try-except see above
+            pass
+
+        # buttons
+        self.bstart = Button(parent=self.panel, id=wx.ID_ANY,
+                             label=_("Start &GRASS session"))
+        self.bstart.SetDefault()
+        self.bexit = Button(parent=self.panel, id=wx.ID_EXIT)
+        self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
+        self.bhelp = Button(parent=self.panel, id=wx.ID_HELP)
+        self.bbrowse = Button(parent=self.gisdbase_panel, id=wx.ID_ANY,
+                              label=_("&Browse"))
+        self.bmapset = Button(parent=self.mapset_panel, id=wx.ID_ANY,
+                              # GTC New mapset
+                              label=_("&New"))
+        self.bmapset.SetToolTip(_("Create a new Mapset in selected Location"))
+        self.bwizard = Button(parent=self.location_panel, id=wx.ID_ANY,
+                              # GTC New location
+                              label=_("N&ew"))
+        self.bwizard.SetToolTip(
+            _(
+                "Create a new location using location wizard."
+                " After location is created successfully,"
+                " GRASS session is started."))
+        self.rename_location_button = Button(parent=self.location_panel, id=wx.ID_ANY,
+                                             # GTC Rename location
+                                             label=_("Ren&ame"))
+        self.rename_location_button.SetToolTip(_("Rename selected location"))
+        self.delete_location_button = Button(parent=self.location_panel, id=wx.ID_ANY,
+                                             # GTC Delete location
+                                             label=_("De&lete"))
+        self.delete_location_button.SetToolTip(_("Delete selected location"))
+        self.rename_mapset_button = Button(parent=self.mapset_panel, id=wx.ID_ANY,
+                                           # GTC Rename mapset
+                                           label=_("&Rename"))
+        self.rename_mapset_button.SetToolTip(_("Rename selected mapset"))
+        self.delete_mapset_button = Button(parent=self.mapset_panel, id=wx.ID_ANY,
+                                           # GTC Delete mapset
+                                           label=_("&Delete"))
+        self.delete_mapset_button.SetToolTip(_("Delete selected mapset"))
+
+        # textinputs
+        self.tgisdbase = wx.TextCtrl(
+            parent=self.gisdbase_panel, id=wx.ID_ANY, value="", size=(
+                300, -1), style=wx.TE_PROCESS_ENTER)
+
+        # Locations
+        self.lblocations = GListBox(parent=self.location_panel,
+                                    id=wx.ID_ANY, size=(180, 200),
+                                    choices=self.listOfLocations)
+        self.lblocations.SetColumnWidth(0, 180)
+
+        # TODO: sort; but keep PERMANENT on top of list
+        # Mapsets
+        self.lbmapsets = GListBox(parent=self.mapset_panel,
+                                  id=wx.ID_ANY, size=(180, 200),
+                                  choices=self.listOfMapsets)
+        self.lbmapsets.SetColumnWidth(0, 180)
+
+        # layout & properties, first do layout so everything is created
+        self._do_layout()
+        self._set_properties(grassVersion, grassRevisionStr)
+
+        # events
+        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
+        self.bstart.Bind(wx.EVT_BUTTON, self.OnStart)
+        self.bexit.Bind(wx.EVT_BUTTON, self.OnExit)
+        self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp)
+        self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset)
+        self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard)
+
+        self.rename_location_button.Bind(wx.EVT_BUTTON, self.RenameLocation)
+        self.delete_location_button.Bind(wx.EVT_BUTTON, self.DeleteLocation)
+        self.rename_mapset_button.Bind(wx.EVT_BUTTON, self.RenameMapset)
+        self.delete_mapset_button.Bind(wx.EVT_BUTTON, self.DeleteMapset)
+
+        self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
+        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMapset)
+        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
+        self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+    def _set_properties(self, version, revision):
+        """Set frame properties"""
+        self.SetTitle(_("GRASS GIS %s startup%s") % (version, revision))
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"),
+                             wx.BITMAP_TYPE_ICO))
+
+        self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
+        self.bstart.SetToolTip(_("Enter GRASS session"))
+        self.bstart.Enable(False)
+        self.bmapset.Enable(False)
+        # this all was originally a choice, perhaps just mapset needed
+        self.rename_location_button.Enable(False)
+        self.delete_location_button.Enable(False)
+        self.rename_mapset_button.Enable(False)
+        self.delete_mapset_button.Enable(False)
+
+        # set database
+        if not self.gisdbase:
+            # sets an initial path for gisdbase if nothing in GISRC
+            if os.path.isdir(os.getenv("HOME")):
+                self.gisdbase = os.getenv("HOME")
+            else:
+                self.gisdbase = os.getcwd()
+        try:
+            self.tgisdbase.SetValue(self.gisdbase)
+        except UnicodeDecodeError:
+            wx.MessageBox(parent=self, caption=_("Error"),
+                          message=_("Unable to set GRASS database. "
+                                    "Check your locale settings."),
+                          style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+
+        self.OnSetDatabase(None)
+        location = self.GetRCValue("LOCATION_NAME")
+        if location == "<UNKNOWN>":
+            return
+        if not os.path.isdir(os.path.join(self.gisdbase, location)):
+            location = None
+
+        # list of locations
+        self.UpdateLocations(self.gisdbase)
+        try:
+            self.lblocations.SetSelection(self.listOfLocations.index(location),
+                                          force=True)
+            self.lblocations.EnsureVisible(
+                self.listOfLocations.index(location))
+        except ValueError:
+            sys.stderr.write(
+                _("ERROR: Location <%s> not found\n") %
+                self.GetRCValue("LOCATION_NAME"))
+            if len(self.listOfLocations) > 0:
+                self.lblocations.SetSelection(0, force=True)
+                self.lblocations.EnsureVisible(0)
+                location = self.listOfLocations[0]
+            else:
+                return
+
+        # list of mapsets
+        self.UpdateMapsets(os.path.join(self.gisdbase, location))
+        mapset = self.GetRCValue("MAPSET")
+        if mapset:
+            try:
+                self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
+                                            force=True)
+                self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
+            except ValueError:
+                sys.stderr.write(_("ERROR: Mapset <%s> not found\n") % mapset)
+                self.lbmapsets.SetSelection(0, force=True)
+                self.lbmapsets.EnsureVisible(0)
+
+    def _do_layout(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        self.sizer = sizer  # for the layout call after changing message
+        dbase_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        location_mapset_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        gisdbase_panel_sizer = wx.BoxSizer(wx.VERTICAL)
+        gisdbase_boxsizer = wx.StaticBoxSizer(self.gisdbase_box, wx.VERTICAL)
+
+        btns_sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        self.gisdbase_panel.SetSizer(gisdbase_panel_sizer)
+
+        # gis data directory
+
+        gisdbase_boxsizer.Add(self.gisdbase_panel, proportion=1,
+                              flag=wx.EXPAND | wx.ALL,
+                              border=1)
+
+        gisdbase_panel_sizer.Add(dbase_sizer, proportion=1,
+                                 flag=wx.EXPAND | wx.ALL,
+                                 border=1)
+        gisdbase_panel_sizer.Add(self.ldbase, proportion=0,
+                                 flag=wx.EXPAND | wx.ALL,
+                                 border=1)
+
+        dbase_sizer.Add(self.tgisdbase, proportion=1,
+                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+                        border=1)
+        dbase_sizer.Add(self.bbrowse, proportion=0,
+                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+                        border=1)
+
+        gisdbase_panel_sizer.Fit(self.gisdbase_panel)
+
+        # location and mapset lists
+
+        def layout_list_box(box, panel, list_box, buttons, description):
+            panel_sizer = wx.BoxSizer(wx.VERTICAL)
+            main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+            box_sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+            buttons_sizer = wx.BoxSizer(wx.VERTICAL)
+
+            panel.SetSizer(panel_sizer)
+            panel_sizer.Fit(panel)
+
+            main_sizer.Add(list_box, proportion=1,
+                           flag=wx.EXPAND | wx.ALL,
+                           border=1)
+            main_sizer.Add(buttons_sizer, proportion=0,
+                           flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
+                           border=1)
+            for button in buttons:
+                buttons_sizer.Add(button, proportion=0,
+                                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                                  border=3)
+            box_sizer.Add(panel, proportion=1,
+                          flag=wx.EXPAND | wx.ALL,
+                          border=1)
+            panel_sizer.Add(main_sizer, proportion=1,
+                            flag=wx.EXPAND | wx.ALL,
+                            border=1)
+            panel_sizer.Add(description, proportion=0,
+                            flag=wx.EXPAND | wx.ALL,
+                            border=1)
+            return box_sizer
+
+        location_boxsizer = layout_list_box(
+            box=self.location_box,
+            panel=self.location_panel,
+            list_box=self.lblocations,
+            buttons=[self.bwizard, self.rename_location_button,
+                     self.delete_location_button],
+            description=self.llocation)
+        mapset_boxsizer = layout_list_box(
+            box=self.mapset_box,
+            panel=self.mapset_panel,
+            list_box=self.lbmapsets,
+            buttons=[self.bmapset, self.rename_mapset_button,
+                     self.delete_mapset_button],
+            description=self.lmapset)
+
+        # location and mapset sizer
+        location_mapset_sizer.Add(location_boxsizer, proportion=1,
+                                  flag=wx.LEFT | wx.RIGHT | wx.EXPAND,
+                                  border=3)
+        location_mapset_sizer.Add(mapset_boxsizer, proportion=1,
+                                  flag=wx.RIGHT | wx.EXPAND,
+                                  border=3)
+
+        # buttons
+        btns_sizer.Add(self.bstart, proportion=0,
+                       flag=wx.ALIGN_CENTER_HORIZONTAL |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL,
+                       border=5)
+        btns_sizer.Add(self.bexit, proportion=0,
+                       flag=wx.ALIGN_CENTER_HORIZONTAL |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL,
+                       border=5)
+        btns_sizer.Add(self.bhelp, proportion=0,
+                       flag=wx.ALIGN_CENTER_HORIZONTAL |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL,
+                       border=5)
+
+        # main sizer
+        sizer.Add(self.hbitmap,
+                  proportion=0,
+                  flag=wx.ALIGN_CENTER_VERTICAL |
+                  wx.ALIGN_CENTER_HORIZONTAL |
+                  wx.ALL,
+                  border=3)  # image
+        sizer.Add(gisdbase_boxsizer, proportion=0,
+                  flag=wx.ALIGN_CENTER_HORIZONTAL |
+                  wx.RIGHT | wx.LEFT | wx.TOP | wx.EXPAND,
+                  border=3)  # GISDBASE setting
+
+        # warning/error message
+        sizer.Add(self.lmessage,
+                  proportion=0,
+                  flag=wx.ALIGN_CENTER_VERTICAL |
+                  wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, border=5)
+        sizer.Add(location_mapset_sizer, proportion=1,
+                  flag=wx.RIGHT | wx.LEFT | wx.EXPAND,
+                  border=1)
+        sizer.Add(btns_sizer, proportion=0,
+                  flag=wx.ALIGN_CENTER_VERTICAL |
+                  wx.ALIGN_CENTER_HORIZONTAL |
+                  wx.RIGHT | wx.LEFT,
+                  border=3)
+
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        sizer.SetSizeHints(self)
+        self.Layout()
+
+    def _readGisRC(self):
+        """Read variables from $HOME/.grass7/rc file
+        """
+        grassrc = {}
+
+        gisrc = os.getenv("GISRC")
+
+        if gisrc and os.path.isfile(gisrc):
+            try:
+                rc = open(gisrc, "r")
+                for line in rc.readlines():
+                    try:
+                        key, val = line.split(":", 1)
+                    except ValueError as e:
+                        sys.stderr.write(
+                            _('Invalid line in GISRC file (%s):%s\n' % (e, line)))
+                    grassrc[key.strip()] = DecodeString(val.strip())
+            finally:
+                rc.close()
+
+        return grassrc
+
+    def _showWarning(self, text):
+        """Displays a warning, hint or info message to the user.
+
+        This function can be used for all kinds of messages except for
+        error messages.
+
+        .. note::
+            There is no cleaning procedure. You should call _hideMessage when
+            you know that there is everything correct now.
+        """
+        self.lmessage.SetLabel(text)
+        self.lmessage.Wrap(self.GetClientSize()[0])
+        self.sizer.Layout()
+
+    def _showError(self, text):
+        """Displays a error message to the user.
+
+        This function should be used only when something serious and unexpected
+        happens, otherwise _showWarning should be used.
+
+        .. note::
+            There is no cleaning procedure. You should call _hideMessage when
+            you know that there is everything correct now.
+        """
+        self.lmessage.SetLabel(_("Error: {text}").format(text=text))
+        self.lmessage.Wrap(self.GetClientSize()[0])
+        self.sizer.Layout()
+
+    def _hideMessage(self):
+        """Clears/hides the error message."""
+        # we do no hide widget
+        # because we do not want the dialog to change the size
+        self.lmessage.SetLabel("")
+        self.sizer.Layout()
+
+    def GetRCValue(self, value):
+        """Return GRASS variable (read from GISRC)
+        """
+        if value in self.grassrc:
+            return self.grassrc[value]
+        else:
+            return None
+
+    def OnWizard(self, event):
+        """Location wizard started"""
+        from location_wizard.wizard import LocationWizard
+        gWizard = LocationWizard(parent=self,
+                                 grassdatabase=self.tgisdbase.GetValue())
+        if gWizard.location is not None:
+            self.tgisdbase.SetValue(gWizard.grassdatabase)
+            self.OnSetDatabase(None)
+            self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
+            self.lblocations.SetSelection(
+                self.listOfLocations.index(
+                    gWizard.location))
+            self.lbmapsets.SetSelection(0)
+            self.SetLocation(self.gisdbase, gWizard.location, 'PERMANENT')
+            if gWizard.georeffile:
+                message = _("Do you want to import <%(name)s> to the newly created location?") % {
+                    'name': gWizard.georeffile}
+                dlg = wx.MessageDialog(parent=self, message=message, caption=_(
+                    "Import data?"), style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+                dlg.CenterOnParent()
+                if dlg.ShowModal() == wx.ID_YES:
+                    self.ImportFile(gWizard.georeffile)
+                dlg.Destroy()
+            if gWizard.default_region:
+                defineRegion = RegionDef(self, location=gWizard.location)
+                defineRegion.CenterOnParent()
+                defineRegion.ShowModal()
+                defineRegion.Destroy()
+
+            if gWizard.user_mapset:
+                dlg = TextEntryDialog(
+                    parent=self,
+                    message=_("New mapset:"),
+                    caption=_("Create new mapset"),
+                    defaultValue=self._getDefaultMapsetName(),
+                    validator=GenericValidator(
+                        grass.legal_name,
+                        self._nameValidationFailed
+                    ),
+                    style=wx.OK | wx.CANCEL | wx.HELP
+                )
+                help = dlg.FindWindowById(wx.ID_HELP)
+                help.Bind(wx.EVT_BUTTON, self.OnHelp)
+                if dlg.ShowModal() == wx.ID_OK:
+                    mapsetName = dlg.GetValue()
+                    self.CreateNewMapset(mapsetName)
+
+    def ImportFile(self, filePath):
+        """Tries to import file as vector or raster.
+
+        If successfull sets default region from imported map.
+        """
+        RunCommand('db.connect', flags='c')
+        mapName = os.path.splitext(os.path.basename(filePath))[0]
+        vectors = RunCommand('v.in.ogr', input=filePath, flags='l',
+                             read=True)
+
+        wx.BeginBusyCursor()
+        wx.Yield()
+        if mapName in vectors:
+            # vector detected
+            returncode, error = RunCommand(
+                'v.in.ogr', input=filePath, output=mapName, flags='e',
+                getErrorMsg=True)
+        else:
+            returncode, error = RunCommand(
+                'r.in.gdal', input=filePath, output=mapName, flags='e',
+                getErrorMsg=True)
+        wx.EndBusyCursor()
+
+        if returncode != 0:
+            GError(
+                parent=self,
+                message=_(
+                    "Import of <%(name)s> failed.\n"
+                    "Reason: %(msg)s") % ({
+                        'name': filePath,
+                        'msg': error}))
+        else:
+            GMessage(
+                message=_(
+                    "Data file <%(name)s> imported successfully. "
+                    "The location's default region was set from this imported map.") % {
+                    'name': filePath},
+                parent=self)
+
+    # the event can be refactored out by using lambda in bind
+    def RenameMapset(self, event):
+        """Rename selected mapset
+        """
+        location = self.listOfLocations[self.lblocations.GetSelection()]
+        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
+        if mapset == 'PERMANENT':
+            GMessage(
+                parent=self, message=_(
+                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
+                    'This mapset cannot be renamed.'))
+            return
+
+        dlg = TextEntryDialog(
+            parent=self,
+            message=_('Current name: %s\n\nEnter new name:') %
+            mapset,
+            caption=_('Rename selected mapset'),
+            validator=GenericValidator(
+                grass.legal_name,
+                self._nameValidationFailed))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            newmapset = dlg.GetValue()
+            if newmapset == mapset:
+                dlg.Destroy()
+                return
+
+            if newmapset in self.listOfMapsets:
+                wx.MessageBox(
+                    parent=self, caption=_('Message'), message=_(
+                        'Unable to rename mapset.\n\n'
+                        'Mapset <%s> already exists in location.') %
+                    newmapset, style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            else:
+                try:
+                    os.rename(os.path.join(self.gisdbase, location, mapset),
+                              os.path.join(self.gisdbase, location, newmapset))
+                    self.OnSelectLocation(None)
+                    self.lbmapsets.SetSelection(
+                        self.listOfMapsets.index(newmapset))
+                except Exception as e:
+                    wx.MessageBox(
+                        parent=self,
+                        caption=_('Error'),
+                        message=_('Unable to rename mapset.\n\n%s') %
+                        e,
+                        style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+
+        dlg.Destroy()
+
+    def RenameLocation(self, event):
+        """Rename selected location
+        """
+        location = self.listOfLocations[self.lblocations.GetSelection()]
+
+        dlg = TextEntryDialog(
+            parent=self,
+            message=_('Current name: %s\n\nEnter new name:') %
+            location,
+            caption=_('Rename selected location'),
+            validator=GenericValidator(
+                grass.legal_name,
+                self._nameValidationFailed))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            newlocation = dlg.GetValue()
+            if newlocation == location:
+                dlg.Destroy()
+                return
+
+            if newlocation in self.listOfLocations:
+                wx.MessageBox(
+                    parent=self, caption=_('Message'), message=_(
+                        'Unable to rename location.\n\n'
+                        'Location <%s> already exists in GRASS database.') %
+                    newlocation, style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            else:
+                try:
+                    os.rename(os.path.join(self.gisdbase, location),
+                              os.path.join(self.gisdbase, newlocation))
+                    self.UpdateLocations(self.gisdbase)
+                    self.lblocations.SetSelection(
+                        self.listOfLocations.index(newlocation))
+                    self.UpdateMapsets(newlocation)
+                except Exception as e:
+                    wx.MessageBox(
+                        parent=self,
+                        caption=_('Error'),
+                        message=_('Unable to rename location.\n\n%s') %
+                        e,
+                        style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+
+        dlg.Destroy()
+
+    def DeleteMapset(self, event):
+        """Delete selected mapset
+        """
+        location = self.listOfLocations[self.lblocations.GetSelection()]
+        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
+        if mapset == 'PERMANENT':
+            GMessage(
+                parent=self, message=_(
+                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
+                    'This mapset cannot be deleted.'))
+            return
+
+        dlg = wx.MessageDialog(
+            parent=self,
+            message=_(
+                "Do you want to continue with deleting mapset <%(mapset)s> "
+                "from location <%(location)s>?\n\n"
+                "ALL MAPS included in this mapset will be "
+                "PERMANENTLY DELETED!") %
+            {'mapset': mapset, 'location': location},
+            caption=_("Delete selected mapset"),
+            style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+
+        if dlg.ShowModal() == wx.ID_YES:
+            try:
+                shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
+                self.OnSelectLocation(None)
+                self.lbmapsets.SetSelection(0)
+            except:
+                wx.MessageBox(message=_('Unable to delete mapset'))
+
+        dlg.Destroy()
+
+    def DeleteLocation(self, event):
+        """
+        Delete selected location
+        """
+
+        location = self.listOfLocations[self.lblocations.GetSelection()]
+
+        dlg = wx.MessageDialog(
+            parent=self,
+            message=_(
+                "Do you want to continue with deleting "
+                "location <%s>?\n\n"
+                "ALL MAPS included in this location will be "
+                "PERMANENTLY DELETED!") %
+            (location),
+            caption=_("Delete selected location"),
+            style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+
+        if dlg.ShowModal() == wx.ID_YES:
+            try:
+                shutil.rmtree(os.path.join(self.gisdbase, location))
+                self.UpdateLocations(self.gisdbase)
+                self.lblocations.SetSelection(0)
+                self.OnSelectLocation(None)
+                self.lbmapsets.SetSelection(0)
+            except:
+                wx.MessageBox(message=_('Unable to delete location'))
+
+        dlg.Destroy()
+
+    def UpdateLocations(self, dbase):
+        """Update list of locations"""
+        try:
+            self.listOfLocations = GetListOfLocations(dbase)
+        except (UnicodeEncodeError, UnicodeDecodeError) as e:
+            GError(parent=self,
+                   message=_("Unicode error detected. "
+                             "Check your locale settings. Details: {0}").format(e),
+                   showTraceback=False)
+
+        self.lblocations.Clear()
+        self.lblocations.InsertItems(self.listOfLocations, 0)
+
+        if len(self.listOfLocations) > 0:
+            self._hideMessage()
+            self.lblocations.SetSelection(0)
+        else:
+            self.lblocations.SetSelection(wx.NOT_FOUND)
+            self._showWarning(_("No GRASS Location found in '%s'."
+                                " Create a new Location or choose different"
+                                " GRASS database directory.")
+                              % self.gisdbase)
+
+        return self.listOfLocations
+
+    def UpdateMapsets(self, location):
+        """Update list of mapsets"""
+        self.FormerMapsetSelection = wx.NOT_FOUND  # for non-selectable item
+
+        self.listOfMapsetsSelectable = list()
+        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)
+
+        self.lbmapsets.Clear()
+
+        # disable mapset with denied permission
+        locationName = os.path.basename(location)
+
+        ret = RunCommand('g.mapset',
+                         read=True,
+                         flags='l',
+                         location=locationName,
+                         gisdbase=self.gisdbase)
+
+        if ret:
+            for line in ret.splitlines():
+                self.listOfMapsetsSelectable += line.split(' ')
+        else:
+            RunCommand("g.gisenv",
+                       set="GISDBASE=%s" % self.gisdbase)
+            RunCommand("g.gisenv",
+                       set="LOCATION_NAME=%s" % locationName)
+            RunCommand("g.gisenv",
+                       set="MAPSET=PERMANENT")
+            # first run only
+            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
+
+        disabled = []
+        idx = 0
+        for mapset in self.listOfMapsets:
+            if mapset not in self.listOfMapsetsSelectable or \
+                    os.path.isfile(os.path.join(self.gisdbase,
+                                                locationName,
+                                                mapset, ".gislock")):
+                disabled.append(idx)
+            idx += 1
+
+        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)
+
+        return self.listOfMapsets
+
+    def OnSelectLocation(self, event):
+        """Location selected"""
+        if event:
+            self.lblocations.SetSelection(event.GetIndex())
+
+        if self.lblocations.GetSelection() != wx.NOT_FOUND:
+            self.UpdateMapsets(
+                os.path.join(
+                    self.gisdbase,
+                    self.listOfLocations[
+                        self.lblocations.GetSelection()]))
+        else:
+            self.listOfMapsets = []
+
+        disabled = []
+        idx = 0
+        try:
+            locationName = self.listOfLocations[
+                self.lblocations.GetSelection()]
+        except IndexError:
+            locationName = ''
+
+        for mapset in self.listOfMapsets:
+            if mapset not in self.listOfMapsetsSelectable or \
+                    os.path.isfile(os.path.join(self.gisdbase,
+                                                locationName,
+                                                mapset, ".gislock")):
+                disabled.append(idx)
+            idx += 1
+
+        self.lbmapsets.Clear()
+        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)
+
+        if len(self.listOfMapsets) > 0:
+            self.lbmapsets.SetSelection(0)
+            if locationName:
+                # enable start button when location and mapset is selected
+                self.bstart.Enable()
+                self.bstart.SetFocus()
+                self.bmapset.Enable()
+                # replacing disabled choice, perhaps just mapset needed
+                self.rename_location_button.Enable()
+                self.delete_location_button.Enable()
+                self.rename_mapset_button.Enable()
+                self.delete_mapset_button.Enable()
+        else:
+            self.lbmapsets.SetSelection(wx.NOT_FOUND)
+            self.bstart.Enable(False)
+            self.bmapset.Enable(False)
+            # this all was originally a choice, perhaps just mapset needed
+            self.rename_location_button.Enable(False)
+            self.delete_location_button.Enable(False)
+            self.rename_mapset_button.Enable(False)
+            self.delete_mapset_button.Enable(False)
+
+    def OnSelectMapset(self, event):
+        """Mapset selected"""
+        self.lbmapsets.SetSelection(event.GetIndex())
+
+        if event.GetText() not in self.listOfMapsetsSelectable:
+            self.lbmapsets.SetSelection(self.FormerMapsetSelection)
+        else:
+            self.FormerMapsetSelection = event.GetIndex()
+            event.Skip()
+
+    def OnSetDatabase(self, event):
+        """Database set"""
+        gisdbase = self.tgisdbase.GetValue()
+        self._hideMessage()
+        if not os.path.exists(gisdbase):
+            self._showError(_("Path '%s' doesn't exist.") % gisdbase)
+            return
+
+        self.gisdbase = self.tgisdbase.GetValue()
+        self.UpdateLocations(self.gisdbase)
+
+        self.OnSelectLocation(None)
+
+    def OnBrowse(self, event):
+        """'Browse' button clicked"""
+        if not event:
+            defaultPath = os.getenv('HOME')
+        else:
+            defaultPath = ""
+
+        dlg = wx.DirDialog(parent=self, message=_("Choose GIS Data Directory"),
+                           defaultPath=defaultPath, style=wx.DD_DEFAULT_STYLE)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            self.gisdbase = dlg.GetPath()
+            self.tgisdbase.SetValue(self.gisdbase)
+            self.OnSetDatabase(event)
+
+        dlg.Destroy()
+
+    def OnCreateMapset(self, event):
+        """Create new mapset"""
+        dlg = TextEntryDialog(
+            parent=self,
+            message=_('Enter name for new mapset:'),
+            caption=_('Create new mapset'),
+            defaultValue=self._getDefaultMapsetName(),
+            validator=GenericValidator(
+                grass.legal_name,
+                self._nameValidationFailed))
+        if dlg.ShowModal() == wx.ID_OK:
+            mapset = dlg.GetValue()
+            return self.CreateNewMapset(mapset=mapset)
+        else:
+            return False
+
+    def CreateNewMapset(self, mapset):
+        if mapset in self.listOfMapsets:
+            GMessage(parent=self,
+                     message=_("Mapset <%s> already exists.") % mapset)
+            return False
+
+        if mapset.lower() == 'ogr':
+            dlg1 = wx.MessageDialog(
+                parent=self,
+                message=_(
+                    "Mapset <%s> is reserved for direct "
+                    "read access to OGR layers. Please consider to use "
+                    "another name for your mapset.\n\n"
+                    "Are you really sure that you want to create this mapset?") %
+                mapset,
+                caption=_("Reserved mapset name"),
+                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+            ret = dlg1.ShowModal()
+            dlg1.Destroy()
+            if ret == wx.ID_NO:
+                dlg1.Destroy()
+                return False
+
+        try:
+            self.gisdbase = self.tgisdbase.GetValue()
+            location = self.listOfLocations[self.lblocations.GetSelection()]
+            os.mkdir(os.path.join(self.gisdbase, location, mapset))
+            # copy WIND file and its permissions from PERMANENT and set
+            # permissions to u+rw,go+r
+            shutil.copy(
+                os.path.join(
+                    self.gisdbase,
+                    location,
+                    'PERMANENT',
+                    'WIND'),
+                os.path.join(
+                    self.gisdbase,
+                    location,
+                    mapset))
+            # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644)
+            self.OnSelectLocation(None)
+            self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
+            self.bstart.SetFocus()
+
+            return True
+        except Exception as e:
+            GError(parent=self,
+                   message=_("Unable to create new mapset: %s") % e,
+                   showTraceback=False)
+            return False
+
+    def OnStart(self, event):
+        """'Start GRASS' button clicked"""
+        dbase = self.tgisdbase.GetValue()
+        location = self.listOfLocations[self.lblocations.GetSelection()]
+        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
+
+        lockfile = os.path.join(dbase, location, mapset, '.gislock')
+        if os.path.isfile(lockfile):
+            dlg = wx.MessageDialog(
+                parent=self,
+                message=_(
+                    "GRASS is already running in selected mapset <%(mapset)s>\n"
+                    "(file %(lock)s found).\n\n"
+                    "Concurrent use not allowed.\n\n"
+                    "Do you want to try to remove .gislock (note that you "
+                    "need permission for this operation) and continue?") %
+                {'mapset': mapset, 'lock': lockfile},
+                caption=_("Lock file found"),
+                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
+
+            ret = dlg.ShowModal()
+            dlg.Destroy()
+            if ret == wx.ID_YES:
+                dlg1 = wx.MessageDialog(
+                    parent=self,
+                    message=_(
+                        "ARE YOU REALLY SURE?\n\n"
+                        "If you really are running another GRASS session doing this "
+                        "could corrupt your data. Have another look in the processor "
+                        "manager just to be sure..."),
+                    caption=_("Lock file found"),
+                    style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
+
+                ret = dlg1.ShowModal()
+                dlg1.Destroy()
+
+                if ret == wx.ID_YES:
+                    try:
+                        os.remove(lockfile)
+                    except IOError as e:
+                        GError(_("Unable to remove '%(lock)s'.\n\n"
+                                 "Details: %(reason)s") % {'lock': lockfile, 'reason': e})
+                else:
+                    return
+            else:
+                return
+        self.SetLocation(dbase, location, mapset)
+        self.ExitSuccessfully()
+
+    def SetLocation(self, dbase, location, mapset):
+        RunCommand("g.gisenv",
+                   set="GISDBASE=%s" % dbase)
+        RunCommand("g.gisenv",
+                   set="LOCATION_NAME=%s" % location)
+        RunCommand("g.gisenv",
+                   set="MAPSET=%s" % mapset)
+
+    def _getDefaultMapsetName(self):
+        """Returns default name for mapset."""
+        try:
+            defaultName = getpass.getuser()
+            # raise error if not ascii (not valid mapset name)
+            defaultName.encode('ascii')
+        except:  # whatever might go wrong
+            defaultName = 'user'
+
+        return defaultName
+
+    def ExitSuccessfully(self):
+        self.Destroy()
+        sys.exit(self.exit_success)
+
+    def OnExit(self, event):
+        """'Exit' button clicked"""
+        self.Destroy()
+        sys.exit(self.exit_user_requested)
+
+    def OnHelp(self, event):
+        """'Help' button clicked"""
+
+        # help text in lib/init/helptext.html
+        RunCommand('g.manual', entry='helptext')
+
+    def OnCloseWindow(self, event):
+        """Close window event"""
+        event.Skip()
+        sys.exit(self.exit_user_requested)
+
+    def _nameValidationFailed(self, ctrl):
+        message = _(
+            "Name <%(name)s> is not a valid name for location or mapset. "
+            "Please use only ASCII characters excluding %(chars)s "
+            "and space.") % {
+            'name': ctrl.GetValue(),
+            'chars': '/"\'@,=*~'}
+        GError(parent=self, message=message, caption=_("Invalid name"))
+
+
+class GListBox(ListCtrl, listmix.ListCtrlAutoWidthMixin):
+    """Use wx.ListCtrl instead of wx.ListBox, different style for
+    non-selectable items (e.g. mapsets with denied permission)"""
+
+    def __init__(self, parent, id, size,
+                 choices, disabled=[]):
+        ListCtrl.__init__(
+            self, parent, id, size=size, style=wx.LC_REPORT | wx.LC_NO_HEADER |
+            wx.LC_SINGLE_SEL | wx.BORDER_SUNKEN)
+
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+        self.InsertColumn(0, '')
+
+        self.selected = wx.NOT_FOUND
+
+        self._LoadData(choices, disabled)
+
+    def _LoadData(self, choices, disabled=[]):
+        """Load data into list
+
+        :param choices: list of item
+        :param disabled: list of indices of non-selectable items
+        """
+        idx = 0
+        count = self.GetItemCount()
+        for item in choices:
+            index = self.InsertStringItem(count + idx, item)
+            self.SetStringItem(index, 0, item)
+
+            if idx in disabled:
+                self.SetItemTextColour(idx, wx.Colour(150, 150, 150))
+            idx += 1
+
+    def Clear(self):
+        self.DeleteAllItems()
+
+    def InsertItems(self, choices, pos, disabled=[]):
+        self._LoadData(choices, disabled)
+
+    def SetSelection(self, item, force=False):
+        if item !=  wx.NOT_FOUND and \
+                (platform.system() != 'Windows' or force):
+            # Windows -> FIXME
+            self.SetItemState(
+                item,
+                wx.LIST_STATE_SELECTED,
+                wx.LIST_STATE_SELECTED)
+
+        self.selected = item
+
+    def GetSelection(self):
+        return self.selected
+
+
+class StartUp(wx.App):
+    """Start-up application"""
+
+    def OnInit(self):
+        if not globalvar.CheckWxVersion([2, 9]):
+            wx.InitAllImageHandlers()
+        StartUp = GRASSStartup()
+        StartUp.CenterOnScreen()
+        self.SetTopWindow(StartUp)
+        StartUp.Show()
+
+        if StartUp.GetRCValue("LOCATION_NAME") == "<UNKNOWN>":
+            # TODO: This is not ideal, either it should be checked elsewhere
+            # where other checks are performed or it should use some public
+            # API. There is no reason for not exposing it.
+            # TODO: another question is what should be warning, hint or message
+            StartUp._showWarning(
+                _(
+                    'GRASS needs a directory (GRASS database) '
+                    'in which to store its data. '
+                    'Create one now if you have not already done so. '
+                    'A popular choice is "grassdata", located in '
+                    'your home directory. '
+                    'Press Browse button to select the directory.'))
+
+        return 1
+
+if __name__ == "__main__":
+    if os.getenv("GISBASE") is None:
+        sys.exit("Failed to start GUI, GRASS GIS is not running.")
+
+    GRASSStartUp = StartUp(0)
+    GRASSStartUp.MainLoop()

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set_error.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set_error.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_gis_set_error.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,38 @@
+"""
+ at package gis_set_error
+
+GRASS start-up screen error message.
+
+(C) 2010-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+
+from core import globalvar
+import wx
+
+
+def main():
+    app = wx.App()
+
+    if len(sys.argv) == 1:
+        msg = "Unknown reason"
+    else:
+        msg = ''
+        for m in sys.argv[1:]:
+            msg += m
+
+    wx.MessageBox(caption="Error",
+                  message=msg,
+                  style=wx.OK | wx.ICON_ERROR)
+
+    app.MainLoop()
+
+if __name__ == "__main__":
+    main()

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_manager.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_manager.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_manager.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,3282 @@
+"""
+ at package gcp.manager
+
+ at brief Georectification module for GRASS GIS. Includes ground control
+point management and interactive point and click GCP creation
+
+Classes:
+ - manager::GCPWizard
+ - manager::LocationPage
+ - manager::GroupPage
+ - manager::DispMapPage
+ - manager::GCP
+ - manager::GCPList
+ - manager::VectGroup
+ - manager::EditGCP
+ - manager::GrSettingsDialog
+
+(C) 2006-2014 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Original author Michael Barton
+ at author Original version improved by Martin Landa <landa.martin gmail.com>
+ at author Rewritten by Markus Metz redesign georectfier -> GCP Manage
+ at author Support for GraphicsSet added by Stepan Turek <stepan.turek seznam.cz> (2012)
+
+TODO: i.ortho.transform has 6 appearances, check each of them and configure
+"""
+
+import os
+import sys
+import shutil
+import time
+from copy import copy
+
+import wx
+from wx.lib.mixins.listctrl import CheckListCtrlMixin, ColumnSorterMixin, ListCtrlAutoWidthMixin
+import wx.lib.colourselect as csel
+
+from core import globalvar
+if globalvar.wxPythonPhoenix:
+    from wx.adv import Wizard as wiz
+else:
+    import wx.wizard as wiz
+
+import grass.script as grass
+
+
+from core import utils
+from core.render import Map
+from core.utils import _
+from gui_core.gselect import Select, LocationSelect, MapsetSelect
+from gui_core.dialogs import GroupDialog
+from core.gcmd import RunCommand, GMessage, GError, GWarning, EncodeString
+from core.settings import UserSettings
+from gcp.mapdisplay import MapFrame
+from core.giface import Notification
+from gui_core.wrap import SpinCtrl
+
+from location_wizard.wizard import TitledPage as TitledPage
+
+#
+# global variables
+#
+global src_map
+global tgt_map
+global maptype
+
+src_map = ''
+tgt_map = {'raster': '',
+           'vector': ''}
+maptype = 'raster'
+
+
+def getSmallUpArrowImage():
+    stream = open(os.path.join(globalvar.IMGDIR, 'small_up_arrow.png'), 'rb')
+    try:
+        img = wx.ImageFromStream(stream)
+    finally:
+        stream.close()
+    return img
+
+
+def getSmallDnArrowImage():
+    stream = open(os.path.join(globalvar.IMGDIR, 'small_down_arrow.png'), 'rb')
+    try:
+        img = wx.ImageFromStream(stream)
+    finally:
+        stream.close()
+    stream.close()
+    return img
+
+
+class GCPWizard(object):
+    """
+    Start wizard here and finish wizard here
+    """
+
+    #def __init__(self, parent, giface, srcloc, srcmpt, srcgrp, srcras, tgtras, camera, order, extension):
+    #    global maptype
+    #    global src_map
+    #    global tgt_map
+    #    maptype = 'raster'
+    #    rendertype = 'raster'
+    #    self.parent = parent  # GMFrame
+    #    self._giface = giface
+    #    self.srcloc = srcloc
+    #    self.srcmpt = srcmpt
+    #    self.group = srcgrp
+    #    self.src_map = srcras
+    #    self.tgt_map = tgtras
+    #    self.camera = camera
+    #    self.order = int(order)
+    #    self.extension = extension
+    #    self.src_maps = self.src_map
+    #    # location for xy map to georectify
+    #    self.newlocation = self.srcloc 
+    #    # mapset for xy map to georectify
+    #    self.newmapset = self.srcmpt
+    def __init__(self, parent, giface):
+        self.parent = parent  # GMFrame
+        self._giface = giface
+
+        #
+        # get environmental variables
+        #
+        self.grassdatabase = grass.gisenv()['GISDBASE']
+
+        #
+        # read original environment settings
+        #
+        self.target_gisrc = os.environ['GISRC']
+        self.gisrc_dict = {}
+        try:
+            f = open(self.target_gisrc, 'r')
+            for line in f.readlines():
+                line = line.replace('\n', '').strip()
+                if len(line) < 1:
+                    continue
+                key, value = line.split(':', 1)
+                self.gisrc_dict[key.strip()] = value.strip()
+        finally:
+            f.close()
+
+        self.currentlocation = self.gisrc_dict['LOCATION_NAME']
+        self.currentmapset = self.gisrc_dict['MAPSET']
+        # location for xy map to georectify
+        self.newlocation = ''
+        # mapset for xy map to georectify
+        self.newmapset = ''
+
+        global maptype
+        global src_map
+        global tgt_map
+
+        #src_map = ''
+        #tgt_map = ''
+        maptype = 'raster'
+
+        # GISRC file for source location/mapset of map(s) to georectify
+        self.source_gisrc = ''
+        self.src_maps = []
+
+        #
+        # define wizard pages
+        #
+        self.wizard = wiz.Wizard(
+            parent=parent,
+            id=wx.ID_ANY,
+            title=_("Setup for georectification"))
+        self.startpage = LocationPage(self.wizard, self)
+        self.grouppage = GroupPage(self.wizard, self)
+        self.mappage = DispMapPage(self.wizard, self)
+
+        #
+        # set the initial order of the pages
+        #
+        self.startpage.SetNext(self.grouppage)
+        self.grouppage.SetPrev(self.startpage)
+        self.grouppage.SetNext(self.mappage)
+        self.mappage.SetPrev(self.grouppage)
+
+        #
+        # do pages layout
+        #
+        self.startpage.DoLayout()
+        self.grouppage.DoLayout()
+        self.mappage.DoLayout()
+        self.wizard.FitToPage(self.startpage)
+
+        # self.Bind(wx.EVT_CLOSE,    self.Cleanup)
+        # self.parent.Bind(wx.EVT_ACTIVATE, self.OnGLMFocus)
+
+        success = False
+
+        #
+        # run wizard
+        #
+        if self.wizard.RunWizard(self.startpage):
+            success = self.OnWizFinished()
+            if success == False:
+                GMessage(parent=self.parent,
+                         message=_("Georectifying setup canceled."))
+                self.Cleanup()
+        else:
+            GMessage(parent=self.parent,
+                     message=_("Georectifying setup canceled."))
+            self.Cleanup()
+
+        #
+        # start GCP display
+        #
+        if success != False:
+            # instance of render.Map to be associated with display
+            self.SwitchEnv('source')
+            self.SrcMap = Map(gisrc=self.source_gisrc)
+            self.SwitchEnv('target')
+            self.TgtMap = Map(gisrc=self.target_gisrc)
+            self.Map = self.SrcMap
+
+            #
+            # add layer to source map
+            #
+            if maptype == 'raster':
+                rendertype = 'raster'
+                cmdlist = ['d.rast', 'map=%s' % src_map]
+            else:  # -> vector layer
+                rendertype = 'vector'
+                cmdlist = ['d.vect', 'map=%s' % src_map]
+
+            self.SwitchEnv('source')
+            name, found = utils.GetLayerNameFromCmd(cmdlist)
+            self.SrcMap.AddLayer(
+                ltype=rendertype,
+                command=cmdlist,
+                active=True,
+                name=name,
+                hidden=False,
+                opacity=1.0,
+                render=False)
+
+            self.SwitchEnv('target')
+            if tgt_map['raster']:
+                #
+                # add raster layer to target map
+                #
+                rendertype = 'raster'
+                cmdlist = ['d.rast', 'map=%s' % tgt_map['raster']]
+
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.TgtMap.AddLayer(
+                    ltype=rendertype,
+                    command=cmdlist,
+                    active=True,
+                    name=name,
+                    hidden=False,
+                    opacity=1.0,
+                    render=False)
+
+            if tgt_map['vector']:
+                #
+                # add raster layer to target map
+                #
+                rendertype = 'vector'
+                cmdlist = ['d.vect', 'map=%s' % tgt_map['vector']]
+
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.TgtMap.AddLayer(
+                    ltype=rendertype,
+                    command=cmdlist,
+                    active=True,
+                    name=name,
+                    hidden=False,
+                    opacity=1.0,
+                    render=False)
+
+            #
+            # start GCP Manager
+            #
+            self.gcpmgr = GCP(self.parent, giface=self._giface,
+                              grwiz=self, size=globalvar.MAP_WINDOW_SIZE,
+                              toolbars=["gcpdisp"],
+                              Map=self.SrcMap, lmgr=self.parent)
+
+            # load GCPs
+            self.gcpmgr.InitMapDisplay()
+            self.gcpmgr.CenterOnScreen()
+            self.gcpmgr.Show()
+            # need to update AUI here for wingrass
+            self.gcpmgr._mgr.Update()
+        else:
+            self.Cleanup()
+
+    def SetSrcEnv(self, location, mapset):
+        """Create environment to use for location and mapset
+        that are the source of the file(s) to georectify
+
+        :param location: source location
+        :param mapset: source mapset
+
+        :return: False on error
+        :return: True on success
+        """
+
+        self.newlocation = location
+        self.newmapset = mapset
+
+        # check to see if we are georectifying map in current working
+        # location/mapset
+        if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+            return False
+
+        self.gisrc_dict['LOCATION_NAME'] = location
+        self.gisrc_dict['MAPSET'] = mapset
+
+        self.source_gisrc = EncodeString(utils.GetTempfile())
+
+        try:
+            f = open(self.source_gisrc, mode='w')
+            for line in self.gisrc_dict.items():
+                f.write(line[0] + ": " + line[1] + "\n")
+        finally:
+            f.close()
+
+        return True
+
+    def SwitchEnv(self, grc):
+        """
+        Switches between original working location/mapset and
+        location/mapset that is source of file(s) to georectify
+        """
+        # check to see if we are georectifying map in current working
+        # location/mapset
+        if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+            return False
+
+        if grc == 'target':
+            os.environ['GISRC'] = str(self.target_gisrc)
+        elif grc == 'source':
+            os.environ['GISRC'] = str(self.source_gisrc)
+
+        return True
+
+    def OnWizFinished(self):
+        # self.Cleanup()
+
+        return True
+
+    def OnGLMFocus(self, event):
+        """Layer Manager focus"""
+        # self.SwitchEnv('target')
+
+        event.Skip()
+
+    def Cleanup(self):
+        """Return to current location and mapset"""
+        # here was also the cleaning of gcpmanagement from layer manager
+        # which is no longer needed
+
+        self.SwitchEnv('target')
+        self.wizard.Destroy()
+
+
+class LocationPage(TitledPage):
+    """
+    Set map type (raster or vector) to georectify and
+    select location/mapset of map(s) to georectify.
+    """
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _(
+            "Select map type and location/mapset"))
+
+        self.parent = parent
+        self.grassdatabase = self.parent.grassdatabase
+
+        self.xylocation = ''
+        self.xymapset = ''
+
+        #
+        # layout
+        #
+        # map type
+        self.rb_maptype = wx.RadioBox(
+            parent=self, id=wx.ID_ANY, label=' %s ' %
+            _("Map type to georectify"), choices=[
+                _('raster'), _('vector')], majorDimension=wx.RA_SPECIFY_COLS)
+        self.sizer.Add(self.rb_maptype,
+                       flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, border=5,
+                       pos=(1, 1), span=(1, 2))
+
+        # location
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select source location:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                1))
+        self.cb_location = LocationSelect(
+            parent=self, gisdbase=self.grassdatabase)
+        self.sizer.Add(
+            self.cb_location,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                2))
+
+        # mapset
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select source mapset:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                3,
+                1))
+        self.cb_mapset = MapsetSelect(parent=self, gisdbase=self.grassdatabase,
+                                      setItems=False)
+        self.sizer.Add(self.cb_mapset, flag=wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5, pos=(3, 2))
+        self.sizer.AddGrowableCol(2)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
+        self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
+        self.cb_mapset.Bind(wx.EVT_TEXT, self.OnMapset)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        # self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
+
+    def OnMaptype(self, event):
+        """Change map type"""
+        global maptype
+
+        if event.GetInt() == 0:
+            maptype = 'raster'
+        else:
+            maptype = 'vector'
+
+    def OnLocation(self, event):
+        """Sets source location for map(s) to georectify"""
+        self.xylocation = event.GetString()
+
+        # create a list of valid mapsets
+        tmplist = os.listdir(os.path.join(self.grassdatabase, self.xylocation))
+        self.mapsetList = []
+        for item in tmplist:
+            if os.path.isdir(os.path.join(self.grassdatabase, self.xylocation, item)) and \
+                    os.path.exists(os.path.join(self.grassdatabase, self.xylocation, item, 'WIND')):
+                if item != 'PERMANENT':
+                    self.mapsetList.append(item)
+
+        self.xymapset = 'PERMANENT'
+        utils.ListSortLower(self.mapsetList)
+        self.mapsetList.insert(0, 'PERMANENT')
+        self.cb_mapset.SetItems(self.mapsetList)
+        self.cb_mapset.SetStringSelection(self.xymapset)
+
+        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+    def OnMapset(self, event):
+        """Sets source mapset for map(s) to georectify"""
+        if self.xylocation == '':
+            GMessage(_('You must select a valid location '
+                       'before selecting a mapset'),
+                     parent=self)
+            return
+
+        self.xymapset = event.GetString()
+
+        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+    def OnPageChanging(self, event=None):
+        if event.GetDirection() and \
+                (self.xylocation == '' or self.xymapset == ''):
+            GMessage(_('You must select a valid location '
+                       'and mapset in order to continue'),
+                     parent=self)
+            event.Veto()
+            return
+
+        self.parent.SetSrcEnv(self.xylocation, self.xymapset)
+
+    def OnEnterPage(self, event=None):
+        if self.xylocation == '' or self.xymapset == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+
+class GroupPage(TitledPage):
+    """
+    Set group to georectify. Create group if desired.
+    """
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _(
+            "Select image/map group to georectify"))
+
+        self.parent = parent
+
+        self.grassdatabase = self.parent.grassdatabase
+        self.groupList = []
+
+        self.xylocation = ''
+        self.xymapset = ''
+        self.xygroup = ''
+
+        # default extension
+        self.extension = '_georect' + str(os.getpid())
+
+        #
+        # layout
+        #
+        # group
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select group:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                1,
+                1))
+        self.cb_group = wx.ComboBox(parent=self, id=wx.ID_ANY,
+                                    choices=self.groupList, size=(350, -1),
+                                    style=wx.CB_DROPDOWN | wx.CB_READONLY)
+        self.sizer.Add(self.cb_group, flag=wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5, pos=(1, 2))
+
+        # create group
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Create group if none exists')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                1))
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.btn_mkgroup = wx.Button(
+            parent=self,
+            id=wx.ID_ANY,
+            label=_("Create/edit group..."))
+        self.btn_vgroup = wx.Button(
+            parent=self,
+            id=wx.ID_ANY,
+            label=_("Add vector map to group..."))
+        btnSizer.Add(self.btn_mkgroup,
+                     flag=wx.RIGHT, border=5)
+
+        btnSizer.Add(self.btn_vgroup,
+                     flag=wx.LEFT, border=5)
+
+        self.sizer.Add(
+            btnSizer,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                2))
+
+        # extension
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Extension for output maps:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                3,
+                1))
+        self.ext_txt = wx.TextCtrl(
+            parent=self, id=wx.ID_ANY, value="", size=(
+                350, -1))
+        self.ext_txt.SetValue(self.extension)
+        self.sizer.Add(self.ext_txt, flag=wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5, pos=(3, 2))
+
+        self.sizer.AddGrowableCol(2)
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_COMBOBOX, self.OnGroup, self.cb_group)
+        self.Bind(wx.EVT_TEXT, self.OnExtension, self.ext_txt)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
+
+        # hide vector group button by default
+        self.btn_vgroup.Hide()
+
+    def OnGroup(self, event):
+        self.xygroup = event.GetString()
+
+    def OnMkGroup(self, event):
+        """Create new group in source location/mapset"""
+        dlg = GroupDialog(parent=self, defaultGroup=self.xygroup)
+        dlg.DisableSubgroupEdit()
+        dlg.ShowModal()
+        gr, s = dlg.GetSelectedGroup()
+        if gr in dlg.GetExistGroups():
+            self.xygroup = gr
+        else:
+            gr = ''
+        dlg.Destroy()
+
+        self.OnEnterPage()
+        self.Update()
+
+    def OnVGroup(self, event):
+        """Add vector maps to group"""
+        dlg = VectGroup(parent=self,
+                        id=wx.ID_ANY,
+                        grassdb=self.grassdatabase,
+                        location=self.xylocation,
+                        mapset=self.xymapset,
+                        group=self.xygroup)
+
+        if dlg.ShowModal() != wx.ID_OK:
+            return
+
+        dlg.MakeVGroup()
+        self.OnEnterPage()
+
+    def OnExtension(self, event):
+        self.extension = self.ext_txt.GetValue()
+
+    def OnPageChanging(self, event=None):
+        if event.GetDirection() and self.xygroup == '':
+            GMessage(_('You must select a valid image/map '
+                       'group in order to continue'),
+                     parent=self)
+            event.Veto()
+            return
+
+        if event.GetDirection() and self.extension == '':
+            GMessage(_('You must enter an map name '
+                       'extension in order to continue'),
+                     parent=self)
+            event.Veto()
+            return
+
+    def OnEnterPage(self, event=None):
+        global maptype
+
+        self.groupList = []
+
+        self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
+        self.xymapset = self.parent.gisrc_dict['MAPSET']
+
+        # create a list of groups in selected mapset
+        if os.path.isdir(os.path.join(self.grassdatabase,
+                                      self.xylocation,
+                                      self.xymapset,
+                                      'group')):
+            tmplist = os.listdir(os.path.join(self.grassdatabase,
+                                              self.xylocation,
+                                              self.xymapset,
+                                              'group'))
+            for item in tmplist:
+                if os.path.isdir(os.path.join(self.grassdatabase,
+                                              self.xylocation,
+                                              self.xymapset,
+                                              'group',
+                                              item)):
+                    self.groupList.append(item)
+
+        if maptype == 'raster':
+            self.btn_vgroup.Hide()
+            self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
+
+        elif maptype == 'vector':
+            self.btn_vgroup.Show()
+            self.Bind(wx.EVT_BUTTON, self.OnMkGroup, self.btn_mkgroup)
+            self.Bind(wx.EVT_BUTTON, self.OnVGroup, self.btn_vgroup)
+
+        utils.ListSortLower(self.groupList)
+        self.cb_group.SetItems(self.groupList)
+
+        if len(self.groupList) > 0:
+            if self.xygroup and self.xygroup in self.groupList:
+                self.cb_group.SetStringSelection(self.xygroup)
+            else:
+                self.cb_group.SetSelection(0)
+                self.xygroup = self.groupList[0]
+
+        if self.xygroup == '' or \
+                self.extension == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        # switch to source
+        self.parent.SwitchEnv('source')
+
+
+class DispMapPage(TitledPage):
+    """
+    Select ungeoreferenced map to display for interactively
+    setting ground control points (GCPs).
+    """
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(
+            self, wizard,
+            _("Select maps to display for ground control point (GCP) creation"))
+
+        self.parent = parent
+        global maptype
+
+        #
+        # layout
+        #
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select source map to display:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                1,
+                1))
+
+        self.srcselection = Select(
+            self,
+            id=wx.ID_ANY,
+            size=globalvar.DIALOG_GSELECT_SIZE,
+            type=maptype,
+            updateOnPopup=False)
+
+        self.sizer.Add(
+            self.srcselection,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                1,
+                2))
+
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select target raster map to display:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                1))
+
+        self.tgtrastselection = Select(
+            self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+            type='raster', updateOnPopup=False)
+
+        self.sizer.Add(
+            self.tgtrastselection,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                2,
+                2))
+
+        self.sizer.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select target vector map to display:')),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                3,
+                1))
+
+        self.tgtvectselection = Select(
+            self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+            type='vector', updateOnPopup=False)
+
+        self.sizer.Add(
+            self.tgtvectselection,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5,
+            pos=(
+                3,
+                2))
+
+        #
+        # bindings
+        #
+        self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
+        self.tgtrastselection.Bind(wx.EVT_TEXT, self.OnTgtRastSelection)
+        self.tgtvectselection.Bind(wx.EVT_TEXT, self.OnTgtVectSelection)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
+
+    def OnSrcSelection(self, event):
+        """Source map to display selected"""
+        global src_map
+        global maptype
+
+        src_map = self.srcselection.GetValue()
+
+        if src_map == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        try:
+            # set computational region to match selected map and zoom display
+            # to region
+            if maptype == 'raster':
+                p = RunCommand('g.region', 'raster=src_map')
+            elif maptype == 'vector':
+                p = RunCommand('g.region', 'vector=src_map')
+
+            if p.returncode == 0:
+                print 'returncode = ', str(p.returncode)
+                self.parent.Map.region = self.parent.Map.GetRegion()
+        except:
+            pass
+
+    def OnTgtRastSelection(self, event):
+        """Source map to display selected"""
+        global tgt_map
+
+        tgt_map['raster'] = self.tgtrastselection.GetValue()
+
+    def OnTgtVectSelection(self, event):
+        """Source map to display selected"""
+        global tgt_map
+
+        tgt_map['vector'] = self.tgtvectselection.GetValue()
+
+    def OnPageChanging(self, event=None):
+        global src_map
+        global tgt_map
+
+        if event.GetDirection() and (src_map == ''):
+            GMessage(_('You must select a source map '
+                       'in order to continue'),
+                     parent=self)
+            event.Veto()
+            return
+
+        self.parent.SwitchEnv('target')
+
+    def OnEnterPage(self, event=None):
+        global maptype
+        global src_map
+        global tgt_map
+
+        self.srcselection.SetElementList(maptype)
+
+        if maptype == 'raster':
+            ret = RunCommand('i.group',
+                             parent=self,
+                             read=True,
+                             group=self.parent.grouppage.xygroup,
+                             flags='g')
+
+            if ret:
+                self.parent.src_maps = ret.splitlines()
+            else:
+                GError(
+                    parent=self, message=_(
+                        'No maps in selected group <%s>.\n'
+                        'Please edit group or select another group.') %
+                    self.parent.grouppage.xygroup)
+                return
+
+        elif maptype == 'vector':
+            grassdatabase = self.parent.grassdatabase
+            xylocation = self.parent.gisrc_dict['LOCATION_NAME']
+            xymapset = self.parent.gisrc_dict['MAPSET']
+            # make list of vectors to georectify from VREF
+
+            vgrpfile = os.path.join(grassdatabase,
+                                    xylocation,
+                                    xymapset,
+                                    'group',
+                                    self.parent.grouppage.xygroup,
+                                    'VREF')
+
+            f = open(vgrpfile)
+            try:
+                for vect in f.readlines():
+                    vect = vect.strip('\n')
+                    if len(vect) < 1:
+                        continue
+                    self.parent.src_maps.append(vect)
+            finally:
+                f.close()
+
+            if len(self.parent.src_maps) < 1:
+                GError(
+                    parent=self, message=_(
+                        'No maps in selected group <%s>.\n'
+                        'Please edit group or select another group.') %
+                    self.parent.grouppage.xygroup)
+                return
+
+        # filter out all maps not in group
+        self.srcselection.tcp.GetElementList(elements=self.parent.src_maps)
+        src_map = self.parent.src_maps[0]
+        self.srcselection.SetValue(src_map)
+
+        self.parent.SwitchEnv('target')
+        self.tgtrastselection.SetElementList('raster')
+        self.tgtrastselection.GetElementList()
+        self.tgtvectselection.SetElementList('vector')
+        self.tgtvectselection.GetElementList()
+        self.parent.SwitchEnv('source')
+
+        if src_map == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+
+class GCP(MapFrame, ColumnSorterMixin):
+    """
+    Manages ground control points for georectifying. Calculates RMS statistics.
+    Calls i.rectify or v.rectify to georectify map.
+    """
+
+    def __init__(self, parent, giface, grwiz=None, id=wx.ID_ANY,
+                 title=_("Manage Ground Control Points"),
+                 size=(700, 300), toolbars=["gcpdisp"], Map=None, lmgr=None):
+
+        self.grwiz = grwiz  # GR Wizard
+        self._giface = giface
+
+        if tgt_map['raster'] == '' and tgt_map['vector'] == '':
+            self.show_target = False
+        else:
+            self.show_target = True
+
+        #wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
+        MapFrame.__init__(
+            self,
+            parent=parent,
+            giface=self._giface,
+            title=title,
+            size=size,
+            Map=Map,
+            toolbars=toolbars,
+            name='GCPMapWindow')
+
+        # init variables
+        self.parent = parent
+
+        #
+        # register data structures for drawing GCP's
+        #
+        self.pointsToDrawTgt = self.TgtMapWindow.RegisterGraphicsToDraw(
+            graphicsType="point", setStatusFunc=self.SetGCPSatus)
+        self.pointsToDrawSrc = self.SrcMapWindow.RegisterGraphicsToDraw(
+            graphicsType="point", setStatusFunc=self.SetGCPSatus)
+
+        # connect to the map windows signals
+        # used to add or edit GCP
+        self.SrcMapWindow.mouseLeftUpPointer.connect(
+            lambda x, y:
+            self._onMouseLeftUpPointer(self.SrcMapWindow, x, y))
+        self.TgtMapWindow.mouseLeftUpPointer.connect(
+            lambda x, y:
+            self._onMouseLeftUpPointer(self.TgtMapWindow, x, y))
+
+        # window resized
+        self.resize = False
+
+        self.grassdatabase = self.grwiz.grassdatabase
+
+        self.currentlocation = self.grwiz.currentlocation
+        self.currentmapset = self.grwiz.currentmapset
+
+        self.newlocation = self.grwiz.newlocation
+        self.newmapset = self.grwiz.newmapset
+
+        self.xylocation = self.grwiz.gisrc_dict['LOCATION_NAME']
+        self.xymapset = self.grwiz.gisrc_dict['MAPSET']
+        self.xygroup = self.grwiz.grouppage.xygroup
+        self.src_maps = self.grwiz.src_maps
+        self.extension = self.grwiz.grouppage.extension
+        self.outname = ''
+        self.VectGRList = []
+
+        self.file = {
+            'ii2t_points': os.path.join(self.grassdatabase,
+                                   self.xylocation,
+                                   self.xymapset,
+                                   'group',
+                                   self.xygroup,
+                                   'II2T_POINTS'),
+            'ii2t_points_bak': os.path.join(self.grassdatabase,
+                                       self.xylocation,
+                                       self.xymapset,
+                                       'group',
+                                       self.xygroup,
+                                       'II2T_POINTS_BAK'),
+            'rgrp': os.path.join(self.grassdatabase,
+                                 self.xylocation,
+                                 self.xymapset,
+                                 'group',
+                                 self.xygroup,
+                                 'REF'),
+            'vgrp': os.path.join(self.grassdatabase,
+                                 self.xylocation,
+                                 self.xymapset,
+                                 'group',
+                                 self.xygroup,
+                                 'VREF'),
+            'target': os.path.join(self.grassdatabase,
+                                   self.xylocation,
+                                   self.xymapset,
+                                   'group',
+                                   self.xygroup,
+                                   'TARGET'),
+            'elevation': os.path.join(self.grassdatabase,
+                                   self.xylocation,
+                                   self.xymapset,
+                                   'group',
+                                   self.xygroup,
+                                   'ELEVATION'),
+        }
+
+        # make a backup of the current points file
+        if os.path.exists(self.file['ii2t_points']):
+            shutil.copy(self.file['ii2t_points'], self.file['ii2t_points_bak'])
+
+        # polynomial order transformation for georectification
+        self.gr_order = 1
+        # interpolation method for georectification
+        self.gr_method = 'nearest'
+        # region clipping for georectified map
+        self.clip_to_region = False
+        # number of GCPs selected to be used for georectification (checked)
+        self.GCPcount = 0
+        # forward RMS error
+        self.fwd_rmserror = 0.0
+        # backward RMS error
+        self.bkw_rmserror = 0.0
+        # list map coords and ID of map display they came from
+        self.mapcoordlist = []
+        self.mapcoordlist.append([0,        # GCP number
+                                  0.0,      # source east
+                                  0.0,      # source north
+                                  0.0,      # source height
+                                  0.0,      # target east
+                                  0.0,      # target north
+                                  0.0,      # target height
+                                  0.0,      # forward error
+                                  0.0])   # backward error
+
+        # init vars to highlight high RMS errors
+        self.highest_only = True
+        self.show_unused = True
+        self.highest_key = -1
+        self.rmsthresh = 0
+        self.rmsmean = 0
+        self.rmssd = 0
+
+        self.SetTarget(self.xygroup, self.currentlocation, self.currentmapset)
+
+        self.itemDataMap = None
+
+        # images for column sorting
+        # CheckListCtrlMixin must set an ImageList first
+        self.il = self.list.GetImageList(wx.IMAGE_LIST_SMALL)
+
+        SmallUpArrow = wx.BitmapFromImage(getSmallUpArrowImage())
+        SmallDnArrow = wx.BitmapFromImage(getSmallDnArrowImage())
+        self.sm_dn = self.il.Add(SmallDnArrow)
+        self.sm_up = self.il.Add(SmallUpArrow)
+
+        # set mouse characteristics
+        self.mapwin = self.SrcMapWindow
+        self.mapwin.mouse['box'] = 'point'
+        self.mapwin.mouse["use"] == "pointer"
+        self.mapwin.zoomtype = 0
+        self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
+        self.mapwin.SetNamedCursor('cross')
+
+        self.mapwin = self.TgtMapWindow
+
+        # set mouse characteristics
+        self.mapwin.mouse['box'] = 'point'
+        self.mapwin.mouse["use"] == "pointer"
+        self.mapwin.zoomtype = 0
+        self.mapwin.pen = wx.Pen(colour='black', width=2, style=wx.SOLID)
+        self.mapwin.SetNamedCursor('cross')
+
+        #
+        # show new display & draw map
+        #
+        if self.show_target:
+            self.MapWindow = self.TgtMapWindow
+            self.Map = self.TgtMap
+            self.OnZoomToMap(None)
+
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        self.OnZoomToMap(None)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+        self.Bind(wx.EVT_CLOSE, self.OnQuit)
+
+        self.SetSettings()
+
+    def __del__(self):
+        """Disable GCP manager mode"""
+        # leaving the method here but was used only to delete gcpmanagement
+        # from layer manager which is now not needed
+        pass
+
+    def CreateGCPList(self):
+        """Create GCP List Control"""
+
+        return GCPList(parent=self, gcp=self)
+
+    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+    def GetListCtrl(self):
+        return self.list
+
+    def GetMapCoordList(self):
+        return self.mapcoordlist
+
+    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+    def GetSortImages(self):
+        return (self.sm_dn, self.sm_up)
+
+    def GetFwdError(self):
+        return self.fwd_rmserror
+
+    def GetBkwError(self):
+        return self.bkw_rmserror
+
+    def InitMapDisplay(self):
+        self.list.LoadData()
+
+        # initialize column sorter
+        self.itemDataMap = self.mapcoordlist
+        ncols = self.list.GetColumnCount()
+        ColumnSorterMixin.__init__(self, ncols)
+        # init to ascending sort on first click
+        self._colSortFlag = [1] * ncols
+
+    def SetTarget(self, tgroup, tlocation, tmapset):
+        """
+        Sets rectification target to current location and mapset
+        """
+        # check to see if we are georectifying map in current working
+        # location/mapset
+        if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+            RunCommand('i.target',
+                       parent=self,
+                       flags='c',
+                       group=tgroup)
+        else:
+            self.grwiz.SwitchEnv('source')
+            RunCommand('i.target',
+                       parent=self,
+                       group=tgroup,
+                       location=tlocation,
+                       mapset=tmapset)
+            self.grwiz.SwitchEnv('target')
+
+    def AddGCP(self, event):
+        """
+        Appends an item to GCP list
+        """
+        keyval = self.list.AddGCPItem() + 1
+        # source east, source north, target east, target north, forward error,
+        # backward error
+        self.mapcoordlist.append([keyval,             # GCP number
+                                  0.0,                # source east
+                                  0.0,                # source north
+                                  0.0,                # source height
+                                  0.0,                # target east
+                                  0.0,                # target north
+                                  0.0,                # target height
+                                  0.0,                # forward error
+                                  0.0])             # backward error
+
+        if self.statusbarManager.GetMode() == 8:  # go to
+            self.StatusbarUpdate()
+
+    def DeleteGCP(self, event):
+        """
+        Deletes selected item in GCP list
+        """
+        minNumOfItems = self.OnGROrder(None)
+
+        if self.list.GetItemCount() <= minNumOfItems:
+            GMessage(
+                parent=self,
+                message=_("At least %d GCPs required. Operation canceled.") %
+                minNumOfItems)
+            return
+
+        key = self.list.DeleteGCPItem()
+        del self.mapcoordlist[key]
+
+        # update key and GCP number
+        for newkey in range(key, len(self.mapcoordlist)):
+            index = self.list.FindItemData(-1, newkey + 1)
+            self.mapcoordlist[newkey][0] = newkey
+            self.list.SetStringItem(index, 0, str(newkey))
+            self.list.SetItemData(index, newkey)
+
+        # update selected
+        if self.list.GetItemCount() > 0:
+            if self.list.selected < self.list.GetItemCount():
+                self.list.selectedkey = self.list.GetItemData(
+                    self.list.selected)
+            else:
+                self.list.selected = self.list.GetItemCount() - 1
+                self.list.selectedkey = self.list.GetItemData(
+                    self.list.selected)
+
+            self.list.SetItemState(self.list.selected,
+                                   wx.LIST_STATE_SELECTED,
+                                   wx.LIST_STATE_SELECTED)
+        else:
+            self.list.selected = wx.NOT_FOUND
+            self.list.selectedkey = -1
+
+        self.UpdateColours()
+
+        if self.statusbarManager.GetMode() == 8:  # go to
+            self.StatusbarUpdate()
+            if self.list.selectedkey > 0:
+                self.statusbarManager.SetProperty(
+                    'gotoGCP', self.list.selectedkey)
+
+    def ClearGCP(self, event):
+        """
+        Clears all values in selected item of GCP list and unchecks it
+        """
+        index = self.list.GetSelected()
+        key = self.list.GetItemData(index)
+        for i in range(1, 7):
+            self.list.SetStringItem(index, i, '0.0')
+        self.list.SetStringItem(index, 7, '')
+        self.list.SetStringItem(index, 8, '')
+        self.list.CheckItem(index, False)
+
+        # GCP number, source E, source N, target E, target N, fwd error, bkwd
+        # error
+        self.mapcoordlist[key] = [key, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+
+    def SetSettings(self):
+        """Sets settings for drawing of GCP's.
+        """
+        self.highest_only = UserSettings.Get(
+            group='gcpman', key='rms', subkey='highestonly')
+        self.show_unused = UserSettings.Get(
+            group='gcpman', key='symbol', subkey='unused')
+
+        colours = {"color": "default",
+                   "hcolor": "highest",
+                   "scolor": "selected",
+                   "ucolor": "unused"}
+        wpx = UserSettings.Get(group='gcpman', key='symbol', subkey='width')
+
+        for k, v in colours.iteritems():
+            col = UserSettings.Get(group='gcpman', key='symbol', subkey=k)
+            self.pointsToDrawSrc.GetPen(v).SetColour(wx.Colour(
+                col[0], col[1], col[2], 255))  # TODO GetPen neni to spatne?
+            self.pointsToDrawTgt.GetPen(v).SetColour(
+                wx.Colour(col[0], col[1], col[2], 255))
+
+            self.pointsToDrawSrc.GetPen(v).SetWidth(wpx)
+            self.pointsToDrawTgt.GetPen(v).SetWidth(wpx)
+
+        spx = UserSettings.Get(group='gcpman', key='symbol', subkey='size')
+        self.pointsToDrawSrc.SetPropertyVal("size", int(spx))
+        self.pointsToDrawTgt.SetPropertyVal("size", int(spx))
+
+        font = self.GetFont()
+        font.SetPointSize(int(spx) + 2)
+
+        textProp = {}
+        textProp['active'] = True
+        textProp['font'] = font
+        self.pointsToDrawSrc.SetPropertyVal("text", textProp)
+        self.pointsToDrawTgt.SetPropertyVal("text", copy(textProp))
+
+    def SetGCPSatus(self, item, itemIndex):
+        """Before GCP is drawn, decides it's colour and whether it
+        will be drawed.
+        """
+        key = self.list.GetItemData(itemIndex)
+        # incremented because of itemDataMap (has one more item) - will be
+        # changed
+        itemIndex += 1
+
+        if not self.list.IsChecked(key - 1):
+            wxPen = "unused"
+            if not self.show_unused:
+                item.SetPropertyVal('hide', True)
+            else:
+                item.SetPropertyVal('hide', False)
+
+        else:
+            item.SetPropertyVal('hide', False)
+            if self.highest_only == True:
+                if itemIndex == self.highest_key:
+                    wxPen = "highest"
+                else:
+                    wxPen = "default"
+            else:
+                if (self.mapcoordlist[key][7] > self.rmsthresh):
+                    wxPen = "highest"
+                else:
+                    wxPen = "default"
+
+        if itemIndex == self.list.selectedkey:
+            wxPen = "selected"
+
+        item.SetPropertyVal('label', str(itemIndex))
+        item.SetPropertyVal('penName', wxPen)
+
+    def SetGCPData(self, coordtype, coord, mapdisp=None, confirm=False):
+        """Inserts coordinates from file, mouse click on map, or
+        after editing into selected item of GCP list and checks it for
+        use.
+        """
+        index = self.list.GetSelected()
+        if index == wx.NOT_FOUND:
+            return
+
+        coord0 = coord[0]
+        coord1 = coord[1]
+
+        key = self.list.GetItemData(index)
+        if confirm:
+            if self.MapWindow == self.SrcMapWindow:
+                currloc = _("source")
+            else:
+                currloc = _("target")
+            ret = wx.MessageBox(
+                parent=self, caption=_("Set GCP coordinates"),
+                message=_(
+                    'Set %(coor)s coordinates for GCP No. %(key)s? \n\n'
+                    'East: %(coor0)s \n'
+                    'North: %(coor1)s') %
+                {'coor': currloc, 'key': str(key),
+                 'coor0': str(coord0),
+                 'coor1': str(coord1)},
+                style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
+
+            # for wingrass
+            if os.name == 'nt':
+                self.MapWindow.SetFocus()
+            if ret == wx.NO:
+                return
+
+        if coordtype == 'source':
+            self.list.SetStringItem(index, 1, str(coord0))
+            self.list.SetStringItem(index, 2, str(coord1))
+            self.mapcoordlist[key][1] = coord[0]
+            self.mapcoordlist[key][2] = coord[1]
+            self.pointsToDrawSrc.GetItem(key - 1).SetCoords([coord0, coord1])
+
+        elif coordtype == 'target':
+            self.list.SetStringItem(index, 4, str(coord0))
+            self.list.SetStringItem(index, 5, str(coord1))
+            self.mapcoordlist[key][4] = coord[0]
+            self.mapcoordlist[key][5] = coord[1]
+            #TODO ADD ELEVATION FROM MAP AS HEIGHT
+            if os.path.exists(self.file['elevation']):
+                #Parse the i.ortho.elev generated file
+                #to get the elevation at mapset map name
+                #FIXME
+                elevationmap='elevation at PERMANENT'
+                #Get the elevation height from the map given by i.ortho.elev
+                ret, msg = RunCommand('r.what',
+                                  parent=self,
+                                  getErrorMsg=True,
+                                  quiet=True,
+                                  _map=elevationmap,
+                                  method=self.gr_method,
+                                  flags=flags)
+                self.mapcoordlist[key][6] = ret
+
+            self.pointsToDrawTgt.GetItem(key - 1).SetCoords([coord0, coord1])
+
+        self.list.SetStringItem(index, 7, '0')
+        self.list.SetStringItem(index, 8, '0')
+        self.mapcoordlist[key][7] = 0.0
+        self.mapcoordlist[key][8] = 0.0
+
+        # self.list.ResizeColumns()
+
+    def SaveGCPs(self, event):
+        """Make a POINTS file or save GCP coordinates to existing
+        POINTS file
+        """
+        self.GCPcount = 0
+        try:
+            f = open(self.file['ii2t_points'], mode='w')
+            # use os.linesep or '\n' here ???
+            f.write('# Ground Control Points File\n')
+            f.write("# \n")
+            f.write("# target location: " + self.currentlocation + '\n')
+            f.write("# target mapset: " + self.currentmapset + '\n')
+            f.write("#\tsource\t\t\ttarget\t\t\tstatus\n")
+            f.write("#\teast\tnorth\theight\teast\tnorth\theight\t(1=ok, 0=ignore)\n")
+            f.write(
+                "#----------------------------     ---------------------------     ---------------\n")
+
+            for index in range(self.list.GetItemCount()):
+                if self.list.IsChecked(index) == True:
+                    check = "1"
+                    self.GCPcount += 1
+                else:
+                    check = "0"
+                coord0 = self.list.GetItem(index, 1).GetText()
+                coord1 = self.list.GetItem(index, 2).GetText()
+                coord2 = self.list.GetItem(index, 3).GetText()
+                coord3 = self.list.GetItem(index, 4).GetText()
+                coord4 = self.list.GetItem(index, 5).GetText()
+                coord5 = self.list.GetItem(index, 6).GetText()
+                f.write(
+                    coord0 +
+                    ' ' +
+                    coord1 +
+                    '     ' +
+                    coord2 +
+                    ' ' +
+                    coord3 +
+                    '     ' +
+                    coord4 +
+                    '     ' +
+                    coord5 +
+                    '     ' +
+                    check +
+                    '\n')
+
+        except IOError as err:
+            GError(
+                parent=self,
+                message="%s <%s>. %s%s" %
+                (_("Writing POINTS file failed"),
+                 self.file['ii2t_points'],
+                    os.linesep,
+                    err))
+            return
+
+        f.close()
+
+        # if event != None save also to backup file
+        if event:
+            shutil.copy(self.file['ii2t_points'], self.file['ii2t_points_bak'])
+            self._giface.WriteLog(
+                _('POINTS file saved for group <%s>') %
+                self.xygroup)
+            #self.SetStatusText(_('POINTS file saved'))
+
+    def ReadGCPs(self):
+        """
+        Reads GCPs and georectified coordinates from POINTS file
+        """
+
+        self.GCPcount = 0
+
+        sourceMapWin = self.SrcMapWindow
+        targetMapWin = self.TgtMapWindow
+
+        if not sourceMapWin:
+            GError(parent=self,
+                   message="%s. %s%s" % (_("source mapwin not defined"),
+                                         os.linesep, err))
+
+        if not targetMapWin:
+            GError(parent=self,
+                   message="%s. %s%s" % (_("target mapwin not defined"),
+                                         os.linesep, err))
+
+        try:
+            f = open(self.file['ii2t_points'], 'r')
+            GCPcnt = 0
+
+            for line in f.readlines():
+                if line[0] == '#' or line == '':
+                    continue
+                line = line.replace('\n', '').strip()
+                coords = map(float, line.split())
+                if coords[6] == 1:
+                    check = True
+                    self.GCPcount += 1
+                else:
+                    check = False
+
+                self.AddGCP(event=None)
+                self.SetGCPData('source', (coords[0], coords[1]), sourceMapWin)
+                self.SetGCPData('target', (coords[3], coords[4]), targetMapWin)
+                index = self.list.GetSelected()
+                if index != wx.NOT_FOUND:
+                    self.list.CheckItem(index, check)
+                GCPcnt += 1
+
+        except IOError as err:
+            GError(
+                parent=self,
+                message="%s <%s>. %s%s" %
+                (_("Reading POINTS file failed"),
+                 self.file['ii2t_points'],
+                    os.linesep,
+                    err))
+            return
+
+        f.close()
+
+        if GCPcnt == 0:
+            # 3 gcp is minimum
+            for i in range(3):
+                self.AddGCP(None)
+
+        if self.CheckGCPcount():
+            # calculate RMS
+            self.RMSError(self.xygroup, self.gr_order)
+
+    def ReloadGCPs(self, event):
+        """Reload data from file"""
+
+        # use backup
+        shutil.copy(self.file['ii2t_points_bak'], self.file['ii2t_points'])
+
+        # delete all items in mapcoordlist
+        self.mapcoordlist = []
+        self.mapcoordlist.append([0,        # GCP number
+                                  0.0,      # source east
+                                  0.0,      # source north
+                                  0.0,      # source height
+                                  0.0,      # target east
+                                  0.0,      # target north
+                                  0.0,      # target height
+                                  0.0,      # forward error
+                                  0.0])   # backward error
+
+        self.list.LoadData()
+        self.itemDataMap = self.mapcoordlist
+
+        if self._col != -1:
+            self.list.ClearColumnImage(self._col)
+        self._colSortFlag = [1] * self.list.GetColumnCount()
+
+        # draw GCPs (source and target)
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=False, renderVector=False)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+
+    def OnFocus(self, event):
+        # TODO: it is here just to remove old or obsolate beavior of base class gcp/MapFrame?
+        # self.grwiz.SwitchEnv('source')
+        pass
+
+    def _onMouseLeftUpPointer(self, mapWindow, x, y):
+        if mapWindow == self.SrcMapWindow:
+            coordtype = 'source'
+        else:
+            coordtype = 'target'
+
+        coord = (x, y)
+        self.SetGCPData(coordtype, coord, self, confirm=True)
+        mapWindow.UpdateMap(render=False, renderVector=False)
+
+    def OnRMS(self, event):
+        """
+        RMS button handler
+        """
+        self.RMSError(self.xygroup, self.gr_order)
+
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=False, renderVector=False)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+
+    def CheckGCPcount(self, msg=False):
+        """
+        Checks to make sure that the minimum number of GCPs have been defined and
+        are active for the selected transformation order
+        """
+        if (self.GCPcount < 3 and self.gr_order == 1) or \
+                (self.GCPcount < 6 and self.gr_order == 2) or \
+                (self.GCPcount < 10 and self.gr_order == 3):
+            if msg:
+                GWarning(
+                    parent=self, message=_(
+                        'Insufficient points defined and active (checked) '
+                        'for selected rectification method (order: %d).\n'
+                        '3+ points needed for 1st order,\n'
+                        '6+ points for 2nd order, and\n'
+                        '10+ points for 3rd order.') %
+                    self.gr_order)
+                return False
+        else:
+            return True
+
+    def OnGeorect(self, event):
+        """
+        Georectifies map(s) in group using i.rectify or v.transform
+        """
+        global maptype
+        self.SaveGCPs(None)
+
+        if self.CheckGCPcount(msg=True) == False:
+            return
+
+        if maptype == 'raster':
+            self.grwiz.SwitchEnv('source')
+
+            if self.clip_to_region:
+                flags = "ac"
+            else:
+                flags = "a"
+
+            busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
+                               parent=self)
+            wx.Yield()
+
+            ret, msg = RunCommand('i.rectify',
+                                  parent=self,
+                                  getErrorMsg=True,
+                                  quiet=True,
+                                  group=self.xygroup,
+                                  extension=self.extension,
+                                  order=self.gr_order,
+                                  method=self.gr_method,
+                                  flags=flags)
+
+            busy.Destroy()
+
+            # provide feedback on failure
+            if ret != 0:
+                print >> sys.stderr, msg
+
+        elif maptype == 'vector':
+            # loop through all vectors in VREF
+
+            self.grwiz.SwitchEnv('source')
+
+            # make list of vectors to georectify from VREF
+            f = open(self.file['vgrp'])
+            vectlist = []
+            try:
+                for vect in f.readlines():
+                    vect = vect.strip('\n')
+                    if len(vect) < 1:
+                        continue
+                    vectlist.append(vect)
+            finally:
+                f.close()
+
+            # georectify each vector in VREF using v.rectify
+            for vect in vectlist:
+                self.outname = str(vect.split('@')[0]) + self.extension
+                self._giface.WriteLog(text=_('Transforming <%s>...') % vect,
+                                      notification=Notification.MAKE_VISIBLE)
+                ret = msg = ''
+
+                busy = wx.BusyInfo(
+                    message=_("Rectifying vector map <%s>, please wait...") %
+                    vect, parent=self)
+                wx.Yield()
+
+                ret, msg = RunCommand('v.rectify',
+                                      parent=self,
+                                      getErrorMsg=True,
+                                      quiet=True,
+                                      input=vect,
+                                      output=self.outname,
+                                      group=self.xygroup,
+                                      order=self.gr_order)
+
+                busy.Destroy()
+
+                # provide feedback on failure
+                if ret != 0:
+                    print >> sys.stderr, msg
+
+        self.grwiz.SwitchEnv('target')
+
+    def OnGeorectDone(self, **kargs):
+        """Print final message"""
+        global maptype
+        if maptype == 'raster':
+            return
+
+        returncode = kargs['returncode']
+
+        if returncode == 0:
+            self.VectGRList.append(self.outname)
+            print '*****vector list = ' + str(self.VectGRList)
+        else:
+            self._giface.WriteError(
+                _('Georectification of vector map <%s> failed') %
+                self.outname)
+
+    def OnSettings(self, event):
+        """GCP Manager settings"""
+        dlg = GrSettingsDialog(parent=self, giface=self._giface,
+                               id=wx.ID_ANY, title=_('GCP Manager settings'))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            pass
+
+        dlg.Destroy()
+
+    def UpdateColours(self, srcrender=False, srcrenderVector=False,
+                      tgtrender=False, tgtrenderVector=False):
+        """update colours"""
+        highest_fwd_err = 0.0
+        self.highest_key = 0
+        highest_idx = 0
+
+        for index in range(self.list.GetItemCount()):
+            if self.list.IsChecked(index):
+                key = self.list.GetItemData(index)
+                fwd_err = self.mapcoordlist[key][5]
+
+                if self.highest_only == True:
+                    self.list.SetItemTextColour(index, wx.BLACK)
+                    if highest_fwd_err < fwd_err:
+                        highest_fwd_err = fwd_err
+                        self.highest_key = key
+                        highest_idx = index
+                elif self.rmsthresh > 0:
+                    if (fwd_err > self.rmsthresh):
+                        self.list.SetItemTextColour(index, wx.RED)
+                    else:
+                        self.list.SetItemTextColour(index, wx.BLACK)
+            else:
+                self.list.SetItemTextColour(index, wx.BLACK)
+
+        if self.highest_only and highest_fwd_err > 0.0:
+            self.list.SetItemTextColour(highest_idx, wx.RED)
+
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=srcrender, renderVector=srcrenderVector)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(
+                render=tgtrender,
+                renderVector=tgtrenderVector)
+
+    def OnQuit(self, event):
+        """Quit georectifier"""
+        ret = wx.MessageBox(
+            parent=self, caption=_("Quit GCP Manager"),
+            message=_('Save ground control points?'),
+            style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL | wx.CENTRE)
+
+        if ret != wx.CANCEL:
+            if ret == wx.YES:
+                self.SaveGCPs(None)
+            elif ret == wx.NO:
+                # restore POINTS file from backup
+                if os.path.exists(self.file['ii2t_points_bak']):
+                    shutil.copy(self.file['ii2t_points_bak'], self.file['ii2t_points'])
+
+            if os.path.exists(self.file['ii2t_points_bak']):
+                os.unlink(self.file['ii2t_points_bak'])
+
+            self.SrcMap.Clean()
+            self.TgtMap.Clean()
+
+            self.grwiz.Cleanup()
+
+            self.Destroy()
+
+        # event.Skip()
+
+    def OnGROrder(self, event):
+        """
+        sets transformation order for georectifying
+        """
+        if event:
+            self.gr_order = event.GetInt() + 1
+
+        numOfItems = self.list.GetItemCount()
+        minNumOfItems = numOfItems
+
+        if self.gr_order == 1:
+            minNumOfItems = 3
+            # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order'))
+
+        elif self.gr_order == 2:
+            minNumOfItems = 6
+            diff = 6 - numOfItems
+            # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order'))
+
+        elif self.gr_order == 3:
+            minNumOfItems = 10
+            # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order'))
+
+        for i in range(minNumOfItems - numOfItems):
+            self.AddGCP(None)
+
+        return minNumOfItems
+
+    def RMSError(self, xygroup, order):
+        """
+        Uses i.ortho.transform to calculate forward and backward error for each used GCP
+        in POINTS file and insert error values into GCP list.
+        Calculates total forward and backward RMS error for all used points
+        """
+        # save GCPs to points file to make sure that all checked GCPs are used
+        self.SaveGCPs(None)
+        # self.SetStatusText('')
+
+        if self.CheckGCPcount(msg=True) == False:
+            return
+
+        # get list of forward and reverse rms error values for each point
+        self.grwiz.SwitchEnv('source')
+
+        ret = RunCommand('i.ortho.transform',
+                         parent=self,
+                         read=True,
+                         group=xygroup)
+
+        self.grwiz.SwitchEnv('target')
+
+        if ret:
+            errlist = ret.splitlines()
+        else:
+            GError(parent=self,
+                   message=_('Could not calculate RMS Error.\n'
+                             'Possible error with i.ortho.transform.'))
+            return
+
+        # insert error values into GCP list for checked items
+        sdfactor = float(
+            UserSettings.Get(
+                group='gcpman',
+                key='rms',
+                subkey='sdfactor'))
+        GCPcount = 0
+        sumsq_fwd_err = 0.0
+        sumsq_bkw_err = 0.0
+        sum_fwd_err = 0.0
+        highest_fwd_err = 0.0
+        self.highest_key = 0
+        highest_idx = 0
+
+        for index in range(self.list.GetItemCount()):
+            key = self.list.GetItemData(index)
+            if self.list.IsChecked(index):
+                fwd_err, bkw_err = errlist[GCPcount].split()
+                self.list.SetStringItem(index, 7, fwd_err)
+                self.list.SetStringItem(index, 8, bkw_err)
+                self.mapcoordlist[key][7] = float(fwd_err)
+                self.mapcoordlist[key][8] = float(bkw_err)
+                self.list.SetItemTextColour(index, wx.BLACK)
+                if self.highest_only:
+                    if highest_fwd_err < float(fwd_err):
+                        highest_fwd_err = float(fwd_err)
+                        self.highest_key = key
+                        highest_idx = index
+
+                sumsq_fwd_err += float(fwd_err)**2
+                sumsq_bkw_err += float(bkw_err)**2
+                sum_fwd_err += float(fwd_err)
+                GCPcount += 1
+            else:
+                self.list.SetStringItem(index, 7, '')
+                self.list.SetStringItem(index, 8, '')
+                self.mapcoordlist[key][7] = 0.0
+                self.mapcoordlist[key][8] = 0.0
+                self.list.SetItemTextColour(index, wx.BLACK)
+
+        # SD
+        if GCPcount > 0:
+            self.rmsmean = sum_fwd_err / GCPcount
+            self.rmssd = ((sumsq_fwd_err - self.rmsmean**2)**0.5)
+            self.rmsthresh = self.rmsmean + sdfactor * self.rmssd
+        else:
+            self.rmsthresh = 0
+            self.rmsmean = 0
+            self.rmssd = 0
+
+        if self.highest_only and highest_fwd_err > 0.0:
+            self.list.SetItemTextColour(highest_idx, wx.RED)
+        elif GCPcount > 0 and self.rmsthresh > 0 and not self.highest_only:
+            for index in range(self.list.GetItemCount()):
+                if self.list.IsChecked(index):
+                    key = self.list.GetItemData(index)
+                    if (self.mapcoordlist[key][7] > self.rmsthresh):
+                        self.list.SetItemTextColour(index, wx.RED)
+
+        # calculate global RMS error (geometric mean)
+        self.fwd_rmserror = round((sumsq_fwd_err / GCPcount)**0.5, 4)
+        self.bkw_rmserror = round((sumsq_bkw_err / GCPcount)**0.5, 4)
+        self.list.ResizeColumns()
+
+    def GetNewExtent(self, region, map=None):
+
+        coord_file = utils.GetTempfile()
+        newreg = {'n': 0.0, 's': 0.0, 'e': 0.0, 'w': 0.0, }
+
+        try:
+            f = open(coord_file, mode='w')
+            # NW corner
+            f.write(str(region['e']) + " " + str(region['n']) + "\n")
+            # NE corner
+            f.write(str(region['e']) + " " + str(region['s']) + "\n")
+            # SW corner
+            f.write(str(region['w']) + " " + str(region['n']) + "\n")
+            # SE corner
+            f.write(str(region['w']) + " " + str(region['s']) + "\n")
+        finally:
+            f.close()
+
+        # save GCPs to points file to make sure that all checked GCPs are used
+        self.SaveGCPs(None)
+
+        order = self.gr_order
+        self.gr_order = 1
+
+        if self.CheckGCPcount(msg=True) == False:
+            self.gr_order = order
+            return
+
+        self.gr_order = order
+
+        # get list of forward and reverse rms error values for each point
+        self.grwiz.SwitchEnv('source')
+
+        if map == 'source':
+            ret = RunCommand('i.ortho.transform',
+                             parent=self,
+                             read=True,
+                             group=self.xygroup,
+                             format='dst',
+                             coords=coord_file)
+
+        elif map == 'target':
+            ret = RunCommand('i.ortho.transform',
+                             parent=self,
+                             read=True,
+                             group=self.xygroup,
+                             flags='r',
+                             format='src',
+                             coords=coord_file)
+
+        os.unlink(coord_file)
+
+        self.grwiz.SwitchEnv('target')
+
+        if ret:
+            errlist = ret.splitlines()
+        else:
+            GError(parent=self,
+                   message=_('Could not calculate new extends.\n'
+                             'Possible error with i.ortho.transform.'))
+            return
+
+        # fist corner
+        e, n = errlist[0].split()
+        fe = float(e)
+        fn = float(n)
+        newreg['n'] = fn
+        newreg['s'] = fn
+        newreg['e'] = fe
+        newreg['w'] = fe
+        # other three corners
+        for i in range(1, 4):
+            e, n = errlist[i].split()
+            fe = float(e)
+            fn = float(n)
+            if fe < newreg['w']:
+                newreg['w'] = fe
+            if fe > newreg['e']:
+                newreg['e'] = fe
+            if fn < newreg['s']:
+                newreg['s'] = fn
+            if fn > newreg['n']:
+                newreg['n'] = fn
+
+        return newreg
+
+    def OnHelp(self, event):
+        """Show GCP Manager manual page"""
+        self._giface.Help(entry='wxGUI.gcp')
+
+    def OnUpdateActive(self, event):
+
+        if self.activemap.GetSelection() == 0:
+            self.MapWindow = self.SrcMapWindow
+            self.Map = self.SrcMap
+        else:
+            self.MapWindow = self.TgtMapWindow
+            self.Map = self.TgtMap
+
+        self.UpdateActive(self.MapWindow)
+        # for wingrass
+        if os.name == 'nt':
+            self.MapWindow.SetFocus()
+
+    def UpdateActive(self, win):
+
+        # optionally disable tool zoomback tool
+        self.GetMapToolbar().Enable('zoomback',
+                                    enable=(len(self.MapWindow.zoomhistory) > 1))
+
+        if self.activemap.GetSelection() != (win == self.TgtMapWindow):
+            self.activemap.SetSelection(win == self.TgtMapWindow)
+        self.StatusbarUpdate()
+
+    def AdjustMap(self, newreg):
+        """Adjust map window to new extents
+        """
+
+        # adjust map window
+        self.Map.region['n'] = newreg['n']
+        self.Map.region['s'] = newreg['s']
+        self.Map.region['e'] = newreg['e']
+        self.Map.region['w'] = newreg['w']
+
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                                   self.Map.region['e'], self.Map.region['w'])
+
+        # LL locations
+        if self.Map.projinfo['proj'] == 'll':
+            if newreg['n'] > 90.0:
+                newreg['n'] = 90.0
+            if newreg['s'] < -90.0:
+                newreg['s'] = -90.0
+
+        ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
+        cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
+
+        # calculate new center point and display resolution
+        self.Map.region['center_easting'] = ce
+        self.Map.region['center_northing'] = cn
+        self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
+        self.Map.region["nsres"] = (
+            newreg['n'] - newreg['s']) / self.Map.height
+        self.Map.AlignExtentFromDisplay()
+
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                                   self.Map.region['e'], self.Map.region['w'])
+
+        if self.MapWindow.redrawAll is False:
+            self.MapWindow.redrawAll = True
+
+        self.MapWindow.UpdateMap()
+        self.StatusbarUpdate()
+
+    def OnZoomToSource(self, event):
+        """Set target map window to match extents of source map window
+        """
+
+        if not self.MapWindow == self.TgtMapWindow:
+            self.MapWindow = self.TgtMapWindow
+            self.Map = self.TgtMap
+            self.UpdateActive(self.TgtMapWindow)
+
+        # get new N, S, E, W for target
+        newreg = self.GetNewExtent(self.SrcMap.region, 'source')
+        if newreg:
+            self.AdjustMap(newreg)
+
+    def OnZoomToTarget(self, event):
+        """Set source map window to match extents of target map window
+        """
+
+        if not self.MapWindow == self.SrcMapWindow:
+            self.MapWindow = self.SrcMapWindow
+            self.Map = self.SrcMap
+            self.UpdateActive(self.SrcMapWindow)
+
+        # get new N, S, E, W for target
+        newreg = self.GetNewExtent(self.TgtMap.region, 'target')
+        if newreg:
+            self.AdjustMap(newreg)
+
+    def OnZoomMenuGCP(self, event):
+        """Popup Zoom menu
+        """
+        point = wx.GetMousePosition()
+        zoommenu = wx.Menu()
+        # Add items to the menu
+
+        zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+            'Adjust source display to target display'))
+        zoommenu.AppendItem(zoomsource)
+        self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
+
+        zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+            'Adjust target display to source display'))
+        zoommenu.AppendItem(zoomtarget)
+        self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
+
+        # Popup the menu. If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(zoommenu)
+        zoommenu.Destroy()
+
+    def OnSize(self, event):
+        """Adjust Map Windows after GCP Map Display has been resized
+        """
+        # re-render image on idle
+        self.resize = time.clock()
+        super(MapFrame, self).OnSize(event)
+
+    def OnIdle(self, event):
+        """GCP Map Display resized, adjust Map Windows
+        """
+        if self.GetMapToolbar():
+            if self.resize and self.resize + 0.2 < time.clock():
+                srcwidth, srcheight = self.SrcMapWindow.GetSize()
+                tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+                srcwidth = (srcwidth + tgtwidth) / 2
+                if self.show_target:
+                    self._mgr.GetPane("target").Hide()
+                    self._mgr.Update()
+                self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+                self._mgr.GetPane("target").BestSize((srcwidth, tgtheight))
+                if self.show_target:
+                    self._mgr.GetPane("target").Show()
+                self._mgr.Update()
+                self.resize = False
+            elif self.resize:
+                event.RequestMore()
+        pass
+
+
+class GCPList(wx.ListCtrl,
+              CheckListCtrlMixin,
+              ListCtrlAutoWidthMixin):
+
+    def __init__(self, parent, gcp, id=wx.ID_ANY,
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_HRULES |
+                 wx.LC_SINGLE_SEL):
+
+        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
+
+        self.gcp = gcp  # GCP class
+        self.render = True
+
+        # Mixin settings
+        CheckListCtrlMixin.__init__(self)
+        ListCtrlAutoWidthMixin.__init__(self)
+        # TextEditMixin.__init__(self)
+
+        # tracks whether list items are checked or not
+        self.CheckList = []
+
+        self._Create()
+
+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
+        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
+
+        self.selected = wx.NOT_FOUND
+        self.selectedkey = -1
+
+    def _Create(self):
+
+        if 0:
+            # normal, simple columns
+            idx_col = 0
+            for col in (_('use'),
+                        _('source E'),
+                        _('source N'),
+                        _('source Z'),
+                        _('target E'),
+                        _('target N'),
+                        _('target Z'),
+                        _('Forward error'),
+                        _('Backward error')):
+                self.InsertColumn(idx_col, col)
+                idx_col += 1
+        else:
+            # the hard way: we want images on the column header
+            info = wx.ListItem()
+            info.SetMask(
+                wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT)
+            info.SetImage(-1)
+            info.m_format = wx.LIST_FORMAT_LEFT
+
+            idx_col = 0
+            for lbl in (_('use'),
+                        _('source E'),
+                        _('source N'),
+                        _('source Z'),
+                        _('target E'),
+                        _('target N'),
+                        _('target Z'),
+                        _('Forward error'),
+                        _('Backward error')):
+                info.SetText(lbl)
+                self.InsertColumnInfo(idx_col, info)
+                idx_col += 1
+
+    def LoadData(self):
+        """Load data into list"""
+        self.DeleteAllItems()
+
+        self.render = False
+        if os.path.isfile(self.gcp.file['ii2t_points']):
+            self.gcp.ReadGCPs()
+        else:
+            # 3 gcp is minimum
+            for i in range(3):
+                self.gcp.AddGCP(None)
+
+        # select first point by default
+        self.selected = 0
+        self.selectedkey = self.GetItemData(self.selected)
+        self.SetItemState(self.selected,
+                          wx.LIST_STATE_SELECTED,
+                          wx.LIST_STATE_SELECTED)
+
+        self.ResizeColumns()
+        self.render = True
+
+        self.EnsureVisible(self.selected)
+
+    def OnCheckItem(self, index, flag):
+        """Item is checked/unchecked"""
+
+        if self.render:
+            # redraw points
+            sourceMapWin = self.gcp.SrcMapWindow
+            sourceMapWin.UpdateMap(render=False, renderVector=False)
+            if self.gcp.show_target:
+                targetMapWin = self.gcp.TgtMapWindow
+                targetMapWin.UpdateMap(render=False, renderVector=False)
+
+    def AddGCPItem(self):
+        """
+        Appends an item to GCP list
+        """
+        self.selectedkey = self.GetItemCount() + 1
+
+        self.Append([str(self.selectedkey),    # GCP number
+                     '0.0',                # source E
+                     '0.0',                # source N
+                     '0.0',                # source Z
+                     '0.0',                # target E
+                     '0.0',                # target N
+                     '0.0',                # target Z
+                     '',                   # forward error
+                     ''])                  # backward error
+
+        self.selected = self.GetItemCount() - 1
+        self.SetItemData(self.selected, self.selectedkey)
+
+        self.SetItemState(self.selected,
+                          wx.LIST_STATE_SELECTED,
+                          wx.LIST_STATE_SELECTED)
+
+        self.ResizeColumns()
+
+        self.gcp.pointsToDrawSrc.AddItem(
+            coords=[0, 0], label=str(self.selectedkey))
+        self.gcp.pointsToDrawTgt.AddItem(
+            coords=[0, 0], label=str(self.selectedkey))
+
+        self.EnsureVisible(self.selected)
+
+        return self.selected
+
+    def DeleteGCPItem(self):
+        """Deletes selected item in GCP list.
+        """
+        if self.selected == wx.NOT_FOUND:
+            return
+
+        key = self.GetItemData(self.selected)
+        self.DeleteItem(self.selected)
+
+        if self.selected != wx.NOT_FOUND:
+            item = self.gcp.pointsToDrawSrc.GetItem(key - 1)
+            self.gcp.pointsToDrawSrc.DeleteItem(item)
+
+            item = self.gcp.pointsToDrawTgt.GetItem(key - 1)
+            self.gcp.pointsToDrawTgt.DeleteItem(item)
+
+        return key
+
+    def ResizeColumns(self):
+        """Resize columns"""
+        minWidth = [90, 120]
+        for i in range(self.GetColumnCount()):
+            self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
+            # first column is checkbox, don't set to minWidth
+            if i > 0 and self.GetColumnWidth(i) < minWidth[i > 4]:
+                self.SetColumnWidth(i, minWidth[i > 4])
+
+        self.SendSizeEvent()
+
+    def GetSelected(self):
+        """Get index of selected item"""
+        return self.selected
+
+    def OnItemSelected(self, event):
+        """Item selected
+        """
+        if self.render and self.selected != event.GetIndex():
+            self.selected = event.GetIndex()
+            self.selectedkey = self.GetItemData(self.selected)
+            sourceMapWin = self.gcp.SrcMapWindow
+            sourceMapWin.UpdateMap(render=False, renderVector=False)
+            if self.gcp.show_target:
+                targetMapWin = self.gcp.TgtMapWindow
+                targetMapWin.UpdateMap(render=False, renderVector=False)
+        event.Skip()
+
+    def OnItemActivated(self, event):
+        """
+        When item double clicked, open editor to update coordinate values
+        """
+        coords = []
+        index = event.GetIndex()
+        key = self.GetItemData(index)
+        changed = False
+
+        for i in range(1, 7):
+            coords.append(self.GetItem(index, i).GetText())
+
+        dlg = EditGCP(parent=self, id=wx.ID_ANY, data=coords, gcpno=key)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            values = dlg.GetValues()  # string
+
+            if len(values) == 0:
+                GError(parent=self, message=_(
+                    "Invalid coordinate value. Operation canceled."))
+            else:
+                for i in range(len(values)):
+                    if values[i] != coords[i]:
+                        self.SetStringItem(index, i + 1, values[i])
+                        changed = True
+
+                if changed:
+                    # reset RMS and update mapcoordlist
+                    self.SetStringItem(index, 7, '')
+                    self.SetStringItem(index, 8, '')
+                    key = self.GetItemData(index)
+                    self.gcp.mapcoordlist[key] = [key,
+                                                  float(values[0]),
+                                                  float(values[1]),
+                                                  float(values[2]),
+                                                  float(values[3]),
+                                                  float(values[4]),
+                                                  float(values[5]),
+                                                  0.0,
+                                                  0.0]
+
+                    self.gcp.pointsToDrawSrc.GetItem(
+                        key - 1).SetCoords([float(values[0]), float(values[1])])
+                    self.gcp.pointsToDrawTgt.GetItem(
+                        key - 1).SetCoords([float(values[3]), float(values[4])])
+                    self.gcp.UpdateColours()
+
+    def OnColClick(self, event):
+        """ListCtrl forgets selected item..."""
+        self.selected = self.FindItemData(-1, self.selectedkey)
+        self.SetItemState(self.selected,
+                          wx.LIST_STATE_SELECTED,
+                          wx.LIST_STATE_SELECTED)
+
+        event.Skip()
+
+
+class VectGroup(wx.Dialog):
+    """Dialog to create a vector group (VREF file) for georectifying
+
+    .. todo::
+        Replace by g.group
+    """
+
+    def __init__(self, parent, id, grassdb, location, mapset, group,
+                 style=wx.DEFAULT_DIALOG_STYLE):
+
+        wx.Dialog.__init__(self, parent, id, style=style,
+                           title=_("Create vector map group"))
+
+        self.grassdatabase = grassdb
+        self.xylocation = location
+        self.xymapset = mapset
+        self.xygroup = group
+
+        #
+        # get list of valid vector directories
+        #
+        vectlist = os.listdir(os.path.join(self.grassdatabase,
+                                           self.xylocation,
+                                           self.xymapset,
+                                           'vector'))
+        for dir in vectlist:
+            if not os.path.isfile(os.path.join(self.grassdatabase,
+                                               self.xylocation,
+                                               self.xymapset,
+                                               'vector',
+                                               dir,
+                                               'coor')):
+                vectlist.remove(dir)
+
+        utils.ListSortLower(vectlist)
+
+        # path to vref file
+        self.vgrpfile = os.path.join(self.grassdatabase,
+                                     self.xylocation,
+                                     self.xymapset,
+                                     'group',
+                                     self.xygroup,
+                                     'VREF')
+
+        #
+        # buttons
+        #
+        self.btnCancel = wx.Button(parent=self,
+                                   id=wx.ID_CANCEL)
+        self.btnOK = wx.Button(parent=self,
+                               id=wx.ID_OK)
+        self.btnOK.SetDefault()
+
+        #
+        # list of vector maps
+        #
+        self.listMap = wx.CheckListBox(parent=self, id=wx.ID_ANY,
+                                       choices=vectlist)
+
+        if os.path.isfile(self.vgrpfile):
+            f = open(self.vgrpfile)
+            try:
+                checked = []
+                for line in f.readlines():
+                    line = line.replace('\n', '')
+                    if len(line) < 1:
+                        continue
+                    checked.append(line)
+                self.listMap.SetCheckedStrings(checked)
+            finally:
+                f.close()
+
+        line = wx.StaticLine(parent=self,
+                             id=wx.ID_ANY, size=(20, -1),
+                             style=wx.LI_HORIZONTAL)
+
+        #
+        # layout
+        #
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        box.Add(
+            wx.StaticText(
+                parent=self,
+                id=wx.ID_ANY,
+                label=_('Select vector map(s) to add to group:')),
+            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
+            border=5)
+
+        box.Add(self.listMap,
+                flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
+                border=5)
+
+        sizer.Add(box, flag=wx.ALIGN_RIGHT | wx.ALL,
+                  border=3)
+
+        sizer.Add(line, proportion=0,
+                  flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+                  border=5)
+
+        # buttons
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOK)
+        btnSizer.Realize()
+
+        sizer.Add(btnSizer, proportion=0,
+                  flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER,
+                  border=5)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+        self.Layout()
+
+    def MakeVGroup(self):
+        """Create VREF file"""
+        vgrouplist = []
+        for item in range(self.listMap.GetCount()):
+            if not self.listMap.IsChecked(item):
+                continue
+            vgrouplist.append(
+                self.listMap.GetString(item) +
+                '@' +
+                self.xymapset)
+
+        f = open(self.vgrpfile, mode='w')
+        try:
+            for vect in vgrouplist:
+                f.write(vect + '\n')
+        finally:
+            f.close()
+
+
+class EditGCP(wx.Dialog):
+
+    def __init__(self, parent, data, gcpno, id=wx.ID_ANY,
+                 title=_("Edit GCP"),
+                 style=wx.DEFAULT_DIALOG_STYLE):
+        """Dialog for editing GPC and map coordinates in list control"""
+
+        wx.Dialog.__init__(self, parent, id, title=title, style=style)
+
+        panel = wx.Panel(parent=self)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.StaticBox(
+            parent=panel, id=wx.ID_ANY, label=" %s %s " %
+            (_("Ground Control Point No."), str(gcpno)))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        # source coordinates
+        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+        #YANN TODO update z and h from i.ortho.elevation selected map
+        self.xcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+        self.ycoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+        self.zcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+        self.ecoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+        self.ncoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+        self.hcoord = wx.TextCtrl(parent=panel, id=wx.ID_ANY, size=(150, -1))
+
+        # swap source N, target E
+        tmp_coord = data[1]
+        data[1] = data[2]
+        data[2] = tmp_coord
+
+        row = 0
+        col = 0
+        idx = 0
+        for label, win in ((_("source E:"), self.xcoord),
+                           (_("target E:"), self.ecoord),
+                           (_("source N:"), self.ycoord),
+                           (_("target N:"), self.ncoord),
+                           (_("source Z:"), self.zcoord),
+                           (_("target Z:"), self.hcoord)):
+            label = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                  label=label)
+            gridSizer.Add(label,
+                          flag=wx.ALIGN_CENTER_VERTICAL,
+                          pos=(row, col))
+
+            col += 1
+            win.SetValue(str(data[idx]))
+
+            gridSizer.Add(win,
+                          pos=(row, col))
+
+            col += 1
+            idx += 1
+
+            if col > 3:
+                row += 1
+                col = 0
+
+        boxSizer.Add(gridSizer, proportion=1,
+                     flag=wx.EXPAND | wx.ALL, border=5)
+
+        sizer.Add(boxSizer, proportion=1,
+                  flag=wx.EXPAND | wx.ALL, border=5)
+
+        #
+        # buttons
+        #
+        self.btnCancel = wx.Button(panel, wx.ID_CANCEL)
+        self.btnOk = wx.Button(panel, wx.ID_OK)
+        self.btnOk.SetDefault()
+
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+
+        sizer.Add(btnSizer, proportion=0,
+                  flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
+
+        panel.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def GetValues(self, columns=None):
+        """Return list of values (as strings).
+        """
+        valuelist = []
+        try:
+            float(self.xcoord.GetValue())
+            float(self.ycoord.GetValue())
+            float(self.zcoord.GetValue())
+            float(self.ecoord.GetValue())
+            float(self.ncoord.GetValue())
+            float(self.hcoord.GetValue())
+        except ValueError:
+            return valuelist
+
+        valuelist.append(self.xcoord.GetValue())
+        valuelist.append(self.ycoord.GetValue())
+        valuelist.append(self.zcoord.GetValue())
+        valuelist.append(self.ecoord.GetValue())
+        valuelist.append(self.ncoord.GetValue())
+        valuelist.append(self.hcoord.GetValue())
+
+        return valuelist
+
+
+class GrSettingsDialog(wx.Dialog):
+
+    def __init__(
+            self, parent, id, giface, title, pos=wx.DefaultPosition,
+            size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE):
+        wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+        """
+        Dialog to set profile text options: font, title
+        and font size, axis labels and font size
+        """
+        #
+        # initialize variables
+        #
+        self.parent = parent
+        self.new_src_map = src_map
+        self.new_tgt_map = {'raster': tgt_map['raster'],
+                            'vector': tgt_map['vector']}
+        self.sdfactor = 0
+
+        self.symbol = {}
+
+        self.methods = ["nearest",
+                        "linear",
+                        "linear_f",
+                        "cubic",
+                        "cubic_f",
+                        "lanczos",
+                        "lanczos_f"]
+
+        # notebook
+        notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
+        self.__CreateSymbologyPage(notebook)
+        self.__CreateRectificationPage(notebook)
+
+        # buttons
+        btnSave = wx.Button(self, wx.ID_SAVE)
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnClose = wx.Button(self, wx.ID_CLOSE)
+        btnApply.SetDefault()
+
+        # bindings
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnApply.SetToolTipString(_("Apply changes for the current session"))
+        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        btnSave.SetToolTipString(
+            _("Apply and save changes to user settings file (default for next sessions)"))
+        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
+        btnClose.SetToolTipString(_("Close dialog"))
+
+        # sizers
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
+
+        # sizers
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(
+            notebook,
+            proportion=1,
+            flag=wx.EXPAND | wx.ALL,
+            border=5)
+        mainSizer.Add(btnSizer, proportion=0,
+                      flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
+        #              flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+    def __CreateSymbologyPage(self, notebook):
+        """Create notebook page with symbology settings"""
+
+        panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
+        notebook.AddPage(page=panel, text=_("Symbology"))
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        rmsgridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+
+        # highlight only highest forward RMS error
+        self.highlighthighest = wx.CheckBox(
+            parent=panel, id=wx.ID_ANY,
+            label=_("Highlight highest RMS error only"))
+        hh = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
+        self.highlighthighest.SetValue(hh)
+        rmsgridSizer.Add(
+            self.highlighthighest,
+            flag=wx.ALIGN_CENTER_VERTICAL,
+            pos=(
+                0,
+                0))
+
+        # RMS forward error threshold
+        rmslabel = wx.StaticText(
+            parent=panel, id=wx.ID_ANY,
+            label=_("Highlight RMS error > M + SD * factor:"))
+        rmslabel.SetToolTip(
+            wx.ToolTip(
+                _(
+                    "Highlight GCPs with an RMS error larger than \n"
+                    "mean + standard deviation * given factor. \n"
+                    "Recommended values for this factor are between 1 and 2.")))
+        rmsgridSizer.Add(
+            rmslabel,
+            flag=wx.ALIGN_CENTER_VERTICAL,
+            pos=(
+                1,
+                0))
+        sdfactor = UserSettings.Get(
+            group='gcpman', key='rms', subkey='sdfactor')
+        self.rmsWin = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
+                                  size=(70, -1), style=wx.TE_NOHIDESEL)
+        self.rmsWin.SetValue("%s" % str(sdfactor))
+        if (self.parent.highest_only == True):
+            self.rmsWin.Disable()
+
+        self.symbol['sdfactor'] = self.rmsWin.GetId()
+        rmsgridSizer.Add(self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
+        rmsgridSizer.AddGrowableCol(1)
+        sizer.Add(rmsgridSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+        box = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                           label=" %s " % _("Symbol settings"))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+
+        #
+        # general symbol color
+        #
+        row = 0
+        label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
+        colWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+                                   colour=wx.Colour(col[0],
+                                                    col[1],
+                                                    col[2],
+                                                    255))
+        self.symbol['color'] = colWin.GetId()
+        gridSizer.Add(colWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+
+        #
+        # symbol color for high forward RMS error
+        #
+        row += 1
+        label = wx.StaticText(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=_("Color for high RMS error:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        hcol = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
+        hcolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+                                    colour=wx.Colour(hcol[0],
+                                                     hcol[1],
+                                                     hcol[2],
+                                                     255))
+        self.symbol['hcolor'] = hcolWin.GetId()
+        gridSizer.Add(hcolWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+
+        #
+        # symbol color for selected GCP
+        #
+        row += 1
+        label = wx.StaticText(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=_("Color for selected GCP:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        scol = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
+        scolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+                                    colour=wx.Colour(scol[0],
+                                                     scol[1],
+                                                     scol[2],
+                                                     255))
+        self.symbol['scolor'] = scolWin.GetId()
+        gridSizer.Add(scolWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+
+        #
+        # symbol color for unused GCP
+        #
+        row += 1
+        label = wx.StaticText(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=_("Color for unused GCPs:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        ucol = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
+        ucolWin = csel.ColourSelect(parent=panel, id=wx.ID_ANY,
+                                    colour=wx.Colour(ucol[0],
+                                                     ucol[1],
+                                                     ucol[2],
+                                                     255))
+        self.symbol['ucolor'] = ucolWin.GetId()
+        gridSizer.Add(ucolWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+
+        # show unused GCPs
+        row += 1
+        self.showunused = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+                                      label=_("Show unused GCPs"))
+        shuu = UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
+        self.showunused.SetValue(shuu)
+        gridSizer.Add(
+            self.showunused,
+            flag=wx.ALIGN_CENTER_VERTICAL,
+            pos=(
+                row,
+                0))
+
+        #
+        # symbol size
+        #
+        row += 1
+        label = wx.StaticText(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=_("Symbol size:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        symsize = int(
+            UserSettings.Get(
+                group='gcpman',
+                key='symbol',
+                subkey='size'))
+        sizeWin = SpinCtrl(parent=panel, id=wx.ID_ANY,
+                           min=1, max=20)
+        sizeWin.SetValue(symsize)
+        self.symbol['size'] = sizeWin.GetId()
+        gridSizer.Add(sizeWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+
+        #
+        # symbol width
+        #
+        row += 1
+        label = wx.StaticText(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=_("Line width:"))
+        gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        width = int(
+            UserSettings.Get(
+                group='gcpman',
+                key='symbol',
+                subkey='width'))
+        widWin = SpinCtrl(parent=panel, id=wx.ID_ANY,
+                          min=1, max=10)
+        widWin.SetValue(width)
+        self.symbol['width'] = widWin.GetId()
+        gridSizer.Add(widWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+        gridSizer.AddGrowableCol(1)
+
+        boxSizer.Add(gridSizer, flag=wx.EXPAND)
+        sizer.Add(boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+        #
+        # maps to display
+        #
+        # source map to display
+        self.srcselection = Select(
+            panel,
+            id=wx.ID_ANY,
+            size=globalvar.DIALOG_GSELECT_SIZE,
+            type='maptype',
+            updateOnPopup=False)
+        self.parent.grwiz.SwitchEnv('source')
+        self.srcselection.SetElementList(maptype)
+        # filter out all maps not in group
+        self.srcselection.tcp.GetElementList(elements=self.parent.src_maps)
+
+        # target map(s) to display
+        self.parent.grwiz.SwitchEnv('target')
+        self.tgtrastselection = Select(
+            panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+            type='raster', updateOnPopup=False)
+        self.tgtrastselection.SetElementList('cell')
+        self.tgtrastselection.GetElementList()
+
+        self.tgtvectselection = Select(
+            panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+            type='vector', updateOnPopup=False)
+        self.tgtvectselection.SetElementList('vector')
+        self.tgtvectselection.GetElementList()
+
+        sizer.Add(
+            wx.StaticText(
+                parent=panel,
+                id=wx.ID_ANY,
+                label=_('Select source map to display:')),
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        sizer.Add(
+            self.srcselection,
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        self.srcselection.SetValue(src_map)
+        sizer.Add(
+            wx.StaticText(
+                parent=panel,
+                id=wx.ID_ANY,
+                label=_('Select target raster map to display:')),
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        sizer.Add(
+            self.tgtrastselection,
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        self.tgtrastselection.SetValue(tgt_map['raster'])
+        sizer.Add(
+            wx.StaticText(
+                parent=panel,
+                id=wx.ID_ANY,
+                label=_('Select target vector map to display:')),
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        sizer.Add(
+            self.tgtvectselection,
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        self.tgtvectselection.SetValue(tgt_map['vector'])
+
+        # bindings
+        self.highlighthighest.Bind(wx.EVT_CHECKBOX, self.OnHighlight)
+        self.rmsWin.Bind(wx.EVT_TEXT, self.OnSDFactor)
+        self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
+        self.tgtrastselection.Bind(wx.EVT_TEXT, self.OnTgtRastSelection)
+        self.tgtvectselection.Bind(wx.EVT_TEXT, self.OnTgtVectSelection)
+
+        panel.SetSizer(sizer)
+
+        return panel
+
+    def __CreateRectificationPage(self, notebook):
+        """Create notebook page with symbology settings"""
+
+        panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
+        notebook.AddPage(page=panel, text=_("Rectification"))
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        # transformation order
+        self.rb_grorder = wx.RadioBox(
+            parent=panel,
+            id=wx.ID_ANY,
+            label=" %s " %
+            _("Select rectification order"),
+            choices=[
+                _('1st order'),
+                _('2nd order'),
+                _('3rd order')],
+            majorDimension=wx.RA_SPECIFY_COLS)
+        sizer.Add(self.rb_grorder, proportion=0,
+                  flag=wx.EXPAND | wx.ALL, border=5)
+        self.rb_grorder.SetSelection(self.parent.gr_order - 1)
+
+        # interpolation method
+        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+        gridSizer.Add(
+            wx.StaticText(
+                parent=panel,
+                id=wx.ID_ANY,
+                label=_('Select interpolation method:')),
+            pos=(
+                0,
+                0),
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
+                                  choices=self.methods)
+        gridSizer.Add(self.grmethod, pos=(0, 1),
+                      flag=wx.ALIGN_RIGHT, border=5)
+        self.grmethod.SetStringSelection(self.parent.gr_method)
+        gridSizer.AddGrowableCol(1)
+        sizer.Add(gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+        # clip to region
+        self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=_(
+            "clip to computational region in target location"))
+        sizer.Add(self.check, proportion=0,
+                  flag=wx.EXPAND | wx.ALL, border=5)
+        self.check.SetValue(self.parent.clip_to_region)
+
+        # extension
+        sizer.Add(
+            wx.StaticText(
+                parent=panel,
+                id=wx.ID_ANY,
+                label=_('Extension for output maps:')),
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+        self.ext_txt = wx.TextCtrl(
+            parent=panel, id=wx.ID_ANY, value="", size=(
+                350, -1))
+        self.ext_txt.SetValue(self.parent.extension)
+        sizer.Add(
+            self.ext_txt,
+            proportion=0,
+            flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+            border=5)
+
+        # bindings
+        self.ext_txt.Bind(wx.EVT_TEXT, self.OnExtension)
+        self.Bind(wx.EVT_RADIOBOX, self.parent.OnGROrder, self.rb_grorder)
+        self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
+        self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
+
+        panel.SetSizer(sizer)
+
+        return panel
+
+    def OnHighlight(self, event):
+        """Checkbox 'highlighthighest' checked/unchecked"""
+        if self.highlighthighest.IsChecked():
+            self.parent.highest_only = True
+            self.rmsWin.Disable()
+        else:
+            self.parent.highest_only = False
+            self.rmsWin.Enable()
+
+    def OnSDFactor(self, event):
+        """New factor for RMS threshold = M + SD * factor"""
+        try:
+            self.sdfactor = float(self.rmsWin.GetValue())
+        except ValueError:
+            return
+        if self.sdfactor <= 0:
+            GError(parent=self,
+                   message=_('RMS threshold factor must be > 0'))
+        elif self.sdfactor < 1:
+            GError(parent=self,
+                   message=_('RMS threshold factor is < 1\n'
+                             'Too many points might be highlighted'))
+
+    def OnSrcSelection(self, event):
+        """Source map to display selected"""
+        global src_map
+
+        tmp_map = self.srcselection.GetValue()
+
+        if not tmp_map == '' and not tmp_map == src_map:
+            self.new_src_map = tmp_map
+
+    def OnTgtRastSelection(self, event):
+        """Target map to display selected"""
+        global tgt_map
+
+        self.new_tgt_map['raster'] = self.tgtrastselection.GetValue()
+
+    def OnTgtVectSelection(self, event):
+        """Target map to display selected"""
+        global tgt_map
+
+        self.new_tgt_map['vector'] = self.tgtvectselection.GetValue()
+
+    def OnMethod(self, event):
+        self.parent.gr_method = self.methods[event.GetSelection()]
+
+    def OnClipRegion(self, event):
+        self.parent.clip_to_region = event.IsChecked()
+
+    def OnExtension(self, event):
+        self.parent.extension = self.ext_txt.GetValue()
+
+    def UpdateSettings(self):
+        global src_map
+        global tgt_map
+        global maptype
+
+        layers = None
+
+        UserSettings.Set(group='gcpman', key='rms', subkey='highestonly',
+                         value=self.highlighthighest.GetValue())
+
+        if self.sdfactor > 0:
+            UserSettings.Set(group='gcpman', key='rms', subkey='sdfactor',
+                             value=self.sdfactor)
+
+            self.parent.sdfactor = self.sdfactor
+            if self.parent.rmsthresh > 0:
+                self.parent.rmsthresh = self.parent.rmsmean + self.parent.sdfactor * self.parent.rmssd
+
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='color',
+            value=tuple(
+                wx.FindWindowById(
+                    self.symbol['color']).GetColour()))
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='hcolor',
+            value=tuple(
+                wx.FindWindowById(
+                    self.symbol['hcolor']).GetColour()))
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='scolor',
+            value=tuple(
+                wx.FindWindowById(
+                    self.symbol['scolor']).GetColour()))
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='ucolor',
+            value=tuple(
+                wx.FindWindowById(
+                    self.symbol['ucolor']).GetColour()))
+        UserSettings.Set(group='gcpman', key='symbol', subkey='unused',
+                         value=self.showunused.GetValue())
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='size',
+            value=wx.FindWindowById(
+                self.symbol['size']).GetValue())
+        UserSettings.Set(
+            group='gcpman',
+            key='symbol',
+            subkey='width',
+            value=wx.FindWindowById(
+                self.symbol['width']).GetValue())
+
+        srcrender = False
+        srcrenderVector = False
+        tgtrender = False
+        tgtrenderVector = False
+        reload_target = False
+        if self.new_src_map != src_map:
+            # remove old layer
+            layers = self.parent.grwiz.SrcMap.GetListOfLayers()
+            self.parent.grwiz.SrcMap.DeleteLayer(layers[0])
+
+            src_map = self.new_src_map
+            if maptype == 'raster':
+                cmdlist = ['d.rast', 'map=%s' % src_map]
+                srcrender = True
+            else:
+                cmdlist = ['d.vect', 'map=%s' % src_map]
+                srcrenderVector = True
+            self.parent.grwiz.SwitchEnv('source')
+            name, found = utils.GetLayerNameFromCmd(cmdlist)
+            self.parent.grwiz.SrcMap.AddLayer(
+                ltype=maptype, command=cmdlist, active=True, name=name,
+                hidden=False, opacity=1.0, render=False)
+
+            self.parent.grwiz.SwitchEnv('target')
+
+        if self.new_tgt_map['raster'] != tgt_map['raster'] or \
+           self.new_tgt_map['vector'] != tgt_map['vector']:
+            # remove all layers
+            layers = self.parent.grwiz.TgtMap.GetListOfLayers()
+            while layers:
+                self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
+                del layers[0]
+                layers = self.parent.grwiz.TgtMap.GetListOfLayers()
+            # self.parent.grwiz.TgtMap.DeleteAllLayers()
+            reload_target = True
+            tgt_map['raster'] = self.new_tgt_map['raster']
+            tgt_map['vector'] = self.new_tgt_map['vector']
+
+            if tgt_map['raster'] != '':
+                cmdlist = ['d.rast', 'map=%s' % tgt_map['raster']]
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.parent.grwiz.TgtMap.AddLayer(
+                    ltype='raster', command=cmdlist, active=True, name=name,
+                    hidden=False, opacity=1.0, render=False)
+
+                tgtrender = True
+
+            if tgt_map['vector'] != '':
+                cmdlist = ['d.vect', 'map=%s' % tgt_map['vector']]
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.parent.grwiz.TgtMap.AddLayer(
+                    ltype='vector', command=cmdlist, active=True, name=name,
+                    hidden=False, opacity=1.0, render=False)
+
+                tgtrenderVector = True
+
+        if tgt_map['raster'] == '' and tgt_map['vector'] == '':
+            if self.parent.show_target == True:
+                self.parent.show_target = False
+                self.parent._mgr.GetPane("target").Hide()
+                self.parent._mgr.Update()
+                self.parent.activemap.SetSelection(0)
+                self.parent.activemap.Enable(False)
+                self.parent.GetMapToolbar().Enable('zoommenu', enable=False)
+        else:
+            if self.parent.show_target == False:
+                self.parent.show_target = True
+                self.parent._mgr.GetPane("target").Show()
+                self.parent._mgr.Update()
+                self.parent.activemap.SetSelection(0)
+                self.parent.activemap.Enable(True)
+                self.parent.GetMapToolbar().Enable('zoommenu', enable=True)
+                self.parent.TgtMapWindow.ZoomToMap(
+                    layers=self.parent.TgtMap.GetListOfLayers())
+
+        self.parent.UpdateColours(
+            srcrender,
+            srcrenderVector,
+            tgtrender,
+            tgtrenderVector)
+        self.parent.SetSettings()
+
+    def OnSave(self, event):
+        """Button 'Save' pressed"""
+        self.UpdateSettings()
+        fileSettings = {}
+        UserSettings.ReadSettingsFile(settings=fileSettings)
+        fileSettings['gcpman'] = UserSettings.Get(group='gcpman')
+        file = UserSettings.SaveToFile(fileSettings)
+        self.parent._giface.WriteLog(
+            _('GCP Manager settings saved to file \'%s\'.') %
+            file)
+        # self.Close()
+
+    def OnApply(self, event):
+        """Button 'Apply' pressed"""
+        self.UpdateSettings()
+        # self.Close()
+
+    def OnClose(self, event):
+        """Button 'Cancel' pressed"""
+        self.Close()

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_mapdisplay.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_mapdisplay.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_mapdisplay.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,533 @@
+"""
+ at package gcp.mapdisplay
+
+ at brief Display to manage ground control points with two toolbars, one
+for various display management functions, one for manipulating GCPs.
+
+Classes:
+- mapdisplay::MapFrame
+
+(C) 2006-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import math
+import platform
+
+from core import globalvar
+import wx
+import wx.aui
+
+from mapdisp.toolbars import MapToolbar
+from gcp.toolbars import GCPDisplayToolbar, GCPManToolbar
+from mapdisp.gprint import PrintOptions
+from core.gcmd import GMessage
+from core.utils import _
+from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
+from gui_core.mapdisp import SingleMapFrame
+from core.settings import UserSettings
+from mapwin.buffered import BufferedMapWindow
+from mapwin.base import MapWindowProperties
+
+import mapdisp.statusbar as sb
+import gcp.statusbar as sbgcp
+
+# for standalone app
+cmdfilename = None
+
+
+class MapFrame(SingleMapFrame):
+    """Main frame for map display window. Drawing takes place in
+    child double buffered drawing window.
+    """
+
+    def __init__(self, parent, giface,
+                 title=_("GRASS GIS Manage Ground Control Points"),
+                 toolbars=["gcpdisp"], Map=None, auimgr=None,
+                 name='GCPMapWindow', **kwargs):
+        """Main map display window with toolbars, statusbar and
+        DrawWindow
+
+        :param giface: GRASS interface instance
+        :param title: window title
+        :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
+        :param map: instance of render.Map
+        :param auimgs: AUI manager
+        :param kwargs: wx.Frame attribures
+        """
+
+        SingleMapFrame.__init__(
+            self,
+            parent=parent,
+            giface=giface,
+            title=title,
+            Map=Map,
+            auimgr=auimgr,
+            name=name,
+            **kwargs)
+
+        self._giface = giface
+        # properties are shared in other objects, so defining here
+        self.mapWindowProperties = MapWindowProperties()
+        self.mapWindowProperties.setValuesFromUserSettings()
+        self.mapWindowProperties.alignExtent = True
+
+        #
+        # Add toolbars
+        #
+        for toolb in toolbars:
+            self.AddToolbar(toolb)
+
+        self.activemap = self.toolbars['gcpdisp'].togglemap
+        self.activemap.SetSelection(0)
+
+        self.SrcMap = self.grwiz.SrcMap       # instance of render.Map
+        self.TgtMap = self.grwiz.TgtMap       # instance of render.Map
+        self._mgr.SetDockSizeConstraint(0.5, 0.5)
+
+        #
+        # Add statusbar
+        #
+
+        # items for choice
+        self.statusbarItems = [sb.SbCoordinates,
+                               sb.SbRegionExtent,
+                               sb.SbCompRegionExtent,
+                               sb.SbShowRegion,
+                               sb.SbResolution,
+                               sb.SbDisplayGeometry,
+                               sb.SbMapScale,
+                               sb.SbProjection,
+                               sbgcp.SbGoToGCP,
+                               sbgcp.SbRMSError]
+
+        # create statusbar and its manager
+        statusbar = self.CreateStatusBar(number=4, style=0)
+        statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.statusbarManager = sb.SbManager(
+            mapframe=self, statusbar=statusbar)
+
+        # fill statusbar manager
+        self.statusbarManager.AddStatusbarItemsByClass(
+            self.statusbarItems, mapframe=self, statusbar=statusbar)
+        self.statusbarManager.AddStatusbarItem(
+            sb.SbMask(self, statusbar=statusbar, position=2))
+        self.statusbarManager.AddStatusbarItem(
+            sb.SbRender(self, statusbar=statusbar, position=3))
+
+        self.statusbarManager.SetMode(8)  # goto GCP
+
+        #
+        # Init map display (buffered DC & set default cursor)
+        #
+        self.grwiz.SwitchEnv('source')
+        self.SrcMapWindow = BufferedMapWindow(
+            parent=self, giface=self._giface, id=wx.ID_ANY,
+            properties=self.mapWindowProperties, Map=self.SrcMap)
+
+        self.grwiz.SwitchEnv('target')
+        self.TgtMapWindow = BufferedMapWindow(
+            parent=self, giface=self._giface, id=wx.ID_ANY,
+            properties=self.mapWindowProperties, Map=self.TgtMap)
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        self._setUpMapWindow(self.SrcMapWindow)
+        self._setUpMapWindow(self.TgtMapWindow)
+        self.SrcMapWindow.SetNamedCursor('cross')
+        self.TgtMapWindow.SetNamedCursor('cross')
+        # used to switch current map (combo box in toolbar)
+        self.SrcMapWindow.mouseEntered.connect(
+            lambda:
+            self._setActiveMapWindow(self.SrcMapWindow))
+        self.TgtMapWindow.mouseEntered.connect(
+            lambda:
+            self._setActiveMapWindow(self.TgtMapWindow))
+
+        #
+        # initialize region values
+        #
+        self._initMap(Map=self.SrcMap)
+        self._initMap(Map=self.TgtMap)
+
+        self.GetMapToolbar().SelectDefault()
+
+        #
+        # Bind various events
+        #
+        self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+
+        #
+        # Update fancy gui style
+        #
+        # AuiManager wants a CentrePane, workaround to get two equally sized
+        # windows
+        self.list = self.CreateGCPList()
+
+        #self.SrcMapWindow.SetSize((300, 300))
+        #self.TgtMapWindow.SetSize((300, 300))
+        self.list.SetSize((100, 150))
+        self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
+                          Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
+                          RightDockable(False).PinButton().FloatingSize((600, 200)).
+                          CloseButton(False).DestroyOnClose(True).
+                          Top().Layer(1).MinSize((200, 100)))
+        self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
+                          Name("source").Caption(_("Source Display")).Dockable(False).
+                          CloseButton(False).DestroyOnClose(True).Floatable(False).
+                          Centre())
+        self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
+                          Name("target").Caption(_("Target Display")).Dockable(False).
+                          CloseButton(False).DestroyOnClose(True).Floatable(False).
+                          Right().Layer(0))
+
+        srcwidth, srcheight = self.SrcMapWindow.GetSize()
+        tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+        srcwidth = (srcwidth + tgtwidth) / 2
+        self._mgr.GetPane("target").Hide()
+        self._mgr.Update()
+        self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+        self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
+        if self.show_target:
+            self._mgr.GetPane("target").Show()
+        else:
+            self.activemap.Enable(False)
+        # needed by Mac OS, does not harm on Linux, breaks display on Windows
+        if platform.system() != 'Windows':
+            self._mgr.Update()
+
+        #
+        # Init print module and classes
+        #
+        self.printopt = PrintOptions(self, self.MapWindow)
+
+        #
+        # Initialization of digitization tool
+        #
+        self.digit = None
+
+        # set active map
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+
+        # do not init zoom history here, that happens when zooming to map(s)
+
+        #
+        # Re-use dialogs
+        #
+        self.dialogs = {}
+        self.dialogs['attributes'] = None
+        self.dialogs['category'] = None
+        self.dialogs['barscale'] = None
+        self.dialogs['legend'] = None
+
+        self.decorationDialog = None  # decoration/overlays
+
+        # doing nice things in statusbar when other things are ready
+        self.statusbarManager.Update()
+
+    def _setUpMapWindow(self, mapWindow):
+        # TODO: almost the smae implementation as for MapFrameBase (only names differ)
+        # enable or disable zoom history tool
+        mapWindow.zoomHistoryAvailable.connect(
+            lambda:
+            self.GetMapToolbar().Enable('zoomback', enable=True))
+        mapWindow.zoomHistoryUnavailable.connect(
+            lambda:
+            self.GetMapToolbar().Enable('zoomback', enable=False))
+        mapWindow.mouseMoving.connect(self.CoordinatesChanged)
+
+    def AddToolbar(self, name):
+        """Add defined toolbar to the window
+
+        Currently known toolbars are:
+         - 'map'     - basic map toolbar
+         - 'vdigit'  - vector digitizer
+         - 'gcpdisp' - GCP Manager, Display
+         - 'gcpman'  - GCP Manager, points management
+         - 'nviz'    - 3D view mode
+        """
+        # default toolbar
+        if name == "map":
+            self.toolbars['map'] = MapToolbar(self, self._toolSwitcher)
+
+            self._mgr.AddPane(self.toolbars['map'],
+                              wx.aui.AuiPaneInfo().
+                              Name("maptoolbar").Caption(_("Map Toolbar")).
+                              ToolbarPane().Top().
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2).
+                              BestSize((self.toolbars['map'].GetSize())))
+
+        # GCP display
+        elif name == "gcpdisp":
+            self.toolbars['gcpdisp'] = GCPDisplayToolbar(
+                self, self._toolSwitcher)
+
+            self._mgr.AddPane(self.toolbars['gcpdisp'],
+                              wx.aui.AuiPaneInfo().
+                              Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
+                              ToolbarPane().Top().
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2))
+
+            if self.show_target == False:
+                self.toolbars['gcpdisp'].Enable('zoommenu', enable=False)
+
+            self.toolbars['gcpman'] = GCPManToolbar(self)
+
+            self._mgr.AddPane(self.toolbars['gcpman'],
+                              wx.aui.AuiPaneInfo().
+                              Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
+                              ToolbarPane().Top().Row(1).
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2))
+
+        self._mgr.Update()
+
+    def OnUpdateProgress(self, event):
+        """
+        Update progress bar info
+        """
+        self.GetProgressBar().UpdateProgress(event.layer, event.map)
+
+        event.Skip()
+
+    def OnFocus(self, event):
+        """
+        Change choicebook page to match display.
+        Or set display for georectifying
+        """
+        # was in if layer manager but considering the state it was executed
+        # always, moreover, there is no layer manager dependent code
+
+        # in GCP Management, set focus to current MapWindow for mouse actions
+        self.OnPointer(event)
+        self.MapWindow.SetFocus()
+
+        event.Skip()
+
+    def OnDraw(self, event):
+        """Re-display current map composition
+        """
+        self.MapWindow.UpdateMap(render=False)
+
+    def OnRender(self, event):
+        """Re-render map composition (each map layer)
+        """
+        # FIXME: remove qlayer code or use RemoveQueryLayer() now in mapdisp.frame
+        # delete tmp map layers (queries)
+        qlayer = self.Map.GetListOfLayers(name=globalvar.QUERYLAYER)
+        for layer in qlayer:
+            self.Map.DeleteLayer(layer)
+
+        self.SrcMapWindow.UpdateMap(render=True)
+        if self.show_target:
+            self.TgtMapWindow.UpdateMap(render=True)
+
+        # update statusbar
+        self.StatusbarUpdate()
+
+    def OnPointer(self, event):
+        """Pointer button clicked
+        """
+        self.SrcMapWindow.SetModePointer()
+        self.TgtMapWindow.SetModePointer()
+        # change the default cursor
+        self.SrcMapWindow.SetNamedCursor('cross')
+        self.TgtMapWindow.SetNamedCursor('cross')
+
+    def OnZoomIn(self, event):
+        """Zoom in the map."""
+        self.SrcMapWindow.SetModeZoomIn()
+        self.TgtMapWindow.SetModeZoomIn()
+
+    def OnZoomOut(self, event):
+        """Zoom out the map."""
+        self.SrcMapWindow.SetModeZoomOut()
+        self.TgtMapWindow.SetModeZoomOut()
+
+    def OnPan(self, event):
+        """Panning, set mouse to drag"""
+        self.SrcMapWindow.SetModePan()
+        self.TgtMapWindow.SetModePan()
+
+    def OnErase(self, event):
+        """
+        Erase the canvas
+        """
+        self.MapWindow.EraseMap()
+
+        if self.MapWindow == self.SrcMapWindow:
+            win = self.TgtMapWindow
+        elif self.MapWindow == self.TgtMapWindow:
+            win = self.SrcMapWindow
+
+        win.EraseMap()
+
+    def SaveToFile(self, event):
+        """Save map to image
+        """
+        img = self.MapWindow.img
+        if not img:
+            GMessage(parent=self, message=_(
+                "Nothing to render (empty map). Operation canceled."))
+            return
+        filetype, ltype = GetImageHandlers(img)
+
+        # get size
+        dlg = ImageSizeDialog(self)
+        dlg.CentreOnParent()
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        width, height = dlg.GetValues()
+        dlg.Destroy()
+
+        # get filename
+        dlg = wx.FileDialog(parent=self,
+                            message=_("Choose a file name to save the image "
+                                      "(no need to add extension)"),
+                            wildcard=filetype,
+                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            if not path:
+                dlg.Destroy()
+                return
+
+            base, ext = os.path.splitext(path)
+            fileType = ltype[dlg.GetFilterIndex()]['type']
+            extType = ltype[dlg.GetFilterIndex()]['ext']
+            if ext != extType:
+                path = base + '.' + extType
+
+            self.MapWindow.SaveToFile(path, fileType,
+                                      width, height)
+
+        dlg.Destroy()
+
+    def PrintMenu(self, event):
+        """
+        Print options and output menu for map display
+        """
+        point = wx.GetMousePosition()
+        printmenu = wx.Menu()
+        # Add items to the menu
+        setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
+        printmenu.AppendItem(setup)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
+
+        preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
+        printmenu.AppendItem(preview)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
+
+        doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
+        printmenu.AppendItem(doprint)
+        self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(printmenu)
+        printmenu.Destroy()
+
+    def OnZoomToRaster(self, event):
+        """
+        Set display extents to match selected raster map (ignore NULLs)
+        """
+        self.MapWindow.ZoomToMap(ignoreNulls=True)
+
+    def OnZoomToSaved(self, event):
+        """Set display geometry to match extents in
+        saved region file
+        """
+        self.MapWindow.SetRegion(zoomOnly=True)
+
+    def OnDisplayToWind(self, event):
+        """Set computational region (WIND file) to match display
+        extents
+        """
+        self.MapWindow.DisplayToWind()
+
+    def SaveDisplayRegion(self, event):
+        """Save display extents to named region file.
+        """
+        self.MapWindow.SaveDisplayRegion()
+
+    def OnZoomMenu(self, event):
+        """Popup Zoom menu
+        """
+        point = wx.GetMousePosition()
+        zoommenu = wx.Menu()
+        # Add items to the menu
+
+        zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+            'Zoom to computational region (set with g.region)'))
+        zoommenu.AppendItem(zoomwind)
+        self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
+
+        zoomdefault = wx.MenuItem(
+            zoommenu, wx.ID_ANY, _('Zoom to default region'))
+        zoommenu.AppendItem(zoomdefault)
+        self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
+
+        zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
+        zoommenu.AppendItem(zoomsaved)
+        self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
+
+        savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+            'Set computational region from display'))
+        zoommenu.AppendItem(savewind)
+        self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
+
+        savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _(
+            'Save display geometry to named region'))
+        zoommenu.AppendItem(savezoom)
+        self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
+
+        # Popup the menu. If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(zoommenu)
+        zoommenu.Destroy()
+
+    def IsStandalone(self):
+        """Check if Map display is standalone"""
+        # we do not know and we do not care, so always False
+        return True
+
+    def GetLayerManager(self):
+        """Get reference to Layer Manager
+
+        :return: always None
+        """
+        return None
+
+    def GetSrcWindow(self):
+        return self.SrcMapWindow
+
+    def GetTgtWindow(self):
+        return self.TgtMapWindow
+
+    def GetShowTarget(self):
+        return self.show_target
+
+    def GetMapToolbar(self):
+        """Returns toolbar with zooming tools"""
+        return self.toolbars['gcpdisp']
+
+    def _setActiveMapWindow(self, mapWindow):
+        if not self.MapWindow == mapWindow:
+            self.MapWindow = mapWindow
+            self.Map = mapWindow.Map
+            self.UpdateActive(mapWindow)
+            # needed for wingrass
+            self.SetFocus()

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_menustrings.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_menustrings.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_menustrings.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,2063 @@
+# This is a generated file.
+
+menustrings_menudata.LayerManagerMenuData = [
+    _('&File'),
+    _('Workspace'),
+    _('New'),
+    _('Create new workspace'),
+    _('Open'),
+    _('Load workspace from file'),
+    _('Save'),
+    _('Save workspace'),
+    _('Save as'),
+    _('Save workspace to file'),
+    _('Close'),
+    _('Close workspace file'),
+    _('Load GRC file (Tcl/Tk GUI)'),
+    _('Load map layers from GRC file to layer tree'),
+    _('Map display'),
+    _('Add raster'),
+    _('Add raster map layer to current display'),
+    _('Add vector'),
+    _('Add vector map layer to current display'),
+    _('Add multiple rasters or vectors'),
+    _('Add multiple raster or vector map layers to current display'),
+    _('Add RGB raster layer'),
+    _('Add RGB raster map layer to current display'),
+    _('Add web service layer'),
+    _('Add web service layer'),
+    _('New map display window'),
+    _('Open new map display window'),
+    _('Render all map displays'),
+    _('Re-render maps in all open map display windows'),
+    _('Close current map display window'),
+    _('Close current map display window'),
+    _('Close all open map display windows'),
+    _('Close all open map display windows'),
+    _('Import raster data'),
+    _('Common formats import'),
+    _('Imports raster data into a GRASS raster map using GDAL library.'),
+    _('Import of common formats with reprojection'),
+    _('Imports raster data into a GRASS raster map using GDAL library and reprojects on the fly.'),
+    _('ASCII x,y,z point import and gridding'),
+    _('Creates a raster map from an assemblage of many coordinates using univariate statistics.'),
+    _('ASCII grid import'),
+    _('Converts a GRASS ASCII raster file to binary raster map.'),
+    _('ASCII polygons, lines, and point import'),
+    _('Creates raster maps from ASCII polygon/line/point data files.'),
+    _('Raw binary array import'),
+    _('Import a binary raster file into a GRASS raster map layer.'),
+    _('GRIDATB.FOR import'),
+    _('Imports GRIDATB.FOR map file (TOPMODEL) into a GRASS raster map.'),
+    _('Matlab 2D array import'),
+    _('Imports a binary MAT-File(v4) to a GRASS raster.'),
+    _('PNG import'),
+    _('Imports non-georeferenced PNG format image.'),
+    _('SPOT NDVI import'),
+    _('Imports SPOT VGT NDVI data into a raster map.'),
+    _('SRTM HGT import'),
+    _('Imports SRTM HGT files into raster map.'),
+    _('Terra ASTER HDF import'),
+    _('Georeference, rectify, and import Terra-ASTER imagery and relative DEMs using gdalwarp.'),
+    _('LAS LiDAR points import'),
+    _('Unpack raster map'),
+    _('Imports a raster map as GRASS GIS specific archive file (packed with r.pack)'),
+    _('Reproject raster map from different GRASS location'),
+    _('Re-projects a raster map from given location to the current location.'),
+    _('Import vector data'),
+    _('Common import formats'),
+    _('Imports vector data into a GRASS vector map using OGR library.'),
+    _('Import of common formats with reprojection'),
+    _('Imports vector data into a GRASS vector map using OGR library and reprojects on the fly.'),
+    _('ASCII points or GRASS ASCII format'),
+    _('Creates a vector map from an ASCII points file or ASCII vector file.'),
+    _('ASCII points as a vector lines'),
+    _('Imports ASCII x,y[,z] coordinates as a series of lines.'),
+    _('DXF import'),
+    _('Converts files in DXF format to GRASS vector map format.'),
+    _('WFS'),
+    _('Imports GetFeature from a WFS server.'),
+    _('ESRI e00 import'),
+    _('Imports E00 file into a vector map.'),
+    _('Geonames import'),
+    _('Imports geonames.org country files into a vector points map.'),
+    _('Matlab array or Mapgen format import'),
+    _('Imports Mapgen or Matlab-ASCII vector maps into GRASS.'),
+    _('LAS LiDAR points import'),
+    _('Unpack vector map'),
+    _('Imports a vector map as GRASS GIS specific archive file (packed with v.pack)'),
+    _('Reproject vector map from different GRASS location'),
+    _('Re-projects a vector map from one location to the current location.'),
+    _('Import 3D raster data'),
+    _('ASCII 3D import'),
+    _('Converts a 3D ASCII raster text file into a (binary) 3D raster map.'),
+    _('Raw binary array 3D import'),
+    _('Imports a binary raster file into a GRASS 3D raster map.'),
+    _('Vis5D import'),
+    _('Import 3-dimensional Vis5D files.'),
+    _('Import database table'),
+    _('Common import formats'),
+    _('Imports attribute tables in various formats.'),
+    _('Export raster map'),
+    _('Common export formats'),
+    _('Exports GRASS raster maps into GDAL supported formats.'),
+    _('ASCII grid export'),
+    _('Converts a raster map layer into a GRASS ASCII text file.'),
+    _('ASCII x,y,z points export'),
+    _('Exports a raster map to a text file as x,y,z values based on cell centers.'),
+    _('GRIDATB.FOR export'),
+    _('Exports GRASS raster map to GRIDATB.FOR map file (TOPMODEL).'),
+    _('Matlab 2D array export'),
+    _('Exports a GRASS raster to a binary MAT-File.'),
+    _('Raw binary array export'),
+    _('Exports a GRASS raster to a binary array.'),
+    _('MPEG-1 export'),
+    _('Converts raster map series to MPEG movie.'),
+    _('PNG export'),
+    _('Export a GRASS raster map as a non-georeferenced PNG image.'),
+    _('PPM export'),
+    _('Converts a GRASS raster map to a PPM image file.'),
+    _('PPM from RGB export'),
+    _('Converts 3 GRASS raster layers (R,G,B) to a PPM image file.'),
+    _('POV-Ray export'),
+    _('Converts a raster map layer into a height-field file for POV-Ray.'),
+    _('VRML export'),
+    _('Exports a raster map to the Virtual Reality Modeling Language (VRML).'),
+    _('VTK export'),
+    _('Converts raster maps into the VTK-ASCII format.'),
+    _('Pack raster map'),
+    _('Exports a raster map as GRASS GIS specific archive file'),
+    _('Export vector map'),
+    _('Common export formats'),
+    _('Exports a vector map layer to any of the supported OGR vector formats. By default a vector map layer is exported to Esri Shapefile format.'),
+    _('ASCII points or GRASS ASCII vector export'),
+    _("Exports a vector map to a GRASS ASCII vector representation. By default only features with category are exported. To export all features use 'layer=-1'."),
+    _('DXF export'),
+    _('Exports vector map to DXF file format.'),
+    _('PostGIS export'),
+    _('POV-Ray export'),
+    _('Converts GRASS x,y,z points to POV-Ray x,z,y format.'),
+    _('SVG export'),
+    _('Exports a vector map to SVG file.'),
+    _('VTK export'),
+    _('Converts a vector map to VTK ASCII output.'),
+    _('Pack vector map'),
+    _('Exports a vector map as GRASS GIS specific archive file'),
+    _('Export 3D raster maps'),
+    _('ASCII 3D export'),
+    _('Converts a 3D raster map layer into a ASCII text file.'),
+    _('Raw binary array 3D export'),
+    _('Exports a GRASS 3D raster map to a binary array.'),
+    _('Vis5D export'),
+    _('Exports GRASS 3D raster map to 3-dimensional Vis5D file.'),
+    _('VTK export'),
+    _('Converts 3D raster maps into the VTK-ASCII format.'),
+    _('Export database table'),
+    _('Common export formats'),
+    _('Exports attribute tables into various formats.'),
+    _('Link external data'),
+    _('Link external raster data'),
+    _('Link GDAL supported raster data as a pseudo GRASS raster map layer.'),
+    _('Link external vector data'),
+    _('Creates a new pseudo-vector map as a link to an OGR-supported layer.'),
+    _('Output format for raster data'),
+    _('Redirects raster output to file utilizing GDAL library rather than storing in GRASS raster format.'),
+    _('Output format for vector data'),
+    _('Defines vector output format utilizing OGR library.'),
+    _('Manage maps'),
+    _('Copy'),
+    _("Copies available data files in the current mapset search path to the user's current mapset."),
+    _('List'),
+    _('Lists available GRASS data base files of the user-specified data type optionally using the search pattern.'),
+    _('Rename'),
+    _("Renames data base element files in the user's current mapset."),
+    _('Delete'),
+    _("Removes data base element files from the user's current mapset using the search pattern."),
+    _('Map type conversions'),
+    _('Raster to vector'),
+    _('Converts a raster map into a vector map.'),
+    _('Raster series to 3D raster'),
+    _('Converts 2D raster map slices to one 3D raster volume map.'),
+    _('Raster 2.5D to 3D raster'),
+    _('Creates a 3D volume map based on 2D elevation and value raster maps.'),
+    _('Vector to raster'),
+    _('Converts (rasterize) a vector map into a raster map.'),
+    _('Vector to 3D raster'),
+    _('Converts a vector map (only points) into a 3D raster map.'),
+    _('2D vector to 3D vector'),
+    _('Performs transformation of 2D vector features to 3D.'),
+    _('3D raster to raster series'),
+    _('Converts 3D raster maps to 2D raster maps'),
+    _('Georectify'),
+    _('Manage Ground Control Points for Georectification'),
+    _('Graphical modeler'),
+    _('Launch Graphical modeler'),
+    _('Run model'),
+    _('Run model prepared by Graphical modeler'),
+    _('3D image rendering'),
+    _('Creates a 3D rendering of GIS data. Renders surfaces (raster data), 2D/3D vector data, and volumes (3D raster data) in 3D.'),
+    _('Animation tool'),
+    _('Launch animation tool.'),
+    _('Bearing/distance to coordinates'),
+    _('A simple utility for converting bearing and distance measurements to coordinates and vice versa. It assumes a cartesian coordinate system'),
+    _('Cartographic Composer'),
+    _('Launch Cartographic Composer'),
+    _('Map Swipe'),
+    _('Launch Map Swipe'),
+    _('Launch script'),
+    _('Launches script file.'),
+    _('Close GUI'),
+    _('Close graphical user interface.'),
+    _('Quit GRASS GIS'),
+    _('Close GUI and exit GRASS GIS shell.'),
+    _('&Settings'),
+    _('Computational region'),
+    _('Show current region'),
+    _('Shows the extent and resolution of the computational region.'),
+    _('Show region using latitude and longitude'),
+    _('Shows the extent and resolution of the computational region.'),
+    _('Set region'),
+    _('Manages the boundary definitions for the geographic region.'),
+    _('GRASS working environment'),
+    _('Mapset access'),
+    _('Set/unset access to other mapsets in current location'),
+    _('User access'),
+    _('Controls access to the current mapset for other users on the system. If no option given, prints current status.'),
+    _('Change working environment'),
+    _('Changes/reports current mapset. Optionally create new mapset or list available mapsets in given location.'),
+    _('Change location and mapset'),
+    _('Change current location and mapset.'),
+    _('Change mapset'),
+    _('Change current mapset.'),
+    _('Change working directory'),
+    _('Change working directory'),
+    _('Show settings'),
+    _("Outputs and modifies the user's current GRASS variable settings."),
+    _('Change settings'),
+    _("Outputs and modifies the user's current GRASS variable settings. Prints all defined GRASS variables if no option is given."),
+    _('Create new location'),
+    _('Launches location wizard to create new GRASS location.'),
+    _('Create new mapset'),
+    _('Creates new mapset in the current location, changes current mapset.'),
+    _('Version and copyright'),
+    _('Displays version and copyright information.'),
+    _('Map projections'),
+    _('Display map projection'),
+    _('Converts co-ordinate system descriptions (i.e. projection information) between various formats (including GRASS format).'),
+    _('Manage projections'),
+    _('Prints or modifies GRASS projection information files (in various co-ordinate system descriptions). Can also be used to create new GRASS locations.'),
+    _('Convert coordinates'),
+    _('Converts coordinates from one projection to another (cs2cs frontend).'),
+    _('Addons extensions'),
+    _('Install extension from addons'),
+    _('Installs new extension from GRASS AddOns SVN repository.'),
+    _('Manage installed extension'),
+    _('Updates or removes installed GRASS AddOns extension(s).'),
+    _('Preferences'),
+    _('User GUI preferences (display font, commands, digitizer, etc.)'),
+    _('&Raster'),
+    _('Develop raster map'),
+    _('Compress/decompress'),
+    _('Compresses and decompresses raster maps.'),
+    _('Region boundaries'),
+    _('Sets the boundary definitions for a raster map.'),
+    _('Manage NULL values'),
+    _('Manages NULL-values of given raster map.'),
+    _('Quantization'),
+    _('Produces the quantization file for a floating-point map.'),
+    _('Timestamp'),
+    _('Modifies a timestamp for a raster map. Print/add/remove a timestamp for a raster map.'),
+    _('Resample using aggregate statistics'),
+    _('Resamples raster map layers to a coarser grid using aggregation.'),
+    _('Resample using multiple methods'),
+    _('Resamples raster map to a finer grid using interpolation.'),
+    _('Resample using nearest neighbor'),
+    _('GRASS raster map layer data resampling capability.'),
+    _('Resample using spline tension'),
+    _('Reinterpolates and optionally computes topographic analysis from input raster map to a new raster map (possibly with different resolution) using regularized spline with tension and smoothing.'),
+    _('Resample using bspline'),
+    _('Performs bilinear or bicubic spline interpolation with Tykhonov regularization.'),
+    _('Resample using analytic kernel'),
+    _('Resamples raster map layers using an analytic kernel.'),
+    _('Support file maintenance'),
+    _('Allows creation and/or modification of raster map layer support files.'),
+    _('Update map statistics'),
+    _('Update raster map statistics'),
+    _('Reproject raster map from different GRASS location'),
+    _('Re-projects a raster map from given location to the current location.'),
+    _('Tiling'),
+    _('Produces tilings of the source projection for use in the destination region and projection.'),
+    _('Manage colors'),
+    _('Color tables'),
+    _('Creates/modifies the color table associated with a raster map.'),
+    _('Color tables (stddev)'),
+    _("Sets color rules based on stddev from a raster map's mean value."),
+    _('Manage color rules interactively'),
+    _('Interactive management of raster color tables.'),
+    _('Export color table'),
+    _('Exports the color table associated with a raster map.'),
+    _('Blend 2 color rasters'),
+    _('Blends color components of two raster maps by a given ratio.'),
+    _('Create RGB'),
+    _('Combines red, green and blue raster maps into a single composite raster map.'),
+    _('RGB to HIS'),
+    _('Generates red, green and blue (RGB) raster map layers combining hue, intensity and saturation (HIS) values from user-specified input raster map layers.'),
+    _('Query raster maps'),
+    _('Query values by coordinates'),
+    _('Queries raster maps on their category values and category labels.'),
+    _('Query colors by value'),
+    _('Queries colors for a raster map layer.'),
+    _('Map type conversions'),
+    _('Raster to vector'),
+    _('Converts a raster map into a vector map.'),
+    _('Raster series to 3D raster'),
+    _('Converts 2D raster map slices to one 3D raster volume map.'),
+    _('Raster 2.5D to 3D raster'),
+    _('Creates a 3D volume map based on 2D elevation and value raster maps.'),
+    _('Raster buffers and distance'),
+    _('Buffer rasters'),
+    _('Creates a raster map showing buffer zones surrounding cells that contain non-NULL category values.'),
+    _('Concentric circles'),
+    _('Creates a raster map containing concentric rings around a given point.'),
+    _('Closest points'),
+    _('Locates the closest points between objects in two raster maps.'),
+    _('Grow by one cell'),
+    _('Generates a raster map layer with contiguous areas grown by one cell.'),
+    _('Distance to features'),
+    _('Generates a raster map containing distances to nearest raster features.'),
+    _('Mask'),
+    _('Creates a MASK for limiting raster operation.'),
+    _('Raster map calculator'),
+    _('Raster map calculator'),
+    _('Neighborhood analysis'),
+    _('Moving window'),
+    _('Makes each cell category value a function of the category values assigned to the cells around it, and stores new cell values in an output raster map layer.'),
+    _('Neighborhood points'),
+    _('Neighborhood analysis tool for vector point maps. Makes each cell value a function of the attribute values assigned to the vector points or centroids around it, and stores new cell values in an output raster map.'),
+    _('Overlay rasters'),
+    _('Cross product'),
+    _('Creates a cross product of the category values from multiple raster map layers.'),
+    _('Patch raster maps'),
+    _('Creates a composite raster map layer by using known category values from one (or more) map layer(s) to fill in areas of "no data" in another map layer.'),
+    _('Raster series aggregation'),
+    _('Makes each output cell value a function of the values assigned to the corresponding cells in the input raster map layers.'),
+    _('Raster series accumulation'),
+    _('Makes each output cell value a accumulationfunction of the values assigned to the corresponding cells in the input raster map layers.'),
+    _('Statistical overlay'),
+    _('Calculates category or object oriented statistics (accumulator-based statistics).'),
+    _('Quantiles overlay'),
+    _('Compute category quantiles using two passes.'),
+    _('Solar radiance and shadows'),
+    _('LatLong map'),
+    _('Creates a latitude/longitude raster map.'),
+    _('Solar irradiance and irradiation'),
+    _('Solar irradiance and irradiation model. Computes direct (beam), diffuse and reflected solar irradiation raster maps for given day, latitude, surface and atmospheric conditions. Solar parameters (e.g. sunrise, sunset times, declination, extraterrestrial irradiance, daylight length) are saved in the map history file. Alternatively, a local time can be specified to compute solar incidence angle and/or irradiance raster maps. The shadowing effect of the topography is optionally incorporated.'),
+    _('Shadows map'),
+    _('Calculates cast shadow areas from sun position and elevation raster map. Either exact sun position (A) is specified, or date/time to calculate the sun position (B) by r.sunmask itself.'),
+    _('Sunshine hours and solar angles'),
+    _("Calculates solar elevation, solar azimuth, and sun hours. Solar elevation: the angle between the direction of the geometric center of the sun's apparent disk and the (idealized) horizon. Solar azimuth: the angle from due north in clockwise direction."),
+    _('Terrain analysis'),
+    _('Generate contour lines'),
+    _('Produces a vector map of specified contours from a raster map.'),
+    _('Cost surface'),
+    _('Creates a raster map showing the cumulative cost of moving between different geographic locations on an input raster map whose cell category values represent cost.'),
+    _('Cumulative movement costs'),
+    _('Creates a raster map showing the anisotropic cumulative cost of moving between different geographic locations on an input raster map whose cell category values represent cost.'),
+    _('Least cost route or flow'),
+    _('Traces a flow through an elevation model or cost surface on a raster map.'),
+    _('Compute shaded relief'),
+    _('Creates shaded relief map from an elevation map (DEM). '),
+    _('Apply shade to raster'),
+    _('Drapes a color raster over an shaded relief or aspect map.'),
+    _('Slope and aspect'),
+    _('Generates raster maps of slope, aspect, curvatures and partial derivatives from an elevation raster map. Aspect is calculated counterclockwise from east.'),
+    _('Terrain parameters'),
+    _('Extracts terrain parameters from a DEM. Uses a multi-scale approach by taking fitting quadratic parameters to any size window (via least squares).'),
+    _('Textural features'),
+    _('Generate images with textural features from a raster map.'),
+    _('Visibility'),
+    _('Computes the viewshed of a point on an elevation raster map. Default format: NULL (invisible), vertical angle wrt viewpoint (visible).'),
+    _('Distance to features'),
+    _('Generates a raster map containing distances to nearest raster features.'),
+    _('Horizon angle'),
+    _("Computes horizon angle height from a digital elevation model. The module has two different modes of operation: 1. Computes the entire horizon around a single point whose coordinates are given with the 'coord' option. The horizon height (in radians). 2. Computes one or more raster maps of the horizon height in a single direction. The input for this is the angle (in degrees), which is measured counterclockwise with east=0, north=90 etc. The output is the horizon height in radians."),
+    _('Transform features'),
+    _('Clump'),
+    _('Recategorizes data in a raster map by grouping cells that form physically discrete areas into unique categories.'),
+    _('Grow'),
+    _('Generates a raster map layer with contiguous areas grown by one cell.'),
+    _('Thin'),
+    _('Thins non-null cells that denote linear features in a raster map layer.'),
+    _('Hydrologic modeling'),
+    _('Carve stream channels'),
+    _('Generates stream channels. Takes vector stream data, transforms it to raster and subtracts depth from the output DEM.'),
+    _('Fill lake'),
+    _('Fills lake at given point to given level.'),
+    _('Depressionless map and flowlines'),
+    _('Filters and generates a depressionless elevation map and a flow direction map from a given elevation raster map.'),
+    _('Flow accumulation'),
+    _('Performs flow computation for massive grids.'),
+    _('Flow lines'),
+    _('Constructs flowlines. Computes flowlines, flowpath lengths, and flowaccumulation (contributing areas) from a elevation raster map.'),
+    _('Watershed analysis'),
+    _('Calculates hydrological parameters and RUSLE factors.'),
+    _('Watershed subbasins'),
+    _('Generates watershed subbasins raster map.'),
+    _('Watershed basin creation'),
+    _('Creates watershed basins from a drainage direction map.'),
+    _('Extraction of stream networks'),
+    _('Performs stream network extraction.'),
+    _('SIMWE Overland flow modeling'),
+    _('Overland flow hydrologic simulation using path sampling method (SIMWE).'),
+    _('SIMWE Sediment flux modeling'),
+    _('Sediment transport and erosion/deposition simulation using path sampling method (SIMWE).'),
+    _('Topographic index map'),
+    _('Creates a topographic index (wetness index) raster map from an elevation raster map.'),
+    _('TOPMODEL simulation'),
+    _('Simulates TOPMODEL which is a physically based hydrologic model.'),
+    _('USLE K-factor'),
+    _('Computes USLE Soil Erodibility Factor (K).'),
+    _('USLE R-factor'),
+    _('Computes USLE R factor, Rainfall erosivity index.'),
+    _('Groundwater modeling'),
+    _('Groundwater flow'),
+    _('Numerical calculation program for transient, confined and unconfined groundwater flow in two dimensions.'),
+    _('Groundwater solute transport'),
+    _('Numerical calculation program for transient, confined and unconfined solute transport in two dimensions'),
+    _('Landscape patch analysis'),
+    _('Set up sampling and analysis framework'),
+    _("Configuration editor for r.li.'index'"),
+    _('Edge density'),
+    _('Calculates edge density index on a raster map, using a 4 neighbour algorithm'),
+    _('Contrast weighted edge density'),
+    _('Calculates contrast weighted edge density index on a raster map'),
+    _('Patch area mean'),
+    _('Calculates mean patch size index on a raster map, using a 4 neighbour algorithm'),
+    _('Patch area range'),
+    _('Calculates range of patch area size on a raster map'),
+    _('Patch area Std Dev'),
+    _('Calculates standard deviation of patch area a raster map'),
+    _('Patch area Coeff Var'),
+    _('Calculates coefficient of variation of patch area on a raster map'),
+    _('Patch density'),
+    _('Calculates patch density index on a raster map, using a 4 neighbour algorithm'),
+    _('Patch number'),
+    _('Calculates patch number index on a raster map, using a 4 neighbour algorithm.'),
+    _("Dominance's diversity"),
+    _("Calculates dominance's diversity index on a raster map"),
+    _("Shannon's diversity"),
+    _("Calculates Shannon's diversity index on a raster map"),
+    _("Simpson's diversity"),
+    _("Calculates Simpson's diversity index on a raster map"),
+    _('Richness'),
+    _('Calculates richness index on a raster map'),
+    _('Shape index'),
+    _('Calculates shape index on a raster map'),
+    _('Wildfire modeling'),
+    _('Rate of spread'),
+    _('Generates rate of spread raster maps. Generates three, or four raster map layers showing the base (perpendicular) rate of spread (ROS), the maximum (forward) ROS, the direction of the maximum ROS, and optionally the maximum potential spotting distance for fire spread simulation.'),
+    _('Least-cost spread paths'),
+    _('Recursively traces the least cost path backwards to cells from which the cumulative cost was determined.'),
+    _('Anisotropic spread simulation'),
+    _('Simulates elliptically anisotropic spread. Generates a raster map of the cumulative time of spread, given raster maps containing the rates of spread (ROS), the ROS directions and the spread origins. It optionally produces raster maps to contain backlink UTM coordinates for tracing spread paths. Usable for fire spread simulations.'),
+    _('Change category values and labels'),
+    _('Manage category information'),
+    _('Manages category values and labels associated with user-specified raster map layers.'),
+    _('Interactively edit category values'),
+    _('Edits cell values in a raster map.'),
+    _('Reclassify by size'),
+    _('Reclasses a raster map greater or less than user specified area size (in hectares).'),
+    _('Reclassify'),
+    _('Reclassify raster map based on category values. Creates a new raster map whose category values are based upon a reclassification of the categories in an existing raster map.'),
+    _('Recode'),
+    _('Recodes categorical raster maps.'),
+    _('Rescale'),
+    _('Rescales the range of category values in a raster map layer.'),
+    _('Rescale with histogram'),
+    _('Rescales histogram equalized the range of category values in a raster map layer.'),
+    _('Generate random cells'),
+    _('Random cells'),
+    _('Generates random cell values with spatial dependence.'),
+    _('Random cells and vector points'),
+    _('Creates a raster map layer and vector point map containing randomly located points.'),
+    _('Generate surfaces'),
+    _('Fractal surface'),
+    _('Creates a fractal surface of a given fractal dimension.'),
+    _('Gaussian kernel density surface'),
+    _('Generates a raster density map from vector points map. Density is computed using a moving kernel. Optionally generates a vector density map on a vector network.'),
+    _('Gaussian deviates surface'),
+    _('Generates a raster map using gaussian random number generator. Mean and standard deviation of gaussian deviates can be expressed by the user.'),
+    _('Plane'),
+    _('Creates raster plane map given dip (inclination), aspect (azimuth) and one point.'),
+    _('Random deviates surface'),
+    _('Produces a raster surface map of uniform random deviates with defined range.'),
+    _('Random surface with spatial dependence'),
+    _('Generates random surface(s) with spatial dependence.'),
+    _('Interpolate surfaces'),
+    _('Bilinear and bicubic from vector points'),
+    _('Performs bicubic or bilinear spline interpolation with Tykhonov regularization.'),
+    _('IDW from raster points'),
+    _('Provides surface interpolation from raster point data by Inverse Distance Squared Weighting.'),
+    _('IDW from vector points'),
+    _('Provides surface interpolation from vector point data by Inverse Distance Squared Weighting.'),
+    _('Raster contours'),
+    _('Generates surface raster map from rasterized contours.'),
+    _('Regularized spline tension'),
+    _('Performs surface interpolation from vector points map by splines. Spatial approximation and topographic analysis from given point or isoline data in vector format to floating point raster format using regularized spline with tension.'),
+    _('Raster series interpolation'),
+    _('Interpolates raster maps located (temporal or spatial) in between input raster maps at specific sampling positions.'),
+    _('Fill NULL cells'),
+    _('Fills no-data areas in raster maps using spline interpolation.'),
+    _('Reports and statistics'),
+    _('Basic raster metadata'),
+    _('Outputs basic information about a raster map.'),
+    _('Manage category information'),
+    _('Manages category values and labels associated with user-specified raster map layers.'),
+    _('General statistics'),
+    _('Generates area statistics for raster map.'),
+    _('Quantiles for large data sets'),
+    _('Compute quantiles using two passes.'),
+    _('Range of category values'),
+    _('Prints terse list of category values found in a raster map layer.'),
+    _('Sum area by raster map and category'),
+    _('Reports statistics for raster maps.'),
+    _('Statistics for clumped cells'),
+    _('Calculates the volume of data "clumps". Optionally produces a GRASS vector points map containing the calculated centroids of these clumps.'),
+    _('Total corrected area'),
+    _('Prints estimation of surface area for raster map.'),
+    _('Univariate raster statistics'),
+    _('Calculates univariate statistics from the non-null cells of a raster map. Statistics include number of cells counted, minimum and maximum cell values, range, arithmetic mean, population variance, standard deviation, coefficient of variation, and sum.'),
+    _('Sample transects'),
+    _('Outputs the raster map layer values lying on user-defined line(s).'),
+    _('Sample transects (bearing/distance)'),
+    _('Outputs raster map layer values lying along user defined transect line(s).'),
+    _('Covariance/correlation'),
+    _('Outputs a covariance/correlation matrix for user-specified raster map layer(s).'),
+    _('Linear regression'),
+    _('Calculates linear regression from two raster maps: y = a + b*x.'),
+    _('Multiple regression'),
+    _('Calculates multiple linear regression from raster maps.'),
+    _('Mutual category occurrences'),
+    _('Tabulates the mutual occurrence (coincidence) of categories for two raster map layers.'),
+    _('&Vector'),
+    _('Develop vector map'),
+    _('Create new vector map'),
+    _('Create new empty vector map'),
+    _('Edit vector map (non-interactively)'),
+    _('Edits a vector map, allows adding, deleting and modifying selected vector features.'),
+    _('Convert object types'),
+    _('Changes type of vector features.'),
+    _('Parallel lines'),
+    _('Creates parallel line to input vector lines.'),
+    _('Dissolve boundaries'),
+    _('Dissolves boundaries between adjacent areas sharing a common category number or attribute.'),
+    _('Create 3D vector over raster'),
+    _('Converts 2D vector features to 3D by sampling of elevation raster map.'),
+    _('Extrude 3D vector map'),
+    _('Extrudes flat vector features to 3D vector features with defined height. Optionally the height can be derived from sampling of elevation raster map.'),
+    _('Create labels'),
+    _('Creates paint labels for a vector map from attached attributes.'),
+    _('Reposition vector map'),
+    _('Performs an affine transformation (shift, scale and rotate) on vector map.'),
+    _('Rectify vector map'),
+    _('Rectifies a vector by computing a coordinate transformation for each object in the vector based on the control points.'),
+    _('Reproject vector map from different GRASS location'),
+    _('Re-projects a vector map from one location to the current location.'),
+    _('Support file maintenance'),
+    _('Updates vector map metadata.'),
+    _('Topology maintenance'),
+    _('Create or rebuild topology'),
+    _('Creates topology for vector map. Optionally also checks for topological errors.'),
+    _('Rebuild topology on all vector maps'),
+    _('Rebuilds topology on all vector maps in the current mapset.'),
+    _('Build polylines'),
+    _('Builds polylines from lines or boundaries.'),
+    _('Split lines'),
+    _('Splits vector lines to shorter segments.'),
+    _('Split polylines'),
+    _('Creates points/segments from input vector lines and positions.'),
+    _('Clean vector map'),
+    _('Toolset for cleaning topology of vector map.'),
+    _('Smooth or simplify'),
+    _('Performs vector based generalization.'),
+    _('Add centroids'),
+    _('Adds missing centroids to closed boundaries.'),
+    _('Manage colors'),
+    _('Color tables'),
+    _('Creates/modifies the color table associated with a vector map.'),
+    _('Manage color rules interactively'),
+    _('Interactive management of vector color tables.'),
+    _('Export color table'),
+    _('Exports the color table associated with a vector map.'),
+    _('Query vector map'),
+    _('Query with coordinate(s)'),
+    _('Queries a vector map at given locations.'),
+    _('Query vector attribute data'),
+    _('Prints vector map attributes.'),
+    _('Feature selection'),
+    _('Select by attributes'),
+    _('Selects vector features from an existing vector map and creates a new vector map containing only the selected features.'),
+    _('Select by another map'),
+    _('Selects features from vector map (A) by features from other vector map (B).'),
+    _('Map type conversions'),
+    _('Vector to raster'),
+    _('Converts (rasterize) a vector map into a raster map.'),
+    _('Vector to 3D raster'),
+    _('Converts a vector map (only points) into a 3D raster map.'),
+    _('2D vector to 3D vector'),
+    _('Performs transformation of 2D vector features to 3D.'),
+    _('Buffer vectors'),
+    _('Creates a buffer around vector features of given type.'),
+    _('Point analysis'),
+    _('Identify and remove outliers'),
+    _('Removes outliers from vector point data.'),
+    _('Identify point clusters'),
+    _('Performs cluster identification.'),
+    _('Indices for quadrat counts of vector point lists'),
+    _('Indices for quadrat counts of vector point lists.'),
+    _('Perturb points'),
+    _('Random location perturbations of vector points.'),
+    _('Test/training point sets'),
+    _('Randomly partition points into test/train sets.'),
+    _('Tests for normality for vector points'),
+    _('Tests for normality for vector points.'),
+    _('Lidar analysis'),
+    _('Identify and remove outliers'),
+    _('Removes outliers from vector point data.'),
+    _('Detect edges'),
+    _("Detects the object's edges from a LIDAR data set."),
+    _('Detect interiors'),
+    _('Building contour determination and Region Growing algorithm for determining the building inside'),
+    _('Correct and reclassify objects'),
+    _('Corrects the v.lidar.growing output. It is the last of the three algorithms for LIDAR filtering.'),
+    _('Linear referencing'),
+    _('Create LRS'),
+    _('Creates a linear reference system.'),
+    _('Create stationing'),
+    _('Creates stationing from input lines, and linear reference system.'),
+    _('Create points/segments'),
+    _('Creates points/segments from input lines, linear reference system and positions read from stdin or a file.'),
+    _('Find line id and offset'),
+    _('Finds line id and real km+offset for given points in vector map using linear reference system.'),
+    _('Nearest features'),
+    _("Finds the nearest element in vector map 'to' for elements in vector map 'from'."),
+    _('Network analysis'),
+    _('Vector network analysis tool'),
+    _('Tool for interactive vector network analysis.'),
+    _('Network preparation'),
+    _('Performs network maintenance.'),
+    _('Allocate subnets'),
+    _('Allocates subnets for nearest centers (direction from center). center node must be opened (costs >= 0). Costs of center node are used in calculation'),
+    _('Split net'),
+    _('Splits net by cost isolines. Splits net to bands between cost isolines (direction from center). Center node must be opened (costs >= 0). Costs of center node are used in calculation.'),
+    _('Shortest path'),
+    _('Finds shortest path on vector network.'),
+    _('Shortest path for sets of features'),
+    _("Computes shortest distance via the network between the given sets of features. Finds the shortest paths from each 'from' point to the nearest 'to' feature and various information about this relation are uploaded to the attribute table."),
+    _('Shortest path using timetables'),
+    _('Finds shortest path using timetables.'),
+    _('Shortest path for all pairs'),
+    _('Computes the shortest path between all pairs of nodes in the network.'),
+    _('Visibility network'),
+    _('Performs visibility graph construction.'),
+    _('Bridges and articulation points'),
+    _('Computes bridges and articulation points in the network.'),
+    _('Maximum flow'),
+    _('Computes the maximum flow between two sets of nodes in the network.'),
+    _('Vertex connectivity'),
+    _('Computes vertex connectivity between two sets of nodes in the network.'),
+    _('Components'),
+    _('Computes strongly and weakly connected components in the network.'),
+    _('Centrality'),
+    _('Computes degree, centrality, betweeness, closeness and eigenvector centrality measures in the network.'),
+    _('Steiner tree'),
+    _("Creates Steiner tree for the network and given terminals. Note that 'Minimum Steiner Tree' problem is NP-hard and heuristic algorithm is used in this module so the result may be sub optimal."),
+    _('Minimum spanning tree'),
+    _('Computes minimum spanning tree for the network.'),
+    _('Traveling salesman analysis'),
+    _('Creates a cycle connecting given nodes (Traveling salesman problem). Note that TSP is NP-hard, heuristic algorithm is used by this module and created cycle may be sub optimal'),
+    _('Overlay vector maps'),
+    _('Overlay vector maps'),
+    _('Overlays two vector maps offering clip, intersection, difference, symmetrical difference, union operators.'),
+    _('Patch vector maps'),
+    _('Creates a new vector map by combining other vector maps.'),
+    _('Manage categories'),
+    _('Change or report categories'),
+    _('Attaches, deletes or reports vector categories to map geometry.'),
+    _('Reclassify'),
+    _('Changes vector category values for an existing vector map according to results of SQL queries or a value in attribute table column.'),
+    _('Update attributes'),
+    _('Update area attributes from raster'),
+    _('Calculates univariate statistics from a raster map based on a vector map and uploads statistics to new attribute columns.'),
+    _('Update area attributes from vector'),
+    _('Count points in areas, calculate statistics from point attributes.'),
+    _('Update point attributes from areas'),
+    _('Uploads vector values at positions of vector points to the table.'),
+    _('Update database values from vector'),
+    _('Populates attribute values from vector features.'),
+    _('Sample raster maps at point locations'),
+    _('Uploads raster values at positions of vector points to the table.'),
+    _('Sample raster neighborhood around points'),
+    _('Samples a raster map at vector point locations.'),
+    _('Generate area for current region'),
+    _('Creates a vector polygon from the current region extent.'),
+    _('Generate areas from points'),
+    _('Convex hull'),
+    _('Produces a 2D/3D convex hull for a given vector map.'),
+    _('Delaunay triangles'),
+    _('Creates a Delaunay triangulation from an input vector map containing points or centroids.'),
+    _('Voronoi diagram/Thiessen polygons'),
+    _('Creates a Voronoi diagram in current region from an input vector map containing points or centroids.'),
+    _('Generate grid'),
+    _('Creates a vector map of a user-defined grid.'),
+    _('Generate points'),
+    _('Generate from database'),
+    _('Creates new vector (points) map from database table containing coordinates.'),
+    _('Generate points along lines'),
+    _('Creates points along input lines in new vector map with 2 layers.'),
+    _('Generate random points'),
+    _('Generates random 2D/3D vector points.'),
+    _('Perturb points'),
+    _('Random location perturbations of vector points.'),
+    _('Remove outliers in point sets'),
+    _('Removes outliers from vector point data.'),
+    _('Test/training point sets'),
+    _('Randomly partition points into test/train sets.'),
+    _('Reports and statistics'),
+    _('Basic vector metadata'),
+    _('Outputs basic information about a vector map.'),
+    _('Classify attribute data'),
+    _('Classifies attribute data, e.g. for thematic mapping'),
+    _('Report topology by category'),
+    _('Reports geometry statistics for vector maps.'),
+    _('Univariate attribute statistics for points'),
+    _('Calculates univariate statistics of vector map features. Variance and standard deviation is calculated only for points if specified.'),
+    _('Univariate statistics for attribute columns'),
+    _('Calculates univariate statistics on selected table column for a GRASS vector map.'),
+    _('Quadrat indices'),
+    _('Indices for quadrat counts of vector point lists.'),
+    _('Test normality'),
+    _('Tests for normality for vector points.'),
+    _('&Imagery'),
+    _('Develop images and groups'),
+    _('Create/edit group'),
+    _('Creates, edits, and lists groups of imagery files.'),
+    _('Target group'),
+    _('Targets an imagery group to a GRASS location and mapset.'),
+    _('Mosaic images'),
+    _('Mosaics several images and extends colormap.'),
+    _('Manage image colors'),
+    _('Color balance for RGB'),
+    _('Performs auto-balancing of colors for RGB images.'),
+    _('HIS to RGB'),
+    _('Transforms raster maps from HIS (Hue-Intensity-Saturation) color space to RGB (Red-Green-Blue) color space.'),
+    _('RGB to HIS'),
+    _('Transforms raster maps from RGB (Red-Green-Blue) color space to HIS (Hue-Intensity-Saturation) color space.'),
+    _('Rectify image or raster'),
+    _('Rectifies an image by computing a coordinate transformation for each pixel in the image based on the control points.'),
+    _('Histogram'),
+    _('Generate histogram of image'),
+    _('Spectral response'),
+    _('Displays spectral response at user specified locations in group or images.'),
+    _('Pan sharpening'),
+    _('Image fusion algorithms to sharpen multispectral with high-res panchromatic channels'),
+    _('Classify image'),
+    _('Clustering input for unsupervised classification'),
+    _('Generates spectral signatures for land cover types in an image using a clustering algorithm. The resulting signature file is used as input for i.maxlik, to generate an unsupervised image classification.'),
+    _('Input for supervised MLC'),
+    _('Generates statistics for i.maxlik from raster map.'),
+    _('Maximum likelihood classification (MLC)'),
+    _('Classifies the cell spectral reflectances in imagery data. Classification is based on the spectral signature information generated by either i.cluster, g.gui.iclass, or i.gensig.'),
+    _('Interactive input for supervised classification'),
+    _('Generates spectral signatures by allowing the user to outline training areas.'),
+    _('Input for supervised SMAP'),
+    _('Generates statistics for i.smap from raster map.'),
+    _('Sequential maximum a posteriori classification (SMAP)'),
+    _('Performs contextual image classification using sequential maximum a posteriori (SMAP) estimation.'),
+    _('Object segmentation'),
+    _('Identifies segments (objects) from imagery data.'),
+    _('Filter image'),
+    _('Edge detection'),
+    _('Zero-crossing "edge detection" raster function for image processing.'),
+    _('Matrix/convolving filter'),
+    _('Performs raster map matrix filter.'),
+    _('Transform image'),
+    _('Canonical correlation'),
+    _('Canonical components analysis (CCA) program for image processing.'),
+    _('Principal components'),
+    _('Principal components analysis (PCA) for image processing.'),
+    _('Fast Fourier'),
+    _('Fast Fourier Transform (FFT) for image processing.'),
+    _('Inverse Fast Fourier'),
+    _('Inverse Fast Fourier Transform (IFFT) for image processing.'),
+    _('Satellite images tools'),
+    _('Aster DN to radiance/reflectance'),
+    _('Calculates Top of Atmosphere Radiance/Reflectance/Brightness Temperature from ASTER DN.'),
+    _('Landsat DN to radiance/reflectance'),
+    _('Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI'),
+    _('Landsat cloud cover assessment'),
+    _('Performs Landsat TM/ETM+ Automatic Cloud Cover Assessment (ACCA).'),
+    _('Modis quality control'),
+    _('Extracts quality control parameters from MODIS QC layers.'),
+    _('Atmospheric correction'),
+    _('Performs atmospheric correction using the 6S algorithm. 6S - Second Simulation of Satellite Signal in the Solar Spectrum.'),
+    _('Topographic correction'),
+    _('Computes topographic correction of reflectance.'),
+    _('Satellite images products'),
+    _('Vegetation indices'),
+    _('Calculates different types of vegetation indices. Uses red and nir bands mostly, and some indices require additional bands.'),
+    _('Tasseled cap vegetation index'),
+    _('Performs Tasseled Cap (Kauth Thomas) transformation.'),
+    _('Albedo'),
+    _('Computes broad band albedo from surface reflectance.'),
+    _('Emissivity'),
+    _('Computes emissivity from NDVI, generic method for sparse land.'),
+    _('Biomass growth'),
+    _('Computes biomass growth, precursor of crop yield calculation.'),
+    _('Evapotranspiration calculation'),
+    _('Instantaneaous Net Radiation'),
+    _('Net radiation approximation (Bastiaanssen, 1995).'),
+    _('Soil heat flux'),
+    _('Soil heat flux approximation (Bastiaanssen, 1995).'),
+    _('Sensible heat flux'),
+    _('Computes sensible heat flux iteration SEBAL 01.'),
+    _('Evaporative fraction'),
+    _('Computes evaporative fraction and root zone soil moisture.'),
+    _('Actual Evapotranspiration'),
+    _('Actual evapotranspiration for diurnal period (Bastiaanssen, 1995).'),
+    _('Temporal integration of ETa'),
+    _('Computes temporal integration of satellite ET actual (ETa) following the daily ET reference (ETo) from meteorological station(s).'),
+    _('Hargreaves methods Evapotranspiration'),
+    _('Computes evapotranspiration calculation modified or original Hargreaves formulation, 2001.'),
+    _('Penman-Monteith Evapotranspiration'),
+    _('Computes potential evapotranspiration calculation with hourly Penman-Monteith.'),
+    _('Priestley-Taylor Evapotranspiration'),
+    _('Computes evapotranspiration calculation Priestley and Taylor formulation, 1972.'),
+    _('Reports and statistics'),
+    _('Kappa analysis'),
+    _('Calculates error matrix and kappa parameter for accuracy assessment of classification result.'),
+    _('OIF for LandSat TM'),
+    _('Calculates Optimum-Index-Factor table for spectral bands'),
+    _('3D r&aster'),
+    _('Develop 3D raster map'),
+    _('Manage 3D NULL values'),
+    _('Explicitly create the 3D NULL-value bitmap file.'),
+    _('Manage timestamp'),
+    _('Modifies a timestamp for a 3D raster map. Print/add/remove a timestamp for a 3D raster map.'),
+    _('Map type conversions'),
+    _('3D rasters to raster series'),
+    _('Converts 3D raster maps to 2D raster maps'),
+    _('3D color tables'),
+    _('Creates/modifies the color table associated with a 3D raster map.'),
+    _('Export 3D color table'),
+    _('Exports the color table associated with a 3D raster map.'),
+    _('3D mask'),
+    _('Establishes the current working 3D raster mask.'),
+    _('3D raster map calculator'),
+    _('3D raster map calculator'),
+    _('Cross section'),
+    _('Creates cross section 2D raster map from 3D raster map based on 2D elevation map'),
+    _('Groundwater modeling'),
+    _('Numerical calculation program for transient, confined groundwater flow in three dimensions.'),
+    _('Interpolate 3D raster from points'),
+    _('Interpolates point data to a 3D raster map using regularized spline with tension (RST) algorithm.'),
+    _('Reports and Statistics'),
+    _('Basic 3D raster metadata'),
+    _('Outputs basic information about a user-specified 3D raster map layer.'),
+    _('3D raster statistics'),
+    _('Generates volume statistics for 3D raster maps.'),
+    _('Univariate statistics for 3D rasters'),
+    _('Calculates univariate statistics from the non-null cells of a 3D raster map. Statistics include number of cells counted, minimum and maximum cell values, range, arithmetic mean, population variance, standard deviation, coefficient of variation, and sum.'),
+    _('&Database'),
+    _('Database information'),
+    _('List databases'),
+    _('Lists all databases for a given driver and location.'),
+    _('List drivers'),
+    _('Lists all database drivers.'),
+    _('List tables'),
+    _('Lists all tables for a given database.'),
+    _('Describe table'),
+    _('Describes a table in detail.'),
+    _('List columns'),
+    _('List all columns for a given table.'),
+    _('Manage databases'),
+    _('Connect'),
+    _('Prints/sets general DB connection for current mapset.'),
+    _('Login'),
+    _('Sets user/password for DB driver/database.'),
+    _('Create database'),
+    _('Creates an empty database.'),
+    _('Drop database'),
+    _('Removes an existing database.'),
+    _('Drop table'),
+    _('Drops an attribute table.'),
+    _('Copy table'),
+    _("Copy a table. Either 'from_table' (optionally with 'where') can be used or 'select' option, but not 'from_table' and 'select' at the same time."),
+    _('Drop column'),
+    _('Drops a column from selected attribute table.'),
+    _('Test'),
+    _('Test database driver, database must exist and set by db.connect.'),
+    _('Query'),
+    _('Query any table'),
+    _('Selects data from attribute table. Performs SQL query statement(s).'),
+    _('Query vector attribute data'),
+    _('Prints vector map attributes.'),
+    _('SQL statement'),
+    _("Executes any SQL statement. For SELECT statements use 'db.select'."),
+    _('Vector database connections'),
+    _('New table'),
+    _('Creates and connects a new attribute table to a given layer of an existing vector map.'),
+    _('Remove table'),
+    _('Removes existing attribute table of a vector map.'),
+    _('Join table'),
+    _('Joins a database table to a vector map table.'),
+    _('Add columns'),
+    _('Adds one or more columns to the attribute table connected to a given vector map.'),
+    _('Drop column'),
+    _('Drops a column from the attribute table connected to a given vector map.'),
+    _('Rename column'),
+    _('Renames a column in the attribute table connected to a given vector map.'),
+    _('Change values'),
+    _('Updates a column in the attribute table connected to a vector map.'),
+    _('Drop row'),
+    _('Removes a vector feature from a vector map through attribute selection.'),
+    _('Reconnect vectors to database'),
+    _('Reconnects attribute tables for all vector maps from the current mapset to a new database.'),
+    _('Set vector map - database connection'),
+    _('Prints/sets DB connection for a vector map to attribute table.'),
+    _('&Temporal'),
+    _('Manage datasets'),
+    _('Connect temporal database'),
+    _('Prints/sets general temporal GIS database connection for current mapset.'),
+    _('Create'),
+    _('Creates a space time dataset.'),
+    _('Rename'),
+    _('Renames a space time dataset'),
+    _('Remove'),
+    _('Removes space time datasets from temporal database.'),
+    _('Update metadata'),
+    _('Modifies the metadata of a space time dataset.'),
+    _('Merge'),
+    _('Merges several space time datasets into a single space time dataset.'),
+    _('Temporally shift'),
+    _('Shifts temporally the maps of a space time dataset.'),
+    _('Snap maps of dataset'),
+    _('Snaps temporally the maps of a space time dataset.'),
+    _('List'),
+    _('Lists space time datasets and maps registered in the temporal database.'),
+    _('Manage maps in datasets'),
+    _('Register maps in datasets'),
+    _('Registers raster, vector and raster3d maps in a space time datasets.'),
+    _('Unregister maps from datasets'),
+    _('Unregisters raster, vector and raster3d maps from the temporal database or a specific space time dataset.'),
+    _('List raster dataset maps'),
+    _('Lists registered maps of a space time raster dataset.'),
+    _('List vector dataset maps'),
+    _('Lists registered maps of a space time vector dataset.'),
+    _('List 3D raster dataset maps'),
+    _('Lists registered maps of a space time raster3d dataset.'),
+    _('Import'),
+    _('Import raster dataset'),
+    _('Imports space time raster dataset.'),
+    _('Import vector dataset'),
+    _('Imports a space time vector dataset from a GRASS GIS specific archive file.'),
+    _('Export'),
+    _('Export raster dataset'),
+    _('Exports space time raster dataset.'),
+    _('Export raster dataset as VTK time series'),
+    _('Exports space time raster dataset as VTK time series.'),
+    _('Export vector dataset'),
+    _('Exports a space time vector dataset as GRASS GIS specific archive file.'),
+    _('Convert raster dataset to 3D raster'),
+    _('Converts a space time raster dataset into a 3D raster map.'),
+    _('Extraction'),
+    _('Extract subset of raster dataset'),
+    _('Extracts a subset of a space time raster datasets.'),
+    _('Extract subset of vector dataset'),
+    _('Extracts a subset of a space time vector dataset.'),
+    _('Extract subset of 3D raster dataset'),
+    _('Extracts a subset of a space time 3D raster dataset.'),
+    _('Query vector dataset attribute data'),
+    _('Prints attributes of vector maps registered in a space time vector dataset.'),
+    _('Raster dataset color table'),
+    _('Creates/modifies the color table associated with each raster map of the space time raster dataset.'),
+    _('Raster calculations'),
+    _('Performs spatio-temporal mapcalc expressions on temporally sampled maps of space time raster datasets.'),
+    _('3D raster calculations'),
+    _('Performs r3.mapcalc expressions on maps of sampled space time 3D raster datasets.'),
+    _('Interpolate gaps in raster datasets'),
+    _('Replaces gaps in a space time raster dataset with interpolated raster maps.'),
+    _('Aggregation'),
+    _('Neighborhood analysis in raster dataset'),
+    _('Performs a neighborhood analysis for each map in a space time raster dataset.'),
+    _('Aggregation in raster datasets'),
+    _('Performs different aggregation algorithms from r.series on all or a subset of raster maps in a space time raster dataset.'),
+    _('Temporal aggregation'),
+    _('Aggregates temporally the maps of a space time raster dataset by a user defined granularity.'),
+    _('Temporal aggregation by dataset'),
+    _('Aggregates data of an existing space time raster dataset using the time intervals of a second space time dataset.'),
+    _('Sampling'),
+    _('Sample a space time raster dataset at point coordinates'),
+    _('Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts'),
+    _('Query raster dataset by vector points dataset'),
+    _('Stores raster map values at spatial and temporal positions of vector points as vector attributes.'),
+    _('Observe specific locations in raster dataset'),
+    _('Observes specific locations in a space time raster dataset over a period of time using vector points.'),
+    _('Temporal sampling'),
+    _('Samples the input space time dataset(s) with a sample space time dataset and print the result to stdout.'),
+    _('Reports and statistics'),
+    _('Space time datasets metadata'),
+    _('Lists information about space time datasets and maps.'),
+    _('Univariate raster dataset statistics'),
+    _('Calculates univariate statistics from the non-null cells for each registered raster map of a space time raster dataset.'),
+    _('Univariate vector dataset statistics'),
+    _('Calculates univariate statistics of attributes for each registered vector map of a space time vector dataset'),
+    _('Univariate 3D raster dataset statistics'),
+    _('Calculates univariate statistics from the non-null cells for each registered 3D raster map of a space time 3D raster dataset.'),
+    _('Report temporal topology'),
+    _('Lists temporal topology of a space time dataset.'),
+    _('GUI tools'),
+    _('Animation tool'),
+    _('Launch animation tool.'),
+    _('Timeline tool'),
+    _('Plot temporal extents.'),
+    _('Temporal plot tool'),
+    _('Plot temporal values.'),
+    _('&Help'),
+    _('GRASS help'),
+    _('Display the HTML man pages of GRASS GIS'),
+    _('GUI help'),
+    _('Display the HTML man pages of GRASS GIS'),
+    _('About system'),
+    _('Prints system information'),
+    _('About GRASS GIS'),
+    _('About GRASS GIS'),
+    '']
+menustrings_menudata.LayerManagerModuleTree = [
+    _('Import, export and link data'),
+    _('Import raster data'),
+    _('Common formats import'),
+    _('Imports raster data into a GRASS raster map using GDAL library.'),
+    _('Import of common formats with reprojection'),
+    _('Imports raster data into a GRASS raster map using GDAL library and reprojects on the fly.'),
+    _('ASCII x,y,z point import and gridding'),
+    _('Creates a raster map from an assemblage of many coordinates using univariate statistics.'),
+    _('ASCII grid import'),
+    _('Converts a GRASS ASCII raster file to binary raster map.'),
+    _('ASCII polygons, lines, and point import'),
+    _('Creates raster maps from ASCII polygon/line/point data files.'),
+    _('Raw binary array import'),
+    _('Import a binary raster file into a GRASS raster map layer.'),
+    _('GRIDATB.FOR import'),
+    _('Imports GRIDATB.FOR map file (TOPMODEL) into a GRASS raster map.'),
+    _('Matlab 2D array import'),
+    _('Imports a binary MAT-File(v4) to a GRASS raster.'),
+    _('PNG import'),
+    _('Imports non-georeferenced PNG format image.'),
+    _('SPOT NDVI import'),
+    _('Imports SPOT VGT NDVI data into a raster map.'),
+    _('SRTM HGT import'),
+    _('Imports SRTM HGT files into raster map.'),
+    _('Terra ASTER HDF import'),
+    _('Georeference, rectify, and import Terra-ASTER imagery and relative DEMs using gdalwarp.'),
+    _('LAS LiDAR points import'),
+    _('Unpack raster map'),
+    _('Imports a raster map as GRASS GIS specific archive file (packed with r.pack)'),
+    _('Reproject raster map from different GRASS location'),
+    _('Re-projects a raster map from given location to the current location.'),
+    _('Import vector data'),
+    _('Common import formats'),
+    _('Imports vector data into a GRASS vector map using OGR library.'),
+    _('Import of common formats with reprojection'),
+    _('Imports vector data into a GRASS vector map using OGR library and reprojects on the fly.'),
+    _('ASCII points or GRASS ASCII format'),
+    _('Creates a vector map from an ASCII points file or ASCII vector file.'),
+    _('ASCII points as a vector lines'),
+    _('Imports ASCII x,y[,z] coordinates as a series of lines.'),
+    _('DXF import'),
+    _('Converts files in DXF format to GRASS vector map format.'),
+    _('WFS'),
+    _('Imports GetFeature from a WFS server.'),
+    _('ESRI e00 import'),
+    _('Imports E00 file into a vector map.'),
+    _('Geonames import'),
+    _('Imports geonames.org country files into a vector points map.'),
+    _('Matlab array or Mapgen format import'),
+    _('Imports Mapgen or Matlab-ASCII vector maps into GRASS.'),
+    _('LAS LiDAR points import'),
+    _('Unpack vector map'),
+    _('Imports a vector map as GRASS GIS specific archive file (packed with v.pack)'),
+    _('Reproject vector map from different GRASS location'),
+    _('Re-projects a vector map from one location to the current location.'),
+    _('Import 3D raster data'),
+    _('ASCII 3D import'),
+    _('Converts a 3D ASCII raster text file into a (binary) 3D raster map.'),
+    _('Raw binary array 3D import'),
+    _('Imports a binary raster file into a GRASS 3D raster map.'),
+    _('Vis5D import'),
+    _('Import 3-dimensional Vis5D files.'),
+    _('Import database table'),
+    _('Common import formats'),
+    _('Imports attribute tables in various formats.'),
+    _('Export raster map'),
+    _('Common export formats'),
+    _('Exports GRASS raster maps into GDAL supported formats.'),
+    _('ASCII grid export'),
+    _('Converts a raster map layer into a GRASS ASCII text file.'),
+    _('ASCII x,y,z points export'),
+    _('Exports a raster map to a text file as x,y,z values based on cell centers.'),
+    _('GRIDATB.FOR export'),
+    _('Exports GRASS raster map to GRIDATB.FOR map file (TOPMODEL).'),
+    _('Matlab 2D array export'),
+    _('Exports a GRASS raster to a binary MAT-File.'),
+    _('Raw binary array export'),
+    _('Exports a GRASS raster to a binary array.'),
+    _('MPEG-1 export'),
+    _('Converts raster map series to MPEG movie.'),
+    _('PNG export'),
+    _('Export a GRASS raster map as a non-georeferenced PNG image.'),
+    _('PPM export'),
+    _('Converts a GRASS raster map to a PPM image file.'),
+    _('PPM from RGB export'),
+    _('Converts 3 GRASS raster layers (R,G,B) to a PPM image file.'),
+    _('POV-Ray export'),
+    _('Converts a raster map layer into a height-field file for POV-Ray.'),
+    _('VRML export'),
+    _('Exports a raster map to the Virtual Reality Modeling Language (VRML).'),
+    _('VTK export'),
+    _('Converts raster maps into the VTK-ASCII format.'),
+    _('Pack raster map'),
+    _('Exports a raster map as GRASS GIS specific archive file'),
+    _('Export vector map'),
+    _('Common export formats'),
+    _('Exports a vector map layer to any of the supported OGR vector formats. By default a vector map layer is exported to Esri Shapefile format.'),
+    _('ASCII points or GRASS ASCII vector export'),
+    _("Exports a vector map to a GRASS ASCII vector representation. By default only features with category are exported. To export all features use 'layer=-1'."),
+    _('DXF export'),
+    _('Exports vector map to DXF file format.'),
+    _('PostGIS export'),
+    _('POV-Ray export'),
+    _('Converts GRASS x,y,z points to POV-Ray x,z,y format.'),
+    _('SVG export'),
+    _('Exports a vector map to SVG file.'),
+    _('VTK export'),
+    _('Converts a vector map to VTK ASCII output.'),
+    _('Pack vector map'),
+    _('Exports a vector map as GRASS GIS specific archive file'),
+    _('Export 3D raster maps'),
+    _('ASCII 3D export'),
+    _('Converts a 3D raster map layer into a ASCII text file.'),
+    _('Raw binary array 3D export'),
+    _('Exports a GRASS 3D raster map to a binary array.'),
+    _('Vis5D export'),
+    _('Exports GRASS 3D raster map to 3-dimensional Vis5D file.'),
+    _('VTK export'),
+    _('Converts 3D raster maps into the VTK-ASCII format.'),
+    _('Export database table'),
+    _('Common export formats'),
+    _('Exports attribute tables into various formats.'),
+    _('Link external data'),
+    _('Link external raster data'),
+    _('Link GDAL supported raster data as a pseudo GRASS raster map layer.'),
+    _('Link external vector data'),
+    _('Creates a new pseudo-vector map as a link to an OGR-supported layer.'),
+    _('Output format for raster data'),
+    _('Redirects raster output to file utilizing GDAL library rather than storing in GRASS raster format.'),
+    _('Output format for vector data'),
+    _('Defines vector output format utilizing OGR library.'),
+    _('Manage maps'),
+    _('Copy'),
+    _("Copies available data files in the current mapset search path to the user's current mapset."),
+    _('List'),
+    _('Lists available GRASS data base files of the user-specified data type optionally using the search pattern.'),
+    _('Rename'),
+    _("Renames data base element files in the user's current mapset."),
+    _('Delete'),
+    _("Removes data base element files from the user's current mapset using the search pattern."),
+    _('Computational region'),
+    _('Show current region'),
+    _('Shows the extent and resolution of the computational region.'),
+    _('Show region using latitude and longitude'),
+    _('Shows the extent and resolution of the computational region.'),
+    _('Set region'),
+    _('Manages the boundary definitions for the geographic region.'),
+    _('&Raster'),
+    _('Develop raster map'),
+    _('Compress/decompress'),
+    _('Compresses and decompresses raster maps.'),
+    _('Region boundaries'),
+    _('Sets the boundary definitions for a raster map.'),
+    _('Manage NULL values'),
+    _('Manages NULL-values of given raster map.'),
+    _('Quantization'),
+    _('Produces the quantization file for a floating-point map.'),
+    _('Timestamp'),
+    _('Modifies a timestamp for a raster map. Print/add/remove a timestamp for a raster map.'),
+    _('Resample using aggregate statistics'),
+    _('Resamples raster map layers to a coarser grid using aggregation.'),
+    _('Resample using multiple methods'),
+    _('Resamples raster map to a finer grid using interpolation.'),
+    _('Resample using nearest neighbor'),
+    _('GRASS raster map layer data resampling capability.'),
+    _('Resample using spline tension'),
+    _('Reinterpolates and optionally computes topographic analysis from input raster map to a new raster map (possibly with different resolution) using regularized spline with tension and smoothing.'),
+    _('Resample using bspline'),
+    _('Performs bilinear or bicubic spline interpolation with Tykhonov regularization.'),
+    _('Resample using analytic kernel'),
+    _('Resamples raster map layers using an analytic kernel.'),
+    _('Support file maintenance'),
+    _('Allows creation and/or modification of raster map layer support files.'),
+    _('Update map statistics'),
+    _('Update raster map statistics'),
+    _('Reproject raster map from different GRASS location'),
+    _('Re-projects a raster map from given location to the current location.'),
+    _('Tiling'),
+    _('Produces tilings of the source projection for use in the destination region and projection.'),
+    _('Manage colors'),
+    _('Color tables'),
+    _('Creates/modifies the color table associated with a raster map.'),
+    _('Color tables (stddev)'),
+    _("Sets color rules based on stddev from a raster map's mean value."),
+    _('Manage color rules interactively'),
+    _('Interactive management of raster color tables.'),
+    _('Export color table'),
+    _('Exports the color table associated with a raster map.'),
+    _('Blend 2 color rasters'),
+    _('Blends color components of two raster maps by a given ratio.'),
+    _('Create RGB'),
+    _('Combines red, green and blue raster maps into a single composite raster map.'),
+    _('RGB to HIS'),
+    _('Generates red, green and blue (RGB) raster map layers combining hue, intensity and saturation (HIS) values from user-specified input raster map layers.'),
+    _('Query raster maps'),
+    _('Query values by coordinates'),
+    _('Queries raster maps on their category values and category labels.'),
+    _('Query colors by value'),
+    _('Queries colors for a raster map layer.'),
+    _('Map type conversions'),
+    _('Raster to vector'),
+    _('Converts a raster map into a vector map.'),
+    _('Raster series to 3D raster'),
+    _('Converts 2D raster map slices to one 3D raster volume map.'),
+    _('Raster 2.5D to 3D raster'),
+    _('Creates a 3D volume map based on 2D elevation and value raster maps.'),
+    _('Raster buffers and distance'),
+    _('Buffer rasters'),
+    _('Creates a raster map showing buffer zones surrounding cells that contain non-NULL category values.'),
+    _('Concentric circles'),
+    _('Creates a raster map containing concentric rings around a given point.'),
+    _('Closest points'),
+    _('Locates the closest points between objects in two raster maps.'),
+    _('Grow by one cell'),
+    _('Generates a raster map layer with contiguous areas grown by one cell.'),
+    _('Distance to features'),
+    _('Generates a raster map containing distances to nearest raster features.'),
+    _('Mask'),
+    _('Creates a MASK for limiting raster operation.'),
+    _('Raster map calculator'),
+    _('Raster map calculator'),
+    _('Neighborhood analysis'),
+    _('Moving window'),
+    _('Makes each cell category value a function of the category values assigned to the cells around it, and stores new cell values in an output raster map layer.'),
+    _('Neighborhood points'),
+    _('Neighborhood analysis tool for vector point maps. Makes each cell value a function of the attribute values assigned to the vector points or centroids around it, and stores new cell values in an output raster map.'),
+    _('Overlay rasters'),
+    _('Cross product'),
+    _('Creates a cross product of the category values from multiple raster map layers.'),
+    _('Patch raster maps'),
+    _('Creates a composite raster map layer by using known category values from one (or more) map layer(s) to fill in areas of "no data" in another map layer.'),
+    _('Raster series aggregation'),
+    _('Makes each output cell value a function of the values assigned to the corresponding cells in the input raster map layers.'),
+    _('Raster series accumulation'),
+    _('Makes each output cell value a accumulationfunction of the values assigned to the corresponding cells in the input raster map layers.'),
+    _('Statistical overlay'),
+    _('Calculates category or object oriented statistics (accumulator-based statistics).'),
+    _('Quantiles overlay'),
+    _('Compute category quantiles using two passes.'),
+    _('Solar radiance and shadows'),
+    _('LatLong map'),
+    _('Creates a latitude/longitude raster map.'),
+    _('Solar irradiance and irradiation'),
+    _('Solar irradiance and irradiation model. Computes direct (beam), diffuse and reflected solar irradiation raster maps for given day, latitude, surface and atmospheric conditions. Solar parameters (e.g. sunrise, sunset times, declination, extraterrestrial irradiance, daylight length) are saved in the map history file. Alternatively, a local time can be specified to compute solar incidence angle and/or irradiance raster maps. The shadowing effect of the topography is optionally incorporated.'),
+    _('Shadows map'),
+    _('Calculates cast shadow areas from sun position and elevation raster map. Either exact sun position (A) is specified, or date/time to calculate the sun position (B) by r.sunmask itself.'),
+    _('Sunshine hours and solar angles'),
+    _("Calculates solar elevation, solar azimuth, and sun hours. Solar elevation: the angle between the direction of the geometric center of the sun's apparent disk and the (idealized) horizon. Solar azimuth: the angle from due north in clockwise direction."),
+    _('Terrain analysis'),
+    _('Generate contour lines'),
+    _('Produces a vector map of specified contours from a raster map.'),
+    _('Cost surface'),
+    _('Creates a raster map showing the cumulative cost of moving between different geographic locations on an input raster map whose cell category values represent cost.'),
+    _('Cumulative movement costs'),
+    _('Creates a raster map showing the anisotropic cumulative cost of moving between different geographic locations on an input raster map whose cell category values represent cost.'),
+    _('Least cost route or flow'),
+    _('Traces a flow through an elevation model or cost surface on a raster map.'),
+    _('Compute shaded relief'),
+    _('Creates shaded relief map from an elevation map (DEM). '),
+    _('Apply shade to raster'),
+    _('Drapes a color raster over an shaded relief or aspect map.'),
+    _('Slope and aspect'),
+    _('Generates raster maps of slope, aspect, curvatures and partial derivatives from an elevation raster map. Aspect is calculated counterclockwise from east.'),
+    _('Terrain parameters'),
+    _('Extracts terrain parameters from a DEM. Uses a multi-scale approach by taking fitting quadratic parameters to any size window (via least squares).'),
+    _('Textural features'),
+    _('Generate images with textural features from a raster map.'),
+    _('Visibility'),
+    _('Computes the viewshed of a point on an elevation raster map. Default format: NULL (invisible), vertical angle wrt viewpoint (visible).'),
+    _('Distance to features'),
+    _('Generates a raster map containing distances to nearest raster features.'),
+    _('Horizon angle'),
+    _("Computes horizon angle height from a digital elevation model. The module has two different modes of operation: 1. Computes the entire horizon around a single point whose coordinates are given with the 'coord' option. The horizon height (in radians). 2. Computes one or more raster maps of the horizon height in a single direction. The input for this is the angle (in degrees), which is measured counterclockwise with east=0, north=90 etc. The output is the horizon height in radians."),
+    _('Transform features'),
+    _('Clump'),
+    _('Recategorizes data in a raster map by grouping cells that form physically discrete areas into unique categories.'),
+    _('Grow'),
+    _('Generates a raster map layer with contiguous areas grown by one cell.'),
+    _('Thin'),
+    _('Thins non-null cells that denote linear features in a raster map layer.'),
+    _('Hydrologic modeling'),
+    _('Carve stream channels'),
+    _('Generates stream channels. Takes vector stream data, transforms it to raster and subtracts depth from the output DEM.'),
+    _('Fill lake'),
+    _('Fills lake at given point to given level.'),
+    _('Depressionless map and flowlines'),
+    _('Filters and generates a depressionless elevation map and a flow direction map from a given elevation raster map.'),
+    _('Flow accumulation'),
+    _('Performs flow computation for massive grids.'),
+    _('Flow lines'),
+    _('Constructs flowlines. Computes flowlines, flowpath lengths, and flowaccumulation (contributing areas) from a elevation raster map.'),
+    _('Watershed analysis'),
+    _('Calculates hydrological parameters and RUSLE factors.'),
+    _('Watershed subbasins'),
+    _('Generates watershed subbasins raster map.'),
+    _('Watershed basin creation'),
+    _('Creates watershed basins from a drainage direction map.'),
+    _('Extraction of stream networks'),
+    _('Performs stream network extraction.'),
+    _('SIMWE Overland flow modeling'),
+    _('Overland flow hydrologic simulation using path sampling method (SIMWE).'),
+    _('SIMWE Sediment flux modeling'),
+    _('Sediment transport and erosion/deposition simulation using path sampling method (SIMWE).'),
+    _('Topographic index map'),
+    _('Creates a topographic index (wetness index) raster map from an elevation raster map.'),
+    _('TOPMODEL simulation'),
+    _('Simulates TOPMODEL which is a physically based hydrologic model.'),
+    _('USLE K-factor'),
+    _('Computes USLE Soil Erodibility Factor (K).'),
+    _('USLE R-factor'),
+    _('Computes USLE R factor, Rainfall erosivity index.'),
+    _('Groundwater modeling'),
+    _('Groundwater flow'),
+    _('Numerical calculation program for transient, confined and unconfined groundwater flow in two dimensions.'),
+    _('Groundwater solute transport'),
+    _('Numerical calculation program for transient, confined and unconfined solute transport in two dimensions'),
+    _('Landscape patch analysis'),
+    _('Set up sampling and analysis framework'),
+    _("Configuration editor for r.li.'index'"),
+    _('Edge density'),
+    _('Calculates edge density index on a raster map, using a 4 neighbour algorithm'),
+    _('Contrast weighted edge density'),
+    _('Calculates contrast weighted edge density index on a raster map'),
+    _('Patch area mean'),
+    _('Calculates mean patch size index on a raster map, using a 4 neighbour algorithm'),
+    _('Patch area range'),
+    _('Calculates range of patch area size on a raster map'),
+    _('Patch area Std Dev'),
+    _('Calculates standard deviation of patch area a raster map'),
+    _('Patch area Coeff Var'),
+    _('Calculates coefficient of variation of patch area on a raster map'),
+    _('Patch density'),
+    _('Calculates patch density index on a raster map, using a 4 neighbour algorithm'),
+    _('Patch number'),
+    _('Calculates patch number index on a raster map, using a 4 neighbour algorithm.'),
+    _("Dominance's diversity"),
+    _("Calculates dominance's diversity index on a raster map"),
+    _("Shannon's diversity"),
+    _("Calculates Shannon's diversity index on a raster map"),
+    _("Simpson's diversity"),
+    _("Calculates Simpson's diversity index on a raster map"),
+    _('Richness'),
+    _('Calculates richness index on a raster map'),
+    _('Shape index'),
+    _('Calculates shape index on a raster map'),
+    _('Wildfire modeling'),
+    _('Rate of spread'),
+    _('Generates rate of spread raster maps. Generates three, or four raster map layers showing the base (perpendicular) rate of spread (ROS), the maximum (forward) ROS, the direction of the maximum ROS, and optionally the maximum potential spotting distance for fire spread simulation.'),
+    _('Least-cost spread paths'),
+    _('Recursively traces the least cost path backwards to cells from which the cumulative cost was determined.'),
+    _('Anisotropic spread simulation'),
+    _('Simulates elliptically anisotropic spread. Generates a raster map of the cumulative time of spread, given raster maps containing the rates of spread (ROS), the ROS directions and the spread origins. It optionally produces raster maps to contain backlink UTM coordinates for tracing spread paths. Usable for fire spread simulations.'),
+    _('Change category values and labels'),
+    _('Manage category information'),
+    _('Manages category values and labels associated with user-specified raster map layers.'),
+    _('Interactively edit category values'),
+    _('Edits cell values in a raster map.'),
+    _('Reclassify by size'),
+    _('Reclasses a raster map greater or less than user specified area size (in hectares).'),
+    _('Reclassify'),
+    _('Reclassify raster map based on category values. Creates a new raster map whose category values are based upon a reclassification of the categories in an existing raster map.'),
+    _('Recode'),
+    _('Recodes categorical raster maps.'),
+    _('Rescale'),
+    _('Rescales the range of category values in a raster map layer.'),
+    _('Rescale with histogram'),
+    _('Rescales histogram equalized the range of category values in a raster map layer.'),
+    _('Generate random cells'),
+    _('Random cells'),
+    _('Generates random cell values with spatial dependence.'),
+    _('Random cells and vector points'),
+    _('Creates a raster map layer and vector point map containing randomly located points.'),
+    _('Generate surfaces'),
+    _('Fractal surface'),
+    _('Creates a fractal surface of a given fractal dimension.'),
+    _('Gaussian kernel density surface'),
+    _('Generates a raster density map from vector points map. Density is computed using a moving kernel. Optionally generates a vector density map on a vector network.'),
+    _('Gaussian deviates surface'),
+    _('Generates a raster map using gaussian random number generator. Mean and standard deviation of gaussian deviates can be expressed by the user.'),
+    _('Plane'),
+    _('Creates raster plane map given dip (inclination), aspect (azimuth) and one point.'),
+    _('Random deviates surface'),
+    _('Produces a raster surface map of uniform random deviates with defined range.'),
+    _('Random surface with spatial dependence'),
+    _('Generates random surface(s) with spatial dependence.'),
+    _('Interpolate surfaces'),
+    _('Bilinear and bicubic from vector points'),
+    _('Performs bicubic or bilinear spline interpolation with Tykhonov regularization.'),
+    _('IDW from raster points'),
+    _('Provides surface interpolation from raster point data by Inverse Distance Squared Weighting.'),
+    _('IDW from vector points'),
+    _('Provides surface interpolation from vector point data by Inverse Distance Squared Weighting.'),
+    _('Raster contours'),
+    _('Generates surface raster map from rasterized contours.'),
+    _('Regularized spline tension'),
+    _('Performs surface interpolation from vector points map by splines. Spatial approximation and topographic analysis from given point or isoline data in vector format to floating point raster format using regularized spline with tension.'),
+    _('Raster series interpolation'),
+    _('Interpolates raster maps located (temporal or spatial) in between input raster maps at specific sampling positions.'),
+    _('Fill NULL cells'),
+    _('Fills no-data areas in raster maps using spline interpolation.'),
+    _('Reports and statistics'),
+    _('Basic raster metadata'),
+    _('Outputs basic information about a raster map.'),
+    _('Manage category information'),
+    _('Manages category values and labels associated with user-specified raster map layers.'),
+    _('General statistics'),
+    _('Generates area statistics for raster map.'),
+    _('Quantiles for large data sets'),
+    _('Compute quantiles using two passes.'),
+    _('Range of category values'),
+    _('Prints terse list of category values found in a raster map layer.'),
+    _('Sum area by raster map and category'),
+    _('Reports statistics for raster maps.'),
+    _('Statistics for clumped cells'),
+    _('Calculates the volume of data "clumps". Optionally produces a GRASS vector points map containing the calculated centroids of these clumps.'),
+    _('Total corrected area'),
+    _('Prints estimation of surface area for raster map.'),
+    _('Univariate raster statistics'),
+    _('Calculates univariate statistics from the non-null cells of a raster map. Statistics include number of cells counted, minimum and maximum cell values, range, arithmetic mean, population variance, standard deviation, coefficient of variation, and sum.'),
+    _('Sample transects'),
+    _('Outputs the raster map layer values lying on user-defined line(s).'),
+    _('Sample transects (bearing/distance)'),
+    _('Outputs raster map layer values lying along user defined transect line(s).'),
+    _('Covariance/correlation'),
+    _('Outputs a covariance/correlation matrix for user-specified raster map layer(s).'),
+    _('Linear regression'),
+    _('Calculates linear regression from two raster maps: y = a + b*x.'),
+    _('Multiple regression'),
+    _('Calculates multiple linear regression from raster maps.'),
+    _('Mutual category occurrences'),
+    _('Tabulates the mutual occurrence (coincidence) of categories for two raster map layers.'),
+    _('&Vector'),
+    _('Develop vector map'),
+    _('Create new vector map'),
+    _('Create new empty vector map'),
+    _('Edit vector map (non-interactively)'),
+    _('Edits a vector map, allows adding, deleting and modifying selected vector features.'),
+    _('Convert object types'),
+    _('Changes type of vector features.'),
+    _('Parallel lines'),
+    _('Creates parallel line to input vector lines.'),
+    _('Dissolve boundaries'),
+    _('Dissolves boundaries between adjacent areas sharing a common category number or attribute.'),
+    _('Create 3D vector over raster'),
+    _('Converts 2D vector features to 3D by sampling of elevation raster map.'),
+    _('Extrude 3D vector map'),
+    _('Extrudes flat vector features to 3D vector features with defined height. Optionally the height can be derived from sampling of elevation raster map.'),
+    _('Create labels'),
+    _('Creates paint labels for a vector map from attached attributes.'),
+    _('Reposition vector map'),
+    _('Performs an affine transformation (shift, scale and rotate) on vector map.'),
+    _('Rectify vector map'),
+    _('Rectifies a vector by computing a coordinate transformation for each object in the vector based on the control points.'),
+    _('Reproject vector map from different GRASS location'),
+    _('Re-projects a vector map from one location to the current location.'),
+    _('Support file maintenance'),
+    _('Updates vector map metadata.'),
+    _('Topology maintenance'),
+    _('Create or rebuild topology'),
+    _('Creates topology for vector map. Optionally also checks for topological errors.'),
+    _('Rebuild topology on all vector maps'),
+    _('Rebuilds topology on all vector maps in the current mapset.'),
+    _('Build polylines'),
+    _('Builds polylines from lines or boundaries.'),
+    _('Split lines'),
+    _('Splits vector lines to shorter segments.'),
+    _('Split polylines'),
+    _('Creates points/segments from input vector lines and positions.'),
+    _('Clean vector map'),
+    _('Toolset for cleaning topology of vector map.'),
+    _('Smooth or simplify'),
+    _('Performs vector based generalization.'),
+    _('Add centroids'),
+    _('Adds missing centroids to closed boundaries.'),
+    _('Manage colors'),
+    _('Color tables'),
+    _('Creates/modifies the color table associated with a vector map.'),
+    _('Manage color rules interactively'),
+    _('Interactive management of vector color tables.'),
+    _('Export color table'),
+    _('Exports the color table associated with a vector map.'),
+    _('Query vector map'),
+    _('Query with coordinate(s)'),
+    _('Queries a vector map at given locations.'),
+    _('Query vector attribute data'),
+    _('Prints vector map attributes.'),
+    _('Feature selection'),
+    _('Select by attributes'),
+    _('Selects vector features from an existing vector map and creates a new vector map containing only the selected features.'),
+    _('Select by another map'),
+    _('Selects features from vector map (A) by features from other vector map (B).'),
+    _('Map type conversions'),
+    _('Vector to raster'),
+    _('Converts (rasterize) a vector map into a raster map.'),
+    _('Vector to 3D raster'),
+    _('Converts a vector map (only points) into a 3D raster map.'),
+    _('2D vector to 3D vector'),
+    _('Performs transformation of 2D vector features to 3D.'),
+    _('Buffer vectors'),
+    _('Creates a buffer around vector features of given type.'),
+    _('Point analysis'),
+    _('Identify and remove outliers'),
+    _('Removes outliers from vector point data.'),
+    _('Identify point clusters'),
+    _('Performs cluster identification.'),
+    _('Indices for quadrat counts of vector point lists'),
+    _('Indices for quadrat counts of vector point lists.'),
+    _('Perturb points'),
+    _('Random location perturbations of vector points.'),
+    _('Test/training point sets'),
+    _('Randomly partition points into test/train sets.'),
+    _('Tests for normality for vector points'),
+    _('Tests for normality for vector points.'),
+    _('Lidar analysis'),
+    _('Identify and remove outliers'),
+    _('Removes outliers from vector point data.'),
+    _('Detect edges'),
+    _("Detects the object's edges from a LIDAR data set."),
+    _('Detect interiors'),
+    _('Building contour determination and Region Growing algorithm for determining the building inside'),
+    _('Correct and reclassify objects'),
+    _('Corrects the v.lidar.growing output. It is the last of the three algorithms for LIDAR filtering.'),
+    _('Linear referencing'),
+    _('Create LRS'),
+    _('Creates a linear reference system.'),
+    _('Create stationing'),
+    _('Creates stationing from input lines, and linear reference system.'),
+    _('Create points/segments'),
+    _('Creates points/segments from input lines, linear reference system and positions read from stdin or a file.'),
+    _('Find line id and offset'),
+    _('Finds line id and real km+offset for given points in vector map using linear reference system.'),
+    _('Nearest features'),
+    _("Finds the nearest element in vector map 'to' for elements in vector map 'from'."),
+    _('Network analysis'),
+    _('Vector network analysis tool'),
+    _('Tool for interactive vector network analysis.'),
+    _('Network preparation'),
+    _('Performs network maintenance.'),
+    _('Allocate subnets'),
+    _('Allocates subnets for nearest centers (direction from center). center node must be opened (costs >= 0). Costs of center node are used in calculation'),
+    _('Split net'),
+    _('Splits net by cost isolines. Splits net to bands between cost isolines (direction from center). Center node must be opened (costs >= 0). Costs of center node are used in calculation.'),
+    _('Shortest path'),
+    _('Finds shortest path on vector network.'),
+    _('Shortest path for sets of features'),
+    _("Computes shortest distance via the network between the given sets of features. Finds the shortest paths from each 'from' point to the nearest 'to' feature and various information about this relation are uploaded to the attribute table."),
+    _('Shortest path using timetables'),
+    _('Finds shortest path using timetables.'),
+    _('Shortest path for all pairs'),
+    _('Computes the shortest path between all pairs of nodes in the network.'),
+    _('Visibility network'),
+    _('Performs visibility graph construction.'),
+    _('Bridges and articulation points'),
+    _('Computes bridges and articulation points in the network.'),
+    _('Maximum flow'),
+    _('Computes the maximum flow between two sets of nodes in the network.'),
+    _('Vertex connectivity'),
+    _('Computes vertex connectivity between two sets of nodes in the network.'),
+    _('Components'),
+    _('Computes strongly and weakly connected components in the network.'),
+    _('Centrality'),
+    _('Computes degree, centrality, betweeness, closeness and eigenvector centrality measures in the network.'),
+    _('Steiner tree'),
+    _("Creates Steiner tree for the network and given terminals. Note that 'Minimum Steiner Tree' problem is NP-hard and heuristic algorithm is used in this module so the result may be sub optimal."),
+    _('Minimum spanning tree'),
+    _('Computes minimum spanning tree for the network.'),
+    _('Traveling salesman analysis'),
+    _('Creates a cycle connecting given nodes (Traveling salesman problem). Note that TSP is NP-hard, heuristic algorithm is used by this module and created cycle may be sub optimal'),
+    _('Overlay vector maps'),
+    _('Overlay vector maps'),
+    _('Overlays two vector maps offering clip, intersection, difference, symmetrical difference, union operators.'),
+    _('Patch vector maps'),
+    _('Creates a new vector map by combining other vector maps.'),
+    _('Manage categories'),
+    _('Change or report categories'),
+    _('Attaches, deletes or reports vector categories to map geometry.'),
+    _('Reclassify'),
+    _('Changes vector category values for an existing vector map according to results of SQL queries or a value in attribute table column.'),
+    _('Update attributes'),
+    _('Update area attributes from raster'),
+    _('Calculates univariate statistics from a raster map based on a vector map and uploads statistics to new attribute columns.'),
+    _('Update area attributes from vector'),
+    _('Count points in areas, calculate statistics from point attributes.'),
+    _('Update point attributes from areas'),
+    _('Uploads vector values at positions of vector points to the table.'),
+    _('Update database values from vector'),
+    _('Populates attribute values from vector features.'),
+    _('Sample raster maps at point locations'),
+    _('Uploads raster values at positions of vector points to the table.'),
+    _('Sample raster neighborhood around points'),
+    _('Samples a raster map at vector point locations.'),
+    _('Generate area for current region'),
+    _('Creates a vector polygon from the current region extent.'),
+    _('Generate areas from points'),
+    _('Convex hull'),
+    _('Produces a 2D/3D convex hull for a given vector map.'),
+    _('Delaunay triangles'),
+    _('Creates a Delaunay triangulation from an input vector map containing points or centroids.'),
+    _('Voronoi diagram/Thiessen polygons'),
+    _('Creates a Voronoi diagram in current region from an input vector map containing points or centroids.'),
+    _('Generate grid'),
+    _('Creates a vector map of a user-defined grid.'),
+    _('Generate points'),
+    _('Generate from database'),
+    _('Creates new vector (points) map from database table containing coordinates.'),
+    _('Generate points along lines'),
+    _('Creates points along input lines in new vector map with 2 layers.'),
+    _('Generate random points'),
+    _('Generates random 2D/3D vector points.'),
+    _('Perturb points'),
+    _('Random location perturbations of vector points.'),
+    _('Remove outliers in point sets'),
+    _('Removes outliers from vector point data.'),
+    _('Test/training point sets'),
+    _('Randomly partition points into test/train sets.'),
+    _('Reports and statistics'),
+    _('Basic vector metadata'),
+    _('Outputs basic information about a vector map.'),
+    _('Classify attribute data'),
+    _('Classifies attribute data, e.g. for thematic mapping'),
+    _('Report topology by category'),
+    _('Reports geometry statistics for vector maps.'),
+    _('Univariate attribute statistics for points'),
+    _('Calculates univariate statistics of vector map features. Variance and standard deviation is calculated only for points if specified.'),
+    _('Univariate statistics for attribute columns'),
+    _('Calculates univariate statistics on selected table column for a GRASS vector map.'),
+    _('Quadrat indices'),
+    _('Indices for quadrat counts of vector point lists.'),
+    _('Test normality'),
+    _('Tests for normality for vector points.'),
+    _('&Imagery'),
+    _('Develop images and groups'),
+    _('Create/edit group'),
+    _('Creates, edits, and lists groups of imagery files.'),
+    _('Target group'),
+    _('Targets an imagery group to a GRASS location and mapset.'),
+    _('Mosaic images'),
+    _('Mosaics several images and extends colormap.'),
+    _('Manage image colors'),
+    _('Color balance for RGB'),
+    _('Performs auto-balancing of colors for RGB images.'),
+    _('HIS to RGB'),
+    _('Transforms raster maps from HIS (Hue-Intensity-Saturation) color space to RGB (Red-Green-Blue) color space.'),
+    _('RGB to HIS'),
+    _('Transforms raster maps from RGB (Red-Green-Blue) color space to HIS (Hue-Intensity-Saturation) color space.'),
+    _('Rectify image or raster'),
+    _('Rectifies an image by computing a coordinate transformation for each pixel in the image based on the control points.'),
+    _('Histogram'),
+    _('Generate histogram of image'),
+    _('Spectral response'),
+    _('Displays spectral response at user specified locations in group or images.'),
+    _('Pan sharpening'),
+    _('Image fusion algorithms to sharpen multispectral with high-res panchromatic channels'),
+    _('Classify image'),
+    _('Clustering input for unsupervised classification'),
+    _('Generates spectral signatures for land cover types in an image using a clustering algorithm. The resulting signature file is used as input for i.maxlik, to generate an unsupervised image classification.'),
+    _('Input for supervised MLC'),
+    _('Generates statistics for i.maxlik from raster map.'),
+    _('Maximum likelihood classification (MLC)'),
+    _('Classifies the cell spectral reflectances in imagery data. Classification is based on the spectral signature information generated by either i.cluster, g.gui.iclass, or i.gensig.'),
+    _('Interactive input for supervised classification'),
+    _('Generates spectral signatures by allowing the user to outline training areas.'),
+    _('Input for supervised SMAP'),
+    _('Generates statistics for i.smap from raster map.'),
+    _('Sequential maximum a posteriori classification (SMAP)'),
+    _('Performs contextual image classification using sequential maximum a posteriori (SMAP) estimation.'),
+    _('Object segmentation'),
+    _('Identifies segments (objects) from imagery data.'),
+    _('Filter image'),
+    _('Edge detection'),
+    _('Zero-crossing "edge detection" raster function for image processing.'),
+    _('Matrix/convolving filter'),
+    _('Performs raster map matrix filter.'),
+    _('Transform image'),
+    _('Canonical correlation'),
+    _('Canonical components analysis (CCA) program for image processing.'),
+    _('Principal components'),
+    _('Principal components analysis (PCA) for image processing.'),
+    _('Fast Fourier'),
+    _('Fast Fourier Transform (FFT) for image processing.'),
+    _('Inverse Fast Fourier'),
+    _('Inverse Fast Fourier Transform (IFFT) for image processing.'),
+    _('Satellite images tools'),
+    _('Aster DN to radiance/reflectance'),
+    _('Calculates Top of Atmosphere Radiance/Reflectance/Brightness Temperature from ASTER DN.'),
+    _('Landsat DN to radiance/reflectance'),
+    _('Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI'),
+    _('Landsat cloud cover assessment'),
+    _('Performs Landsat TM/ETM+ Automatic Cloud Cover Assessment (ACCA).'),
+    _('Modis quality control'),
+    _('Extracts quality control parameters from MODIS QC layers.'),
+    _('Atmospheric correction'),
+    _('Performs atmospheric correction using the 6S algorithm. 6S - Second Simulation of Satellite Signal in the Solar Spectrum.'),
+    _('Topographic correction'),
+    _('Computes topographic correction of reflectance.'),
+    _('Satellite images products'),
+    _('Vegetation indices'),
+    _('Calculates different types of vegetation indices. Uses red and nir bands mostly, and some indices require additional bands.'),
+    _('Tasseled cap vegetation index'),
+    _('Performs Tasseled Cap (Kauth Thomas) transformation.'),
+    _('Albedo'),
+    _('Computes broad band albedo from surface reflectance.'),
+    _('Emissivity'),
+    _('Computes emissivity from NDVI, generic method for sparse land.'),
+    _('Biomass growth'),
+    _('Computes biomass growth, precursor of crop yield calculation.'),
+    _('Evapotranspiration calculation'),
+    _('Instantaneaous Net Radiation'),
+    _('Net radiation approximation (Bastiaanssen, 1995).'),
+    _('Soil heat flux'),
+    _('Soil heat flux approximation (Bastiaanssen, 1995).'),
+    _('Sensible heat flux'),
+    _('Computes sensible heat flux iteration SEBAL 01.'),
+    _('Evaporative fraction'),
+    _('Computes evaporative fraction and root zone soil moisture.'),
+    _('Actual Evapotranspiration'),
+    _('Actual evapotranspiration for diurnal period (Bastiaanssen, 1995).'),
+    _('Temporal integration of ETa'),
+    _('Computes temporal integration of satellite ET actual (ETa) following the daily ET reference (ETo) from meteorological station(s).'),
+    _('Hargreaves methods Evapotranspiration'),
+    _('Computes evapotranspiration calculation modified or original Hargreaves formulation, 2001.'),
+    _('Penman-Monteith Evapotranspiration'),
+    _('Computes potential evapotranspiration calculation with hourly Penman-Monteith.'),
+    _('Priestley-Taylor Evapotranspiration'),
+    _('Computes evapotranspiration calculation Priestley and Taylor formulation, 1972.'),
+    _('Reports and statistics'),
+    _('Kappa analysis'),
+    _('Calculates error matrix and kappa parameter for accuracy assessment of classification result.'),
+    _('OIF for LandSat TM'),
+    _('Calculates Optimum-Index-Factor table for spectral bands'),
+    _('3D r&aster'),
+    _('Develop 3D raster map'),
+    _('Manage 3D NULL values'),
+    _('Explicitly create the 3D NULL-value bitmap file.'),
+    _('Manage timestamp'),
+    _('Modifies a timestamp for a 3D raster map. Print/add/remove a timestamp for a 3D raster map.'),
+    _('Map type conversions'),
+    _('3D rasters to raster series'),
+    _('Converts 3D raster maps to 2D raster maps'),
+    _('3D color tables'),
+    _('Creates/modifies the color table associated with a 3D raster map.'),
+    _('Export 3D color table'),
+    _('Exports the color table associated with a 3D raster map.'),
+    _('3D mask'),
+    _('Establishes the current working 3D raster mask.'),
+    _('3D raster map calculator'),
+    _('3D raster map calculator'),
+    _('Cross section'),
+    _('Creates cross section 2D raster map from 3D raster map based on 2D elevation map'),
+    _('Groundwater modeling'),
+    _('Numerical calculation program for transient, confined groundwater flow in three dimensions.'),
+    _('Interpolate 3D raster from points'),
+    _('Interpolates point data to a 3D raster map using regularized spline with tension (RST) algorithm.'),
+    _('Reports and Statistics'),
+    _('Basic 3D raster metadata'),
+    _('Outputs basic information about a user-specified 3D raster map layer.'),
+    _('3D raster statistics'),
+    _('Generates volume statistics for 3D raster maps.'),
+    _('Univariate statistics for 3D rasters'),
+    _('Calculates univariate statistics from the non-null cells of a 3D raster map. Statistics include number of cells counted, minimum and maximum cell values, range, arithmetic mean, population variance, standard deviation, coefficient of variation, and sum.'),
+    _('&Database'),
+    _('Database information'),
+    _('List databases'),
+    _('Lists all databases for a given driver and location.'),
+    _('List drivers'),
+    _('Lists all database drivers.'),
+    _('List tables'),
+    _('Lists all tables for a given database.'),
+    _('Describe table'),
+    _('Describes a table in detail.'),
+    _('List columns'),
+    _('List all columns for a given table.'),
+    _('Manage databases'),
+    _('Connect'),
+    _('Prints/sets general DB connection for current mapset.'),
+    _('Login'),
+    _('Sets user/password for DB driver/database.'),
+    _('Create database'),
+    _('Creates an empty database.'),
+    _('Drop database'),
+    _('Removes an existing database.'),
+    _('Drop table'),
+    _('Drops an attribute table.'),
+    _('Copy table'),
+    _("Copy a table. Either 'from_table' (optionally with 'where') can be used or 'select' option, but not 'from_table' and 'select' at the same time."),
+    _('Drop column'),
+    _('Drops a column from selected attribute table.'),
+    _('Test'),
+    _('Test database driver, database must exist and set by db.connect.'),
+    _('Query'),
+    _('Query any table'),
+    _('Selects data from attribute table. Performs SQL query statement(s).'),
+    _('Query vector attribute data'),
+    _('Prints vector map attributes.'),
+    _('SQL statement'),
+    _("Executes any SQL statement. For SELECT statements use 'db.select'."),
+    _('Vector database connections'),
+    _('New table'),
+    _('Creates and connects a new attribute table to a given layer of an existing vector map.'),
+    _('Remove table'),
+    _('Removes existing attribute table of a vector map.'),
+    _('Join table'),
+    _('Joins a database table to a vector map table.'),
+    _('Add columns'),
+    _('Adds one or more columns to the attribute table connected to a given vector map.'),
+    _('Drop column'),
+    _('Drops a column from the attribute table connected to a given vector map.'),
+    _('Rename column'),
+    _('Renames a column in the attribute table connected to a given vector map.'),
+    _('Change values'),
+    _('Updates a column in the attribute table connected to a vector map.'),
+    _('Drop row'),
+    _('Removes a vector feature from a vector map through attribute selection.'),
+    _('Reconnect vectors to database'),
+    _('Reconnects attribute tables for all vector maps from the current mapset to a new database.'),
+    _('Set vector map - database connection'),
+    _('Prints/sets DB connection for a vector map to attribute table.'),
+    _('&Temporal'),
+    _('Manage datasets'),
+    _('Connect temporal database'),
+    _('Prints/sets general temporal GIS database connection for current mapset.'),
+    _('Create'),
+    _('Creates a space time dataset.'),
+    _('Rename'),
+    _('Renames a space time dataset'),
+    _('Remove'),
+    _('Removes space time datasets from temporal database.'),
+    _('Update metadata'),
+    _('Modifies the metadata of a space time dataset.'),
+    _('Merge'),
+    _('Merges several space time datasets into a single space time dataset.'),
+    _('Temporally shift'),
+    _('Shifts temporally the maps of a space time dataset.'),
+    _('Snap maps of dataset'),
+    _('Snaps temporally the maps of a space time dataset.'),
+    _('List'),
+    _('Lists space time datasets and maps registered in the temporal database.'),
+    _('Manage maps in datasets'),
+    _('Register maps in datasets'),
+    _('Registers raster, vector and raster3d maps in a space time datasets.'),
+    _('Unregister maps from datasets'),
+    _('Unregisters raster, vector and raster3d maps from the temporal database or a specific space time dataset.'),
+    _('List raster dataset maps'),
+    _('Lists registered maps of a space time raster dataset.'),
+    _('List vector dataset maps'),
+    _('Lists registered maps of a space time vector dataset.'),
+    _('List 3D raster dataset maps'),
+    _('Lists registered maps of a space time raster3d dataset.'),
+    _('Import'),
+    _('Import raster dataset'),
+    _('Imports space time raster dataset.'),
+    _('Import vector dataset'),
+    _('Imports a space time vector dataset from a GRASS GIS specific archive file.'),
+    _('Export'),
+    _('Export raster dataset'),
+    _('Exports space time raster dataset.'),
+    _('Export raster dataset as VTK time series'),
+    _('Exports space time raster dataset as VTK time series.'),
+    _('Export vector dataset'),
+    _('Exports a space time vector dataset as GRASS GIS specific archive file.'),
+    _('Convert raster dataset to 3D raster'),
+    _('Converts a space time raster dataset into a 3D raster map.'),
+    _('Extraction'),
+    _('Extract subset of raster dataset'),
+    _('Extracts a subset of a space time raster datasets.'),
+    _('Extract subset of vector dataset'),
+    _('Extracts a subset of a space time vector dataset.'),
+    _('Extract subset of 3D raster dataset'),
+    _('Extracts a subset of a space time 3D raster dataset.'),
+    _('Query vector dataset attribute data'),
+    _('Prints attributes of vector maps registered in a space time vector dataset.'),
+    _('Raster dataset color table'),
+    _('Creates/modifies the color table associated with each raster map of the space time raster dataset.'),
+    _('Raster calculations'),
+    _('Performs spatio-temporal mapcalc expressions on temporally sampled maps of space time raster datasets.'),
+    _('3D raster calculations'),
+    _('Performs r3.mapcalc expressions on maps of sampled space time 3D raster datasets.'),
+    _('Interpolate gaps in raster datasets'),
+    _('Replaces gaps in a space time raster dataset with interpolated raster maps.'),
+    _('Aggregation'),
+    _('Neighborhood analysis in raster dataset'),
+    _('Performs a neighborhood analysis for each map in a space time raster dataset.'),
+    _('Aggregation in raster datasets'),
+    _('Performs different aggregation algorithms from r.series on all or a subset of raster maps in a space time raster dataset.'),
+    _('Temporal aggregation'),
+    _('Aggregates temporally the maps of a space time raster dataset by a user defined granularity.'),
+    _('Temporal aggregation by dataset'),
+    _('Aggregates data of an existing space time raster dataset using the time intervals of a second space time dataset.'),
+    _('Sampling'),
+    _('Sample a space time raster dataset at point coordinates'),
+    _('Sample a space time raster dataset at specific vector point coordinates and write the output to stdout using different layouts'),
+    _('Query raster dataset by vector points dataset'),
+    _('Stores raster map values at spatial and temporal positions of vector points as vector attributes.'),
+    _('Observe specific locations in raster dataset'),
+    _('Observes specific locations in a space time raster dataset over a period of time using vector points.'),
+    _('Temporal sampling'),
+    _('Samples the input space time dataset(s) with a sample space time dataset and print the result to stdout.'),
+    _('Reports and statistics'),
+    _('Space time datasets metadata'),
+    _('Lists information about space time datasets and maps.'),
+    _('Univariate raster dataset statistics'),
+    _('Calculates univariate statistics from the non-null cells for each registered raster map of a space time raster dataset.'),
+    _('Univariate vector dataset statistics'),
+    _('Calculates univariate statistics of attributes for each registered vector map of a space time vector dataset'),
+    _('Univariate 3D raster dataset statistics'),
+    _('Calculates univariate statistics from the non-null cells for each registered 3D raster map of a space time 3D raster dataset.'),
+    _('Report temporal topology'),
+    _('Lists temporal topology of a space time dataset.'),
+    _('GUI tools'),
+    _('Animation tool'),
+    _('Launch animation tool.'),
+    _('Timeline tool'),
+    _('Plot temporal extents.'),
+    _('Temporal plot tool'),
+    _('Plot temporal values.'),
+    _('GUI tools'),
+    _('Animation tool'),
+    _('Launch animation tool.'),
+    _('Attribute table manager'),
+    _('Cartographic Composer'),
+    _('Launch Cartographic Composer'),
+    _('Georectify'),
+    _('Manage Ground Control Points for Georectification'),
+    _('Graphical modeler'),
+    _('Launch Graphical modeler'),
+    _('Interactive input for supervised classification'),
+    _('Generates spectral signatures by allowing the user to outline training areas.'),
+    _('Map Swipe'),
+    _('Launch Map Swipe'),
+    _('Temporal plot tool'),
+    _('Plot temporal values.'),
+    _('Timeline tool'),
+    _('Plot temporal extents.'),
+    '']
+menustrings_menudata.ModelerMenuData = [
+    _('&File'),
+    _('New'),
+    _('Create new model'),
+    _('Open'),
+    _('Load model from file'),
+    _('Save'),
+    _('Save model'),
+    _('Save as'),
+    _('Save model to file'),
+    _('Close'),
+    _('Close model file'),
+    _('Export to image'),
+    _('Export model to image'),
+    _('Export to Python'),
+    _('Export model to Python script'),
+    _('Quit modeler'),
+    _('Close modeler window'),
+    _('&Settings'),
+    _('Preferences'),
+    _('Modeler settings'),
+    _('&Model'),
+    _('Add command'),
+    _('Add action (GRASS command) to model'),
+    _('Add data'),
+    _('Add data item to model'),
+    _('Define relation'),
+    _('Define relation between data and action items'),
+    _('Add loop / series'),
+    _('Adds loop (series) to model'),
+    _('Add condition'),
+    _('Adds condition (if/else) to model'),
+    _('Add comment'),
+    _('Adds comment to model'),
+    _('Remove item'),
+    _('Remove action/data from model'),
+    _('Model properties'),
+    _('Model properties (name, purpose, etc.)'),
+    _('Delete intermediate data'),
+    _('Delete intermediate data defined in the model'),
+    _('Run model'),
+    _('Run entire model'),
+    _('Validate model'),
+    _('Validate entire model'),
+    _('&Help'),
+    _('Help'),
+    _('Display the HTML man pages of Graphical modeler'),
+    _('About Graphical Modeler'),
+    _('Display information about Graphical Modeler'),
+    '']
+menustrings_menudata.PsMapMenuData = [
+    _('&File'),
+    _('Page setup'),
+    _('Specify paper size, margins and orientation'),
+    _('Load instruction file'),
+    _('Load text file with mapping instructions'),
+    _('Export instruction file'),
+    _('Generate text file with mapping instructions'),
+    _('Export to PostScript'),
+    _('Generate PostScript output'),
+    _('Export to PDF'),
+    _('Generate PDF output'),
+    _('Launch ps.map dialog'),
+    _('Launch ps.map dialog'),
+    _('Quit'),
+    _('Close Cartographic Composer'),
+    _('&Insert'),
+    _('Map frame'),
+    _('Add or edit map frame'),
+    _('Raster map'),
+    _('Add or edit raster map'),
+    _('Vector map'),
+    _('Add or edit vector map'),
+    _('Map legend'),
+    _('Add or edit raster and vector legend'),
+    _('Map info'),
+    _('Add or edit map info'),
+    _('Scale bar'),
+    _('Add or edit scale bar'),
+    _('Text'),
+    _('Add text'),
+    _('Image'),
+    _('Add image'),
+    _('North Arrow'),
+    _('Add north arrow'),
+    _('Delete'),
+    _('Delete selected object'),
+    _('&Help'),
+    _('Help'),
+    _('Display the HTML man pages of Cartographic Composer'),
+    _('About Cartographic Composer'),
+    _('Display information about Cartographic Composer'),
+    '']

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_statusbar.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_statusbar.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_statusbar.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,128 @@
+"""
+ at package gcp.statusbar
+
+ at brief Classes for statusbar management in GCP Manager
+
+Classes:
+ - statusbar::SbRMSError
+ - statusbar::SbGoToGCP
+
+(C) 2012-2013 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Vaclav Petras <wenzeslaus gmail.com> (statusbar refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (statusbar refactoring)
+"""
+
+
+import wx
+
+from core.gcmd import GMessage
+from core.utils import _
+from mapdisp.statusbar import SbItem, SbTextItem
+from gui_core.wrap import SpinCtrl
+
+
+class SbGoToGCP(SbItem):
+    """SpinCtrl to select GCP to focus on
+
+    Requires MapFrame.GetSrcWindow, MapFrame.GetTgtWindow,
+    MapFrame.GetListCtrl, MapFrame.GetMapCoordList.
+    """
+
+    def __init__(self, mapframe, statusbar, position=0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'gotoGCP'
+        self.label = _("Go to GCP No.")
+
+        self.widget = SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
+                               value="", min=0)
+        self.widget.Hide()
+
+        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoToGCP)
+        self.widget.Bind(wx.EVT_SPINCTRL, self.OnGoToGCP)
+
+    def OnGoToGCP(self, event):
+        """Zooms to given GCP."""
+        gcpNumber = self.GetValue()
+        mapCoords = self.mapFrame.GetMapCoordList()
+
+        # always false, spin checks it
+        if gcpNumber < 0 or gcpNumber > len(mapCoords):
+            GMessage(parent=self,
+                     message="%s 1 - %s." % (_("Valid Range:"),
+                                             len(mapCoords)))
+            return
+
+        if gcpNumber == 0:
+            return
+
+        listCtrl = self.mapFrame.GetListCtrl()
+
+        listCtrl.selectedkey = gcpNumber
+        listCtrl.selected = listCtrl.FindItemData(-1, gcpNumber)
+        listCtrl.render = False
+        listCtrl.SetItemState(listCtrl.selected,
+                              wx.LIST_STATE_SELECTED,
+                              wx.LIST_STATE_SELECTED)
+        listCtrl.render = True
+
+        listCtrl.EnsureVisible(listCtrl.selected)
+
+        srcWin = self.mapFrame.GetSrcWindow()
+        tgtWin = self.mapFrame.GetTgtWindow()
+
+        # Source MapWindow:
+        begin = (mapCoords[gcpNumber][1], mapCoords[gcpNumber][2])
+        begin = srcWin.Cell2Pixel(begin)
+        end = begin
+        srcWin.Zoom(begin, end, 0)
+
+        # redraw map
+        srcWin.UpdateMap()
+
+        if self.mapFrame.GetShowTarget():
+            # Target MapWindow:
+            begin = (mapCoords[gcpNumber][3], mapCoords[gcpNumber][4])
+            begin = tgtWin.Cell2Pixel(begin)
+            end = begin
+            tgtWin.Zoom(begin, end, 0)
+
+            # redraw map
+            tgtWin.UpdateMap()
+
+        self.GetWidget().SetFocus()
+
+    def Update(self):
+        """Checks the number of items in the gcp list
+        and sets the spin limits accordingly."""
+        self.statusbar.SetStatusText("")
+        maximum = self.mapFrame.GetListCtrl().GetItemCount()
+        if maximum < 1:
+            maximum = 1
+        self.widget.SetRange(0, maximum)
+        self.Show()
+
+        # disable long help
+        self.mapFrame.StatusbarEnableLongHelp(False)
+
+
+class SbRMSError(SbTextItem):
+    """Shows RMS error.
+
+    Requires MapFrame.GetFwdError, MapFrame.GetBkwError.
+    """
+
+    def __init__(self, mapframe, statusbar, position=0):
+        SbTextItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'RMSError'
+        self.label = _("RMS error")
+
+    def Show(self):
+        """Shows the RMS errors."""
+        self.SetValue(_("Forward: %(forw)s, Backward: %(back)s") %
+                      {'forw': self.mapFrame.GetFwdError(),
+                       'back': self.mapFrame.GetBkwError()})
+        SbTextItem.Show(self)

Added: grass/trunk/gui/wxpython/iimage2target/ii2t_toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/iimage2target/ii2t_toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/iimage2target/ii2t_toolbars.py	2017-04-09 21:57:38 UTC (rev 70856)
@@ -0,0 +1,163 @@
+"""
+ at package gcp.toolbars
+
+ at brief Georectification module - toolbars
+
+Classes:
+ - toolbars::GCPMapToolbar
+ - toolbars::GCPDisplayToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import sys
+
+import wx
+
+from core import globalvar
+from core.utils import _
+from gui_core.toolbars import BaseToolbar, BaseIcons
+from icons.icon import MetaIcon
+
+
+class GCPManToolbar(BaseToolbar):
+    """Toolbar for managing ground control points
+
+    :param parent: reference to GCP widget
+    """
+
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+
+        self.InitToolbar(self._toolbarData())
+
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        icons = {
+            'gcpAdd': MetaIcon(img='gcp-add',
+                               label=_('Add new GCP to the list')),
+            'gcpDelete': MetaIcon(img='gcp-delete',
+                                  label=_('Delete selected GCP')),
+            'gcpClear': MetaIcon(img='gcp-remove',
+                                 label=_('Clear selected GCP')),
+            'gcpRms': MetaIcon(img='gcp-rms',
+                               label=_('Recalculate RMS error')),
+            'georectify': MetaIcon(img='georectify',
+                                   label=_('Georectify')),
+            'gcpSave': MetaIcon(img='gcp-save',
+                                label=_('Save GCPs to POINTS file')),
+            'gcpReload': MetaIcon(img='reload',
+                                  label=_('Reload GCPs from POINTS file')),
+        }
+
+        return self._getToolbarData((('gcpAdd', icons["gcpAdd"],
+                                      self.parent.AddGCP),
+                                     ('gcpDelete', icons["gcpDelete"],
+                                      self.parent.DeleteGCP),
+                                     ('gcpClear', icons["gcpClear"],
+                                      self.parent.ClearGCP),
+                                     (None, ),
+                                     ('rms', icons["gcpRms"],
+                                      self.parent.OnRMS),
+                                     ('georect', icons["georectify"],
+                                      self.parent.OnGeorect),
+                                     (None, ),
+                                     ('gcpSave', icons["gcpSave"],
+                                      self.parent.SaveGCPs),
+                                     ('gcpReload', icons["gcpReload"],
+                                      self.parent.ReloadGCPs))
+                                    )
+
+
+class GCPDisplayToolbar(BaseToolbar):
+    """GCP Display toolbar
+    """
+
+    def __init__(self, parent, toolSwitcher):
+        """GCP Display toolbar constructor
+        """
+        BaseToolbar.__init__(self, parent, toolSwitcher)
+
+        self.InitToolbar(self._toolbarData())
+        self._default = self.gcpset
+
+        # add tool to toggle active map window
+        self.togglemapid = wx.NewId()
+        self.togglemap = wx.Choice(parent=self, id=self.togglemapid,
+                                   choices=[_('source'), _('target')])
+
+        self.InsertControl(10, self.togglemap)
+
+        self.SetToolShortHelp(
+            self.togglemapid, '%s %s %s' %
+            (_('Set map canvas for '),
+             BaseIcons["zoomBack"].GetLabel(),
+             _(' / Zoom to map')))
+
+        for tool in (self.gcpset, self.pan, self.zoomin, self.zoomout):
+            self.toolSwitcher.AddToolToGroup(
+                group='mouseUse', toolbar=self, tool=tool)
+
+        # realize the toolbar
+        self.Realize()
+
+        self.EnableTool(self.zoomback, False)
+
+    def _toolbarData(self):
+        """Toolbar data"""
+        icons = {
+            'gcpSet': MetaIcon(
+                img='gcp-create',
+                label=_('Update GCP coordinates'),
+                desc=_('Update GCP coordinates)')),
+            'quit': BaseIcons['quit'].SetLabel(
+                _('Quit georectification tool')),
+            'settings': BaseIcons['settings'].SetLabel(
+                _('Georectifier settings')),
+            'help': BaseIcons['help'].SetLabel(
+                _('Georectifier manual')),
+        }
+
+        return self._getToolbarData((("displaymap", BaseIcons["display"],
+                                      self.parent.OnDraw),
+                                     ("rendermap", BaseIcons["render"],
+                                      self.parent.OnRender),
+                                     ("erase", BaseIcons["erase"],
+                                      self.parent.OnErase),
+                                     (None, ),
+                                     ("gcpset", icons["gcpSet"],
+                                      self.parent.OnPointer,
+                                      wx.ITEM_CHECK),
+                                     ("pan", BaseIcons["pan"],
+                                      self.parent.OnPan,
+                                      wx.ITEM_CHECK),
+                                     ("zoomin", BaseIcons["zoomIn"],
+                                      self.parent.OnZoomIn,
+                                      wx.ITEM_CHECK),
+                                     ("zoomout", BaseIcons["zoomOut"],
+                                      self.parent.OnZoomOut,
+                                      wx.ITEM_CHECK),
+                                     ("zoommenu", BaseIcons["zoomMenu"],
+                                      self.parent.OnZoomMenuGCP),
+                                     (None, ),
+                                     ("zoomback", BaseIcons["zoomBack"],
+                                      self.parent.OnZoomBack),
+                                     ("zoomtomap", BaseIcons["zoomExtent"],
+                                      self.parent.OnZoomToMap),
+                                     (None, ),
+                                     ('settings', icons["settings"],
+                                      self.parent.OnSettings),
+                                     ('help', icons["help"],
+                                      self.parent.OnHelp),
+                                     (None, ),
+                                     ('quit', icons["quit"],
+                                      self.parent.OnQuit))
+                                    )

Added: grass/trunk/gui/wxpython/iimage2target/wxGUI_iimage2target_frame.jpg
===================================================================
(Binary files differ)


Property changes on: grass/trunk/gui/wxpython/iimage2target/wxGUI_iimage2target_frame.jpg
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream



More information about the grass-commit mailing list