[GRASS-SVN] r43384 - in grass/branches/develbranch_6/gui/wxpython: . docs gui_modules images xml

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Sep 1 09:04:23 EDT 2010


Author: mmetz
Date: 2010-09-01 13:04:23 +0000 (Wed, 01 Sep 2010)
New Revision: 43384

Added:
   grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.GCP_Manager.html
   grass/branches/develbranch_6/gui/wxpython/docs/wxGUI_GCP_Manager.jpg
   grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py
   grass/branches/develbranch_6/gui/wxpython/images/small_down_arrow.png
   grass/branches/develbranch_6/gui/wxpython/images/small_up_arrow.png
Modified:
   grass/branches/develbranch_6/gui/wxpython/docs/Makefile
   grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.html
   grass/branches/develbranch_6/gui/wxpython/gui_modules/__init__.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py
   grass/branches/develbranch_6/gui/wxpython/wxgui.py
   grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml
Log:
add GCP Manager

Modified: grass/branches/develbranch_6/gui/wxpython/docs/Makefile
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/docs/Makefile	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/docs/Makefile	2010-09-01 13:04:23 UTC (rev 43384)
@@ -5,7 +5,8 @@
 	wxGUI.Attribute_Table_Manager \
 	wxGUI.Nviz \
 	wxGUI.Icons \
-	wxGUI.Modeler
+	wxGUI.Modeler \
+	wxGUI.GCP_Manager
 
 include $(MODULE_TOPDIR)/include/Make/Platform.make
 include $(MODULE_TOPDIR)/include/Make/Grass.make

Added: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.GCP_Manager.html
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.GCP_Manager.html	                        (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.GCP_Manager.html	2010-09-01 13:04:23 UTC (rev 43384)
@@ -0,0 +1,308 @@
+<h2>DESCRIPTION</h2>
+
+<p>
+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
+&quot;File | Manage Ground Control Points&quot;.
+
+<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 accidential 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_Manager.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/grass2/show.png">&nbsp;
+  <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/grass2/layer-redraw.png">&nbsp;
+  <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/grass2/erase.png">&nbsp;
+  <em>Erase display</em></dt>
+<dd>Erases both source and target canvas to a white background.</dd>
+
+<dt><img src="icons/grass2/gcp-create.png">&nbsp;
+  <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/grass2/pan.png">&nbsp;
+  <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/grass2/zoom-in.png">&nbsp;
+  <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/grass2/zoom-out.png">&nbsp;
+  <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/grass2/zoom-more.png">&nbsp;
+  <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/grass2/zoom-last.png">&nbsp;
+  <em>Return to pervious zoom</em></dt>
+<dd>Returns to the previous zoom extent. Up to 10 levels of zoom back are
+maintained.</dd>
+
+<dt><img src="icons/grass2/zoom-extent.png">&nbsp;
+<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/grass2/settings.png">&nbsp;
+<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>
+<em>Show Help</em></dt>
+<dd>Show help page for the GCP Manager.
+
+<dt><img src="icons/grass2/quit.png">&nbsp;
+<em>Quit</em></dt>
+<dd>Quit the GCP Manager.
+
+</dl>
+
+<h4>Toolbar for the GCP list</h4>
+
+<dl>
+
+<dt><img src="icons/grass2/gcp-save.png">&nbsp;
+<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/grass2/gcp-add.png">&nbsp;
+<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/grass2/gcp-delete.png">&nbsp;
+<em>Delete selected GCP</em></dt>
+<dd>Deletes the currently selected GCP from the list.</dd>
+
+<dt><img src="icons/grass2/gcp-remove.png">&nbsp;
+<em>Clear selected GCP</em></dt>
+<dd>Resets all coordinates of the currently selected GCP to 0 (zero).</dd>
+
+<dt><img src="icons/grass2/reload.png">&nbsp;
+<em>Reload GCPs from POINTS file</em></dt>
+<dd>Reloads GCPs from the imagery group's POINTS file.</dd>
+
+<dt><img src="icons/grass2/gcp-rms.png">&nbsp;
+<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/grass2/georectify.png">&nbsp;
+<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="i.rectify.html">i.rectify</a><br>
+  <a href="g.transform.html">g.transform</a>
+</em>
+
+<h2>AUTHORS</h2>
+
+Markus Metz<br><br>
+<em>Based on the Georectifier by</em><br>
+Michael Barton<br>
+Martin Landa<br>
+
+<p>
+<i>$Date$</i>


Property changes on: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.GCP_Manager.html
___________________________________________________________________
Added: svn:mime-type
   + text/html
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native

Modified: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.html
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.html	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/docs/wxGUI.html	2010-09-01 13:04:23 UTC (rev 43384)
@@ -405,7 +405,7 @@
 see <em><a href="g.region.html">g.region</a></em>.</dd>
 
 <dt><img src="icons/grass2/zoom-last.png">&nbsp;
-  <em>Return to pervious zoom</em></dt>
+  <em>Return to previous zoom</em></dt>
 <dd>Returns to the previous zoom extent. Up to 10 levels of zoom back are
 maintained, see <em><a href="g.region.html">g.region</a></em>.</dd>
 
@@ -520,10 +520,11 @@
 <h2>SEE ALSO</h2>
 
 <em>
-  <a href="wxGUI.Vector_Digitizing_Tool.html">Vector Digitizer</a>,
-  <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a>,
-  <a href="wxGUI.Nviz.html">3D Viewer</a>,
-  <a href="wxGUI.Modeler.html">Graphical Modeler</a>,
+  <a href="wxGUI.Vector_Digitizing_Tool.html">Vector Digitizer</a><br>
+  <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
+  <a href="wxGUI.Nviz.html">3D Viewer</a><br>
+  <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
+  <a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
   <a href="wxGUI.Icons.html">Icon themes</a>
 </em>
 

Added: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI_GCP_Manager.jpg
===================================================================
(Binary files differ)


Property changes on: grass/branches/develbranch_6/gui/wxpython/docs/wxGUI_GCP_Manager.jpg
___________________________________________________________________
Added: svn:mime-type
   + image/jpeg

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/__init__.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/__init__.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/__init__.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -6,6 +6,8 @@
     "debug.py",
     "disp_print.py",
     "gcmd.py",
+    "gcpmanager.py",
+    "gcpmapdisp.py",
     "gdialogs.py",
     "georect.py",
     "ghelp.py"

Added: grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py	                        (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -0,0 +1,2755 @@
+"""!
+ at package gcpmanager.py
+
+ at brief Georectification module for GRASS GIS. Includes ground control
+point management and interactive point and click GCP creation
+
+Classes:
+ - GCPWizard
+ - LocationPage
+ - GroupPage
+ - DispMapPage
+ - GCP
+ - GCPList
+ - VectGroup
+ - EditGCP
+ - GrSettingsDialog
+
+(C) 2006-2010 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
+ at author Updated by Martin Landa <landa.martin gmail.com>
+ at author Markus Metz redesign georectfier -> GCP Manager
+"""
+
+import os
+import sys
+import tempfile
+import shutil
+import time
+import cStringIO
+
+import wx
+from wx.lib.mixins.listctrl import CheckListCtrlMixin, ColumnSorterMixin, ListCtrlAutoWidthMixin
+import wx.lib.colourselect as  csel
+import wx.wizard as wiz
+
+import grass.script as grass
+
+import globalvar
+import render
+import toolbars
+import menuform
+import gselect
+import gcmd
+import utils
+from debug import Debug as Debug
+from icon import Icons as Icons
+from location_wizard import TitledPage as TitledPage
+from preferences import globalSettings as UserSettings
+from gcpmapdisp import MapFrame
+from mapdisp_window import BufferedWindow
+
+try:
+    import subprocess # Not needed if GRASS commands could actually be quiet
+except:
+    CompatPath = globalvar.ETCWXDIR
+    sys.path.append(CompatPath)
+    from compat import subprocess
+
+gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
+sys.path.append(gmpath)
+
+imgpath = os.path.join(globalvar.ETCWXDIR, "images")
+
+#
+# global variables
+#
+global src_map
+global tgt_map
+global maptype
+
+src_map = ''
+tgt_map = ''
+maptype = 'cell'
+
+def getSmallUpArrowImage():
+    stream = open(os.path.join(imgpath, 'small_up_arrow.png'), 'rb')
+    try:
+        img = wx.ImageFromStream(stream)
+    finally:
+        stream.close()
+    return img
+
+def getSmallDnArrowImage():
+    stream = open(os.path.join(imgpath, '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):
+        self.parent = parent # GMFrame
+
+        #
+        # 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 = 'cell'
+
+        # 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:
+                wx.MessageBox(parent=self.parent,
+                              message=_("Georectifying setup canceled."),
+                              caption=_("Georectify"),
+                              style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+                self.Cleanup()
+        else:
+            wx.MessageBox(parent=self.parent,
+                          message=_("Georectifying setup canceled."),
+                          caption=_("Georectify"),
+                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            self.Cleanup()
+
+        #
+        # start GCP display
+        #
+        if success != False:
+            # instance of render.Map to be associated with display
+            self.SwitchEnv('source')
+            self.SrcMap = render.Map(gisrc=self.source_gisrc) 
+            self.SwitchEnv('target')
+            self.TgtMap = render.Map(gisrc=self.target_gisrc)
+            self.Map = self.SrcMap
+            
+            #
+            # add layer to source map
+            #
+            if maptype == 'cell':
+                rendertype = 'raster'
+                cmdlist = ['d.rast', 'map=%s' % src_map]
+            else: # -> vector layer
+                rendertype = 'vector'
+                cmdlist = ['d.vect', 'map=%s' % src_map]
+            
+            self.SwitchEnv('source')
+            self.SrcMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
+                              name=utils.GetLayerNameFromCmd(cmdlist),
+                              l_hidden=False, l_opacity=1.0, l_render=False)
+
+            if tgt_map:
+                #
+                # add layer to target map
+                #
+                if maptype == 'cell':
+                    rendertype = 'raster'
+                    cmdlist = ['d.rast', 'map=%s' % tgt_map]
+                else: # -> vector layer
+                    rendertype = 'vector'
+                    cmdlist = ['d.vect', 'map=%s' % tgt_map]
+                
+                self.SwitchEnv('target')
+                self.TgtMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
+                                  name=utils.GetLayerNameFromCmd(cmdlist),
+                                  l_hidden=False, l_opacity=1.0, l_render=False)
+            
+            #
+            # start GCP Manager
+            #
+            self.gcpmgr = GCP(self.parent, 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 = 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"""
+        self.SwitchEnv('target')
+        self.parent.gcpmanagement = None
+
+        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
+        #
+        self.sizer.AddGrowableCol(2)
+        # 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(item=self.rb_maptype,
+                       flag=wx.ALIGN_CENTER | wx.ALL | wx.EXPAND, border=5,
+                       pos=(1, 1), span=(1, 2))
+
+        # location
+        self.sizer.Add(item=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 = gselect.LocationSelect(parent = self, gisdbase = self.grassdatabase)
+        self.sizer.Add(item=self.cb_location,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(2, 2))
+
+        # mapset
+        self.sizer.Add(item=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 = gselect.MapsetSelect(parent = self, gisdbase = self.grassdatabase,
+                                              setItems = False)
+        self.sizer.Add(item=self.cb_mapset,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(3,2))
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_RADIOBOX, self.OnMaptype, self.rb_maptype)
+        self.Bind(wx.EVT_COMBOBOX, self.OnLocation, self.cb_location)
+        self.Bind(wx.EVT_COMBOBOX, self.OnMapset, self.cb_mapset)
+        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 = 'cell'
+        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 == '':
+            wx.MessageBox(_('You must select a valid location before selecting a mapset'))
+            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 == ''):
+            wx.MessageBox(_('You must select a valid location and mapset in order to continue'))
+            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
+        #
+        self.sizer.AddGrowableCol(2)
+        # group
+        self.sizer.Add(item=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(item=self.cb_group,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(1, 2))
+        
+        # create group               
+        self.sizer.Add(item=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(item=self.btn_mkgroup,
+                     flag=wx.RIGHT, border=5)
+
+        btnSizer.Add(item=self.btn_vgroup,
+                     flag=wx.LEFT, border=5)
+        
+        self.sizer.Add(item=btnSizer,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(2, 2))
+        
+        # extension
+        self.sizer.Add(item=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(item=self.ext_txt,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(3, 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"""
+        menuform.GUI().ParseCommand(['i.group'],
+                                    completed=(self.GetOptData, None, ''),
+                                    parentframe=self.parent.parent, modal=True)
+
+    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 GetOptData(self, dcmd, layer, params, propwin):
+        """!Process i.group"""
+        # update the page
+        if dcmd:
+            gcmd.Command(dcmd)
+
+        self.OnEnterPage()
+        self.Update()
+        
+    def OnExtension(self, event):
+        self.extension = event.GetString()
+
+    def OnPageChanging(self, event=None):
+        if event.GetDirection() and self.xygroup == '':
+            wx.MessageBox(_('You must select a valid image/map group in order to continue'))
+            event.Veto()
+            return
+
+        if event.GetDirection() and self.extension == '':
+            wx.MessageBox(_('You must enter an map name extension in order to continue'))
+            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 == 'cell':
+            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 and \
+                self.xygroup == '':
+            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(item=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 = gselect.Select(self, id=wx.ID_ANY,
+                                    size=globalvar.DIALOG_GSELECT_SIZE, type=maptype, updateOnPopup = False)
+        
+        self.sizer.Add(item=self.srcselection,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(1, 2))
+
+        self.sizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY, label=_('Select target map to display:')),
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(2, 1))
+
+        self.tgtselection = gselect.Select(self, id=wx.ID_ANY,
+                                        size=globalvar.DIALOG_GSELECT_SIZE, type=maptype, updateOnPopup = False)
+        
+        self.sizer.Add(item=self.tgtselection,
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
+                       pos=(2, 2))
+
+        #
+        # bindings
+        #
+        self.srcselection.Bind(wx.EVT_TEXT, self.OnSrcSelection)
+        self.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
+        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 = event.GetString()
+
+        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 == 'cell':
+                p = gcmd.Command(['g.region', 'rast=src_map'])
+            elif maptype == 'vector':
+                p = gcmd.Command(['g.region', 'vect=src_map'])
+            
+            if p.returncode == 0:
+                print 'returncode = ', str(p.returncode)
+                self.parent.Map.region = self.parent.Map.GetRegion()
+        except:
+            pass
+
+    def OnTgtSelection(self,event):
+        """!Source map to display selected"""
+        global tgt_map
+
+        tgt_map = event.GetString()
+
+    def OnPageChanging(self, event=None):
+        global src_map
+        global tgt_map
+
+        if event.GetDirection() and (src_map == ''):
+            wx.MessageBox(_('You must select a source map in order to continue'))
+            event.Veto()
+            return
+
+        self.parent.SwitchEnv('target')
+        
+    def OnEnterPage(self, event=None):
+        global maptype
+        global src_map
+        global tgt_map
+
+        self.srcselection.SetElementList(maptype)
+        ret = gcmd.RunCommand('i.group',
+                              parent = self,
+                              read = True,
+                              group = self.parent.grouppage.xygroup,
+                              flags = 'g')            
+
+        if ret:
+            self.parent.src_maps = ret.splitlines()
+        else:
+            wx.MessageBox(parent=self,
+                              caption=_("Select maps to display"),
+                              message=_('No maps in selected group <%s>. \n'
+                                        'Please edit group or select another group.') %
+                                        self.parent.grouppage.xygroup,
+                              style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
+            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.tgtselection.SetElementList(maptype)
+        self.tgtselection.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, wx.Frame, ColumnSorterMixin):
+    """!
+    Manages ground control points for georectifying. Calculates RMS statics.
+    Calls i.rectify or v.transform to georectify map.
+    """
+    def __init__(self, parent, 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
+
+        if tgt_map == '':
+            self.show_target = False
+        else:
+            self.show_target = True
+        
+        #wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
+        MapFrame.__init__(self, parent, id, title, size = size,
+                            Map=Map, toolbars=["gcpdisp"], lmgr=lmgr, name='GCPMapWindow')
+
+        #
+        # init variables
+        #
+        self.parent = parent # GMFrame
+        self.parent.gcpmanagement = self
+
+        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 = {
+            'points' : os.path.join(self.grassdatabase,
+                                    self.xylocation,
+                                    self.xymapset,
+                                    'group',
+                                    self.xygroup,
+                                    'POINTS'),
+            'points_bak' : os.path.join(self.grassdatabase,
+                                    self.xylocation,
+                                    self.xymapset,
+                                    'group',
+                                    self.xygroup,
+                                    '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'),
+            }
+
+        # make a backup of the current points file
+        if os.path.exists(self.file['points']):
+            shutil.copy(self.file['points'], self.file['points_bak'])
+
+        # polynomial order transformation for georectification
+        self.gr_order = 1 
+        # 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,      # target east
+                                   0.0,      # target north
+                                   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)
+
+        # TODO: make a decision
+        use_art_provider = False
+        if use_art_provider:
+            i_size = wx.Size(12, 12)
+            SmallUpArrow = wx.ArtProvider.GetBitmap(id=wx.ART_GO_UP,
+                           client=wx.ART_FRAME_ICON, size=i_size)
+            SmallDnArrow = wx.ArtProvider.GetBitmap(id=wx.ART_GO_DOWN,
+                           client=wx.ART_FRAME_ICON, size=i_size)
+        else:
+            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.SetCursor(self.cursors["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.SetCursor(self.cursors["cross"])
+
+        #
+        # show new display & draw map
+        #
+        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_CLOSE, self.OnQuit)
+
+    def __del__(self):
+        """!Disable GCP manager mode"""
+        self.parent.gcpmanagement = None
+        
+    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
+
+    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+    def GetSortImages(self):
+        return (self.sm_dn, self.sm_up)
+
+    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:
+            gcmd.RunCommand('i.target',
+                            parent = self,
+                            flags = 'c',
+                            group = tgroup)
+        else:
+            self.grwiz.SwitchEnv('source')
+            gcmd.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,                # target east
+                                   0.0,                # target north
+                                   0.0,                # forward error
+                                   0.0 ] )             # backward error
+
+        if self.statusbarWin['toggle'].GetSelection() == 7: # go to
+            self.StatusbarUpdate()
+
+    def DeleteGCP(self, event):
+        """
+        Deletes selected item in GCP list
+        """
+        minNumOfItems = self.OnGROrder(None)
+
+        if self.list.GetItemCount() <= minNumOfItems:
+            wx.MessageBox(parent=self, message=_("At least %d GCPs required. Operation cancelled.") % minNumOfItems,
+                          caption=_("Delete GCP"), style=wx.OK | wx.ICON_INFORMATION)
+            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.statusbarWin['toggle'].GetSelection() == 7: # go to
+            self.StatusbarUpdate()
+            if self.list.selectedkey > 0:
+                self.statusbarWin['goto'].SetValue(self.list.selectedkey)
+            #self.statusbarWin['goto'].SetValue(0)
+
+    def ClearGCP(self, event):
+        """
+        Clears all values in selected item of GCP list and unchecks it
+        """
+        index = self.list.GetSelected()
+
+        for i in range(4):
+            self.list.SetStringItem(index, i, '0.0')
+        self.list.SetStringItem(index, 4, '')
+        self.list.SetStringItem(index, 5, '')
+        self.list.CheckItem(index, False)
+        key = self.list.GetItemData(index)
+
+        # 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 DrawGCP(self, coordtype):
+        """
+        Updates GCP and map coord maps and redraws
+        active (checked) GCP markers
+        """
+        self.highest_only = UserSettings.Get(group='gcpman', key='rms', subkey='highestonly')
+
+        self.show_unused =  UserSettings.Get(group='gcpman', key='symbol', subkey='unused')
+        col = UserSettings.Get(group='gcpman', key='symbol', subkey='color')
+        wxLowCol = wx.Colour(col[0], col[1], col[2], 255)
+        col = UserSettings.Get(group='gcpman', key='symbol', subkey='hcolor')
+        wxHiCol = wx.Colour(col[0], col[1], col[2], 255)
+        col = UserSettings.Get(group='gcpman', key='symbol', subkey='scolor')
+        wxSelCol = wx.Colour(col[0], col[1], col[2], 255)
+        col = UserSettings.Get(group='gcpman', key='symbol', subkey='ucolor')
+        wxUnCol = wx.Colour(col[0], col[1], col[2], 255)
+        spx = UserSettings.Get(group='gcpman', key='symbol', subkey='size')
+        wpx = UserSettings.Get(group='gcpman', key='symbol', subkey='width')
+        font = self.GetFont()
+        font.SetPointSize(int(spx) + 2)
+
+        penOrig = polypenOrig = None
+
+        mapWin = None
+        
+        if coordtype == 'source':
+            mapWin = self.SrcMapWindow
+            e_idx = 1
+            n_idx = 2
+        elif coordtype == 'target':
+            mapWin = self.TgtMapWindow
+            e_idx = 3
+            n_idx = 4
+
+        if not mapWin:
+            wx.MessageBox(parent=self,
+                  message="%s%s." % (_("mapwin not defined for "),
+                                 str(idx)),
+                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+
+        #for gcp in self.mapcoordlist:
+        for idx in range(self.list.GetItemCount()):
+
+            key = self.list.GetItemData(idx)
+            gcp = self.mapcoordlist[key]
+
+            if not self.list.IsChecked(idx):
+                if self.show_unused:
+                    wxCol = wxUnCol
+                else:
+                    continue
+            else:
+                if self.highest_only == True:
+                    if key == self.highest_key:
+                        wxCol = wxHiCol
+                    else:
+                        wxCol = wxLowCol
+                elif self.rmsthresh > 0:
+                    if (gcp[5] > self.rmsthresh):
+                        wxCol = wxHiCol
+                    else:
+                        wxCol = wxLowCol
+
+            if idx == self.list.selected:
+                wxCol = wxSelCol
+
+            if not penOrig:
+                penOrig = mapWin.pen
+                polypenOrig = mapWin.polypen
+                mapWin.pen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID)
+                mapWin.polypen = wx.Pen(colour=wxCol, width=wpx, style=wx.SOLID) # ?
+
+            mapWin.pen.SetColour(wxCol)
+            mapWin.polypen.SetColour(wxCol)
+
+            coord = mapWin.Cell2Pixel((gcp[e_idx], gcp[n_idx]))
+            mapWin.DrawCross(pdc=mapWin.pdcTmp, coords=coord,
+                             size=spx, text={ 'text' : '%s' % str(gcp[0]),
+                                            'active' : True,
+                                            'font' : font,
+                                            'color': wxCol,
+                                            'coords': [coord[0] + 5,
+                                                       coord[1] + 5,
+                                                       5,
+                                                       5]})
+            
+        if penOrig:
+            mapWin.pen = penOrig
+            mapWin.polypen = polypenOrig
+        
+    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 %s coordinates for GCP No. %s? \n\n'
+                                    'East: %s \n'
+                                    'North: %s') % (currloc, str(key), str(coord0), 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]
+        elif coordtype == 'target':
+            self.list.SetStringItem(index, 3, str(coord0))
+            self.list.SetStringItem(index, 4, str(coord1))
+            self.mapcoordlist[key][3] = coord[0]
+            self.mapcoordlist[key][4] = coord[1]
+            
+        self.list.SetStringItem(index, 5, '0')
+        self.list.SetStringItem(index, 6, '0')
+        self.mapcoordlist[key][5] = 0.0
+        self.mapcoordlist[key][6] = 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['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\ttarget\t\tstatus\n")
+            f.write("#\teast\tnorth\teast\tnorth\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()
+                f.write(coord0 + ' ' + coord1 + '     ' + coord2 + ' ' + coord3 + '     ' + check + '\n')
+
+        except IOError, err:
+            wx.MessageBox(parent=self,
+                          message="%s <%s>. %s%s" % (_("Writing POINTS file failed"),
+                                                     self.file['points'], os.linesep, err),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+
+        f.close()
+
+        # if event != None save also to backup file
+        if event:
+            shutil.copy(self.file['points'], self.file['points_bak'])
+            self.parent.goutput.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
+        #targetMapWin = self.parent.curr_page.maptree.mapdisplay.MapWindow
+
+        if not sourceMapWin:
+            wx.MessageBox(parent=self,
+                          message="%s. %s%s" % (_("source mapwin not defined"),
+                                                     os.linesep, err),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            
+        if not targetMapWin:
+            wx.MessageBox(parent=self,
+                          message="%s. %s%s" % (_("target mapwin not defined"),
+                                                     os.linesep, err),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+
+        try:
+            f = open(self.file['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[4] == 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[2], coords[3]), targetMapWin)
+                index = self.list.GetSelected()
+                if index != wx.NOT_FOUND:
+                    self.list.CheckItem(index, check)
+                GCPcnt += 1
+
+        except IOError, err:
+            wx.MessageBox(parent=self,
+                          message="%s <%s>. %s%s" % (_("Reading POINTS file failed"),
+                                                     self.file['points'], os.linesep, err),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            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)
+        else:
+            # draw GCPs (source and target)
+            sourceMapWin.UpdateMap(render=False, renderVector=False)
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+
+    def ReloadGCPs(self, event):
+        """!Reload data from file"""
+
+        # use backup
+        shutil.copy(self.file['points_bak'], self.file['points'])
+
+        # delete all items in mapcoordlist
+        self.mapcoordlist = []
+        self.mapcoordlist.append([ 0,        # GCP number
+                                   0.0,      # source east
+                                   0.0,      # source north
+                                   0.0,      # target east
+                                   0.0,      # target north
+                                   0.0,      # forward error
+                                   0.0 ] )   # backward error
+
+        self.list.LoadData()
+        self.itemDataMap = self.mapcoordlist
+    
+    def OnFocus(self, event):
+        # self.grwiz.SwitchEnv('source')
+        pass
+        
+    def OnRMS(self, event):
+        """
+        RMS button handler
+        """
+        self.RMSError(self.xygroup,self.gr_order)
+        
+    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:
+                wx.MessageBox(parent=self,
+                              caption=_("RMS Error"),
+                              message=_('Insufficient points defined and active (checked) '
+                                        'for selected rectification method.\n'
+                                        '3+ points needed for 1st order,\n'
+                                        '6+ points for 2nd order, and\n'
+                                        '10+ points for 3rd order.'),
+                              style=wx.ICON_INFORMATION | wx.ID_OK | wx.CENTRE)
+                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 == 'cell':
+            self.grwiz.SwitchEnv('source')
+            cmdlist = ['i.rectify','-a','group=%s' % self.xygroup,
+                       'extension=%s' % self.extension,'order=%s' % self.gr_order]
+            if self.clip_to_region:
+                cmdlist.append('-c')
+            
+            self.parent.goutput.RunCmd(cmdlist, compReg=False,
+                                       switchPage=True)
+            
+            time.sleep(.1)
+
+        elif maptype == 'vector':
+            outmsg = ''
+            # loop through all vectors in VREF
+            # and move resulting vector to target location
+            
+            # make sure current mapset has a vector folder
+            if not os.path.isdir(os.path.join(self.grassdatabase,
+                                              self.currentlocation,
+                                              self.currentmapset,
+                                              'vector')):
+                os.mkdir(os.path.join(self.grassdatabase,
+                                      self.currentlocation,
+                                      self.currentmapset,
+                                      'vector'))
+
+            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.transform
+            for vect in vectlist:
+                self.outname = vect + '_' + self.extension
+                self.parent.goutput.WriteLog(text = _('Transforming <%s>...') % vect,
+                                             switchPage = True)
+                msg = err = ''
+
+                ret, out, err = gcmd.RunCommand('v.transform',
+                           flags = '-o',
+                           input=vect,
+                           output=self.outname,
+                           pointsfile=self.file['points'],
+                           getErrorMsg=True, read=True) 
+                
+                    
+                if ret == 0:
+                    self.VectGRList.append(self.outname)
+                    print err
+                    # note: WriteLog doesn't handle GRASS_INFO_PERCENT well, so using a print here
+#                    self.parent.goutput.WriteLog(text = _(err), switchPage = True)
+                    self.parent.goutput.WriteLog(text = _(out), switchPage = True)
+                else:
+                    self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
+                                                           self.outname)
+                    self.parent.goutput.WriteError(_(err))
+
+                # FIXME
+                # Copying database information not working. 
+                # Does not copy from xy location to current location
+                # TODO: replace $GISDBASE etc with real paths
+#                xyLayer = []
+#                for layer in grass.vector_db(map = vect).itervalues():
+#                    xyLayer.append((layer['driver'],
+#                                    layer['database'],
+#                                    layer['table']))
+
+                        
+#                dbConnect = grass.db_connection()
+#                print 'db connection =', dbConnect
+#                for layer in xyLayer:     
+#                    self.parent.goutput.RunCmd(['db.copy',
+#                                                '--q',
+#                                                '--o',
+#                                                'from_driver=%s' % layer[0],
+#                                                'from_database=%s' % layer[1],
+#                                                'from_table=%s' % layer[2],
+#                                                'to_driver=%s' % dbConnect['driver'],
+#                                                'to_database=%s' % dbConnect['database'],
+#                                                'to_table=%s' % layer[2] + '_' + self.extension])
+
+            # copy all georectified vectors from source location to current location
+            for name in self.VectGRList:
+                xyvpath = os.path.join(self.grassdatabase,
+                                       self.xylocation,
+                                       self.xymapset,
+                                       'vector',
+                                       name)
+                vpath = os.path.join(self.grassdatabase,
+                                     self.currentlocation,
+                                     self.currentmapset,
+                                     'vector',
+                                     name)
+                                    
+                if os.path.isdir(vpath):
+                    self.parent.goutput.WriteWarning(_('Vector map <%s> already exists. '
+                                                       'Change extension name and '
+                                                       'georectify again.') % self.outname)
+                    break
+                else:
+                    # use shutil.copytree() because shutil.move() deletes src dir
+                    shutil.copytree(xyvpath, vpath)
+
+                # TODO: connect vectors to copied tables with v.db.connect
+                                                   
+            wx.MessageBox('For all vector maps georectified successfully, ' + '\n' +
+                          'you will need to copy any attribute tables' + '\n' +
+                          'and reconnect them to the georectified vectors')
+            
+        self.grwiz.SwitchEnv('target')
+
+    def OnGeorectDone(self, **kargs):
+        """!Print final message"""
+        global maptype
+        if maptype == 'cell':
+            return
+        
+        returncode = kargs['returncode']
+        
+        if returncode == 0:
+            self.VectGRList.append(self.outname)
+            print '*****vector list = ' + str(self.VectGRList)
+        else:
+            self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
+                                                   self.outname)
+
+         
+    def OnSettings(self, event):
+        """!GCP Manager settings"""
+        dlg = GrSettingsDialog(parent=self, 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['points_bak']):
+                    shutil.copy(self.file['points_bak'], self.file['points'])
+
+            if os.path.exists(self.file['points_bak']):
+                os.unlink(self.file['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 g.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 = gcmd.RunCommand('g.transform',
+                              parent = self,
+                              read = True,
+                              group = xygroup,
+                              order = order)
+        
+        self.grwiz.SwitchEnv('target')
+
+        if ret:
+            errlist = ret.splitlines()
+        else:
+            wx.MessageBox(parent=self,
+                              caption=_("RMS Error"),
+                              message=_('Could not calculate RMS Error. \n'
+                                        'Possible error with g.transform.'),
+                              style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
+            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, 5, fwd_err)
+                self.list.SetStringItem(index, 6, bkw_err)
+                self.mapcoordlist[key][5] = float(fwd_err)
+                self.mapcoordlist[key][6] = 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, 5, '')
+                self.list.SetStringItem(index, 6, '')
+                self.mapcoordlist[key][5] = 0.0
+                self.mapcoordlist[key][6] = 0.0
+                self.list.SetItemTextColour(index, wx.BLACK)
+
+        # SD
+        if GCPcount > 0:
+            sum_fwd_err /= GCPcount
+            self.rmsmean = sum_fwd_err /GCPcount
+            self.rmssd = (((sumsq_fwd_err/GCPcount) - 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][5] > 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()
+
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=False, renderVector=False)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+
+    def GetNewExtend(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 = gcmd.RunCommand('g.transform',
+                                  parent = self,
+                                  read = True,
+                                  group = self.xygroup,
+                                  order = 1,
+                                  format = 'dst',
+                                  coords = coord_file)
+
+        elif map == 'target':
+            ret = gcmd.RunCommand('g.transform',
+                                  parent = self,
+                                  read = True,
+                                  group = self.xygroup,
+                                  order = 1,
+                                  flags = 'r',
+                                  format = 'src',
+                                  coords = coord_file)
+
+        os.unlink(coord_file)
+        
+        self.grwiz.SwitchEnv('target')
+
+        if ret:
+            errlist = ret.splitlines()
+        else:
+            wx.MessageBox(parent=self,
+                              caption=_("Adjust GCP Displays "),
+                              message=_('Could not calculate new extends. \n'
+                                        'Possible error with g.transform.'),
+                              style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
+            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"""
+        cmdlist = ['g.manual', 'entry=wxGUI.GCP_Manager']
+        self.parent.goutput.RunCmd(cmdlist, compReg=False,
+                                       switchPage=False)
+
+    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.toolbars['gcpdisp'].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.GetNewExtend(self.SrcMap.region, 'source')
+        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.GetNewExtend(self.TgtMap.region, 'target')
+        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 OnDispResize(self, event):
+        """!GCP Map Display resized, adjust Map Windows
+        """
+        if self.toolbars['gcpdisp']:
+            srcwidth, srcheight = self.SrcMapWindow.GetSize()
+            tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+            tgtwidth = (srcwidth + tgtwidth) / 2
+            self._mgr.GetPane("target").Hide()
+            self._mgr.Update()
+            self._mgr.GetPane("source").BestSize((tgtwidth, srcheight))
+            self._mgr.GetPane("target").BestSize((tgtwidth, tgtheight))
+            if self.show_target:
+                self._mgr.GetPane("target").Show()
+            self._mgr.Update()
+        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'),
+                _('target E'),
+                _('target N'),
+                _('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'),
+                _('target E'),
+                _('target N'),
+                _('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['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
+
+    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)
+
+        pass
+    
+    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',                # target E
+                     '0.0',                # target N
+                     '',                   # 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()
+
+        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)
+
+        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, 5):
+            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:
+                wx.MessageBox(parent=self,
+                              caption=_("Edit GCP"),
+                              message=_("Invalid coordinate value. Operation cancelled."),
+                              style=wx.CENTRE | wx.ICON_ERROR | wx.ID_OK)
+            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, 5, '')
+                    self.SetStringItem(index, 6, '')
+                    key = self.GetItemData(index)
+                    self.gcp.mapcoordlist[key] = [key,
+                                                  float(values[0]),
+                                                  float(values[1]),
+                                                  float(values[2]),
+                                                  float(values[3]),
+                                                  0.0,
+                                                  0.0]
+                    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(item = 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(item = 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(item = 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(item = 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))
+        
+        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)
+       
+        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.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))
+
+        # 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)):
+            label = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                  label=label)
+            gridSizer.Add(item=label,
+                          flag=wx.ALIGN_CENTER_VERTICAL,
+                          pos=(row, col))
+
+            col += 1
+            win.SetValue(str(data[idx]))
+
+            gridSizer.Add(item=win,
+                          pos=(row, col))
+
+            col += 1
+            idx += 1
+
+            if col > 3:
+                row += 1
+                col = 0
+
+        boxSizer.Add(item=gridSizer, proportion=1,
+                  flag=wx.EXPAND | wx.ALL, border=5)
+
+        sizer.Add(item=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(item=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.ecoord.GetValue())
+            float(self.ncoord.GetValue())
+        except ValueError:
+            return valuelist
+
+        valuelist.append(self.xcoord.GetValue())
+        valuelist.append(self.ycoord.GetValue())
+        valuelist.append(self.ecoord.GetValue())
+        valuelist.append(self.ncoord.GetValue())
+
+        return valuelist
+
+class GrSettingsDialog(wx.Dialog):
+    def __init__(self, parent, id, 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 = tgt_map
+        self.sdfactor = 0
+
+        self.symbol = {}
+
+        # 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(item=notebook, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
+        mainSizer.Add(item=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)
+        rmsgridSizer.AddGrowableCol(1)
+
+        # 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(item=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(item=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(item=self.rmsWin, flag=wx.ALIGN_RIGHT, pos=(1, 1))
+        sizer.Add(item=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)
+        gridSizer.AddGrowableCol(1)
+
+        #
+        # general symbol color
+        #
+        row = 0
+        label = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Color:"))
+        gridSizer.Add(item=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(item=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(item=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(item=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(item=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(item=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(item=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(item=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(item=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(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        symsize = int(UserSettings.Get(group='gcpman', key='symbol', subkey='size'))
+        sizeWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
+                             min=1, max=20)
+        sizeWin.SetValue(symsize)
+        self.symbol['size'] = sizeWin.GetId()
+        gridSizer.Add(item=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(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        width = int(UserSettings.Get(group='gcpman', key='symbol', subkey='width'))
+        widWin = wx.SpinCtrl(parent=panel, id=wx.ID_ANY,
+                             min=1, max=10)
+        widWin.SetValue(width)
+        self.symbol['width'] = widWin.GetId()
+        gridSizer.Add(item=widWin,
+                      flag=wx.ALIGN_RIGHT,
+                      pos=(row, 1))
+        
+        boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
+        sizer.Add(item=boxSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+        #
+        # maps to display
+        #
+        # source map to display
+        self.srcselection = gselect.Select(panel, id=wx.ID_ANY,
+                    size=globalvar.DIALOG_GSELECT_SIZE, type='cell', 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 to display
+        self.tgtselection = gselect.Select(panel, id=wx.ID_ANY,
+                    size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
+        self.parent.grwiz.SwitchEnv('target')
+        self.tgtselection.SetElementList(maptype)
+        self.tgtselection.GetElementList()
+
+        sizer.Add(item=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(item=self.srcselection, proportion=0, 
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+        self.srcselection.SetValue(src_map)
+        sizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select target map to display:')),
+                       proportion=0, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+        sizer.Add(item=self.tgtselection, proportion=0, 
+                       flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+        self.tgtselection.SetValue(tgt_map)
+
+        # 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.tgtselection.Bind(wx.EVT_TEXT, self.OnTgtSelection)
+
+        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_grmethod = wx.RadioBox(parent=panel, id=wx.ID_ANY,
+                                       label=" %s " % _("Select rectification method for rasters"),
+                                       choices=[_('1st order'), _('2nd order'), _('3rd order')],
+                                       majorDimension=wx.RA_SPECIFY_COLS)
+        sizer.Add(item=self.rb_grmethod, proportion=0,
+                       flag=wx.EXPAND | wx.ALL, border=5)
+        self.rb_grmethod.SetSelection(self.parent.gr_order - 1)
+
+        # clip to region
+        self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+                                label=_("clip to computational region in target location"))
+        sizer.Add(item=self.check, proportion=0,
+                       flag=wx.EXPAND | wx.ALL, border=5)
+        self.check.SetValue(self.parent.clip_to_region)
+
+        # extension
+        sizer.Add(item=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(item=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_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"""
+
+        self.sdfactor = float(event.GetString())
+
+        if self.sdfactor <= 0:
+            wx.MessageBox(parent=self,
+                  caption=_("Update settings"),
+                  message=_('RMS threshold factor must be > 0'),
+                  style=wx.ICON_ERROR | wx.ID_OK | wx.CENTRE)
+        elif self.sdfactor < 1:
+            wx.MessageBox(parent=self,
+                  caption=_("Update settings"),
+                  message=_('RMS threshold factor is < 1\n'
+                            'Too many points might be highlighted'),
+                  style=wx.ICON_EXCLAMATION | wx.ID_OK | wx.CENTRE)
+
+    def OnSrcSelection(self,event):
+        """!Source map to display selected"""
+        global src_map
+
+        tmp_map = event.GetString()
+
+        if not tmp_map == '' and not tmp_map == src_map:
+            self.new_src_map = tmp_map
+
+    def OnTgtSelection(self,event):
+        """!Target map to display selected"""
+        global tgt_map
+
+        tmp_map = event.GetString()
+
+        if not tmp_map == tgt_map:
+            self.new_tgt_map = tmp_map
+
+    def OnClipRegion(self, event):
+        self.parent.clip_to_region = event.IsChecked()
+        
+    def OnExtension(self, event):
+        self.parent.extension = event.GetString()
+
+    def UpdateSettings(self):
+        global src_map
+        global tgt_map
+
+        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.mean + 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
+        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
+            cmdlist = ['d.rast', 'map=%s' % src_map]
+            self.parent.grwiz.SwitchEnv('source')
+            self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
+                              name=utils.GetLayerNameFromCmd(cmdlist),
+                              l_hidden=False, l_opacity=1.0, l_render=False)
+
+            self.parent.grwiz.SwitchEnv('target')
+            srcrender = True
+
+        if self.new_tgt_map != tgt_map:
+            # remove old layer
+            layers = self.parent.grwiz.TgtMap.GetListOfLayers()
+            if layers:
+                self.parent.grwiz.TgtMap.DeleteLayer(layers[0])
+            tgt_map = self.new_tgt_map
+
+            if tgt_map != '':
+                cmdlist = ['d.rast', 'map=%s' % tgt_map]
+                self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
+                                  name=utils.GetLayerNameFromCmd(cmdlist),
+                                  l_hidden=False, l_opacity=1.0, l_render=False)
+
+                tgtrender = True
+                if self.parent.show_target == False:
+                    self.parent.show_target = True
+                    self.parent._mgr.GetPane("target").Show()
+                    self.parent.toolbars['gcpdisp'].Enable('zoommenu', enable = True)
+                    self.parent.activemap.Enable()
+                    self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
+                    self.parent._mgr.Update()
+            else: # tgt_map == ''
+                if self.parent.show_target == True:
+                    self.parent.show_target = False
+                    self.parent._mgr.GetPane("target").Hide()
+                    self.parent.activemap.SetSelection(0)
+                    self.parent.activemap.Enable(False)
+                    self.parent.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
+                    self.parent._mgr.Update()
+
+        self.parent.UpdateColours(srcrender, srcrenderVector, tgtrender, tgtrenderVector)
+
+    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.parent.goutput.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()


Property changes on: grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native

Added: grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py	                        (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -0,0 +1,1123 @@
+"""!
+ at package gcpmapdisp.py
+
+ at brief display to manage ground control points with two toolbars, one for
+various display management functions, one for manipulating GCPs.
+
+Classes:
+- MapFrame
+
+(C) 2006-2010 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.
+
+Derived from mapdisp.py
+
+ at author Markus Metz
+"""
+
+import os
+import sys
+import glob
+import math
+import tempfile
+import copy
+
+import globalvar
+if not os.getenv("GRASS_WXBUNDLED"):
+    globalvar.CheckForWx()
+import wx
+import wx.aui
+
+try:
+    import subprocess
+except:
+    CompatPath = os.path.join(globalvar.ETCWXDIR)
+    sys.path.append(CompatPath)
+    from compat import subprocess
+
+gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
+sys.path.append(gmpath)
+
+grassPath = os.path.join(globalvar.ETCDIR, "python")
+sys.path.append(grassPath)
+
+import render
+import toolbars
+import menuform
+import gselect
+import disp_print
+import gcmd
+import dbm
+import dbm_dialogs
+import globalvar
+import utils
+import gdialogs
+from grass.script import core as grass
+from debug import Debug
+from icon  import Icons
+from preferences import globalSettings as UserSettings
+
+from mapdisp_command import Command
+from mapdisp_window import BufferedWindow
+
+import images
+imagepath = images.__path__[0]
+sys.path.append(imagepath)
+
+###
+### global variables
+###
+# for standalone app
+cmdfilename = None
+
+class MapFrame(wx.Frame):
+    """!Main frame for map display window. Drawing takes place in
+    child double buffered drawing window.
+    """
+    def __init__(self, parent=None, id=wx.ID_ANY, title=_("Manage Ground Control Points"),
+                 style=wx.DEFAULT_FRAME_STYLE, toolbars=["gcpdisp"],
+                 tree=None, notebook=None, lmgr=None, page=None,
+                 Map=None, auimgr=None, **kwargs):
+        """!Main map display window with toolbars, statusbar and
+        DrawWindow
+
+        @param toolbars array of activated toolbars, e.g. ['map', 'digit']
+        @param tree reference to layer tree
+        @param notebook control book ID in Layer Manager
+        @param lmgr Layer Manager
+        @param page notebook page with layer tree
+        @param Map instance of render.Map
+        @param auimgs AUI manager
+        @param kwargs wx.Frame attribures
+        """
+        self._layerManager = lmgr   # Layer Manager object
+        self.Map        = Map       # instance of render.Map
+        self.tree       = tree      # Layer Manager layer tree object
+        self.page       = page      # Notebook page holding the layer tree
+        self.layerbook  = notebook  # Layer Manager layer tree notebook
+        self.parent     = parent
+        
+        if not kwargs.has_key('name'):
+            kwargs['name'] = 'GCPMapWindow'
+        wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
+        
+        # available cursors
+        self.cursors = {
+            # default: cross
+            # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
+            "default" : wx.StockCursor(wx.CURSOR_ARROW),
+            "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
+            "hand"    : wx.StockCursor(wx.CURSOR_HAND),
+            "pencil"  : wx.StockCursor(wx.CURSOR_PENCIL),
+            "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
+            }
+        
+        #
+        # set the size & system icon
+        #
+        self.SetClientSize(self.GetSize())
+        self.iconsize = (16, 16)
+
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
+
+        #
+        # Fancy gui
+        #
+        self._mgr = wx.aui.AuiManager(self)
+
+        #
+        # Add toolbars
+        #
+        self.toolbars = { 'map' : None,
+                          'vdigit' : None,
+                          'georect' : None, 
+                          'gcpdisp' : None, 
+                          'gcpman' : None, 
+                          'nviz' : None }
+
+        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
+        #
+        self.statusbar = self.CreateStatusBar(number=4, style=0)
+        self.statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.statusbarWin = dict()
+        self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
+                                  choices = [_("Coordinates"),
+                                             _("Extent"),
+                                             _("Comp. region"),
+                                             _("Show comp. extent"),
+                                             _("Display mode"),
+                                             _("Display geometry"),
+                                             _("Map scale"),
+                                             _("Go to GCP No."),
+                                             _("RMS error")])
+        # set StatusBar to Go to GCP No.
+        self.statusbarWin['toggle'].SetSelection(7)
+
+        self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
+        # auto-rendering checkbox
+        self.statusbarWin['render'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                                  label=_("Render"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
+        self.statusbarWin['render'].SetValue(UserSettings.Get(group='display',
+                                                              key='autoRendering',
+                                                              subkey='enabled'))
+        self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
+        # show region
+        self.statusbarWin['region'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                                  label=_("Show computational extent"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
+        
+        self.statusbarWin['region'].SetValue(False)
+        self.statusbarWin['region'].Hide()
+        self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
+                                                             "region extent (set with g.region). "
+                                                             "Display region drawn as a blue box inside the "
+                                                             "computational region, "
+                                                             "computational region inside a display region "
+                                                             "as a red box).")))
+        # set resolution
+        self.statusbarWin['resolution'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                                      label=_("Constrain display resolution to computational settings"))
+        self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
+        self.statusbarWin['resolution'].SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
+        self.statusbarWin['resolution'].Hide()
+        self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
+                                                                 "to computational region settings. "
+                                                                 "Default value for new map displays can "
+                                                                 "be set up in 'User GUI settings' dialog.")))
+        # map scale
+        self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
+                                                    style = wx.TE_PROCESS_ENTER,
+                                                    size=(150, -1))
+        self.statusbarWin['mapscale'].SetItems(['1:1000',
+                                                '1:5000',
+                                                '1:10000',
+                                                '1:25000',
+                                                '1:50000',
+                                                '1:100000',
+                                                '1:1000000'])
+        self.statusbarWin['mapscale'].Hide()
+        self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
+        self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
+
+        # go to
+        self.statusbarWin['goto'] = wx.SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
+                             min=0)
+        self.statusbar.Bind(wx.EVT_SPINCTRL, self.OnGoTo, self.statusbarWin['goto'])
+        self.statusbarWin['goto'].Hide()
+        self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
+
+        # projection, unused but BufferedWindow checks for it
+        self.statusbarWin['projection'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+                                                      label=_("Use defined projection"))
+        self.statusbarWin['projection'].SetValue(False)
+        size = self.statusbarWin['projection'].GetSize()
+        self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
+        self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
+                                                                 "in the statusbar. Projection can be "
+                                                                 "defined in GUI preferences dialog "
+                                                                 "(tab 'Display')")))
+        self.statusbarWin['projection'].Hide()
+
+        # mask
+        self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
+                                                  label = '')
+        self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
+        
+        # on-render gauge
+        self.statusbarWin['progress'] = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
+                                      range=0, style=wx.GA_HORIZONTAL)
+        self.statusbarWin['progress'].Hide()
+        
+        self.StatusbarReposition() # reposition statusbar
+
+        #
+        # Init map display (buffered DC & set default cursor)
+        #
+        self.grwiz.SwitchEnv('source')
+        self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
+                                          Map=self.SrcMap, tree=self.tree, lmgr=self._layerManager)
+
+        self.grwiz.SwitchEnv('target')
+        self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
+                                          Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        self.SrcMapWindow.SetCursor(self.cursors["cross"])
+        self.TgtMapWindow.SetCursor(self.cursors["cross"])
+
+        #
+        # initialize region values
+        #
+        self.__InitDisplay() 
+
+        #
+        # Bind various events
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
+        self.Bind(wx.EVT_SIZE,     self.OnDispResize)
+        self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
+        
+        #
+        # 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()
+        tgtwidth = (srcwidth + tgtwidth) / 2
+        self._mgr.GetPane("target").Hide()
+        self._mgr.Update()
+        self._mgr.GetPane("source").BestSize((tgtwidth, tgtheight))
+        self._mgr.GetPane("target").BestSize((tgtwidth, tgtheight))
+        if self.show_target:
+            self._mgr.GetPane("target").Show()
+        else:
+            self.activemap.Enable(False)
+        # called by GCPWizard
+        #self._mgr.Update()
+
+        #
+        # Init print module and classes
+        #
+        self.printopt = disp_print.PrintOptions(self, self.MapWindow)
+        
+        #
+        # Initialization of digitization tool
+        #
+        self.digit = None
+
+        # set active map
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        #
+        # Init zoom history for TgtMapWindow
+        #
+        self.TgtMapWindow.ZoomHistory(self.Map.region['n'],
+                                   self.Map.region['s'],
+                                   self.Map.region['e'],
+                                   self.Map.region['w'])
+        #
+        # Init zoom history
+        #
+        self.MapWindow.ZoomHistory(self.Map.region['n'],
+                                   self.Map.region['s'],
+                                   self.Map.region['e'],
+                                   self.Map.region['w'])
+
+        #
+        # 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
+
+    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
+         - 'georect' - georectifier
+         - 'nviz'    - 3D view mode
+        """
+        # default toolbar
+        if name == "map":
+            self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
+
+            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'] = toolbars.GCPDisplayToolbar(self)
+
+            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'] = toolbars.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 __InitDisplay(self):
+        """
+        Initialize map display, set dimensions and map region
+        """
+        self.width, self.height = self.GetClientSize()
+
+        Debug.msg(2, "MapFrame.__InitDisplay():")
+        self.grwiz.SwitchEnv('source')
+        self.SrcMap.ChangeMapSize(self.GetClientSize())
+        self.SrcMap.region = self.SrcMap.GetRegion() # g.region -upgc
+        self.grwiz.SwitchEnv('target')
+        self.TgtMap.ChangeMapSize(self.GetClientSize())
+        self.TgtMap.region = self.TgtMap.GetRegion() # g.region -upgc
+        # self.SrcMap.SetRegion() # adjust region to match display window
+        # self.TgtMap.SetRegion() # adjust region to match display window
+
+    def OnUpdateProgress(self, event):
+        """
+        Update progress bar info
+        """
+        self.statusbarWin['progress'].SetValue(event.value)
+        
+        event.Skip()
+        
+    def OnFocus(self, event):
+        """
+        Change choicebook page to match display.
+        Or set display for georectifying
+        """
+        if self._layerManager and \
+                self._layerManager.gcpmanagement:
+            # in GCP Management, set focus to current MapWindow for mouse actions
+            self.OnPointer(event)
+            self.MapWindow.SetFocus()
+        else:
+            # change bookcontrol page to page associated with display
+            # GCP Manager: use bookcontrol?
+            if self.page:
+                pgnum = self.layerbook.GetPageIndex(self.page)
+                if pgnum > -1:
+                    self.layerbook.SetSelection(pgnum)
+        
+        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)
+        """
+        # delete tmp map layers (queries)
+        qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
+        for layer in qlayer:
+            self.Map.DeleteLayer(layer)
+
+        self.SrcMapWindow.UpdateMap(render=True)
+        self.TgtMapWindow.UpdateMap(render=True)
+        self._mgr.Update()
+        
+        # update statusbar
+        self.StatusbarUpdate()
+
+    def OnPointer(self, event):
+        """!Pointer button clicked
+        """
+        # change the cursor
+        self.SrcMapWindow.SetCursor(self.cursors["cross"])
+        self.SrcMapWindow.mouse['use'] = "pointer"
+        self.SrcMapWindow.mouse['box'] = "point"
+        self.TgtMapWindow.SetCursor(self.cursors["cross"])
+        self.TgtMapWindow.mouse['use'] = "pointer"
+        self.TgtMapWindow.mouse['box'] = "point"
+
+    def OnZoomIn(self, event):
+        """
+        Zoom in the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "zoom"
+        self.MapWindow.mouse['box'] = "box"
+        self.MapWindow.zoomtype = 1
+        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+
+        if self.MapWindow == self.SrcMapWindow:
+            win = self.TgtMapWindow
+        elif self.MapWindow == self.TgtMapWindow:
+            win = self.SrcMapWindow
+
+        win.mouse['use'] = "zoom"
+        win.mouse['box'] = "box"
+        win.zoomtype = 1
+        win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        win.SetCursor(self.cursors["cross"])
+
+    def OnZoomOut(self, event):
+        """
+        Zoom out the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "zoom"
+        self.MapWindow.mouse['box'] = "box"
+        self.MapWindow.zoomtype = -1
+        self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+
+        if self.MapWindow == self.SrcMapWindow:
+            win = self.TgtMapWindow
+        elif self.MapWindow == self.TgtMapWindow:
+            win = self.SrcMapWindow
+
+        win.mouse['use'] = "zoom"
+        win.mouse['box'] = "box"
+        win.zoomtype = -1
+        win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+        
+        # change the cursor
+        win.SetCursor(self.cursors["cross"])
+
+    def OnZoomBack(self, event):
+        """
+        Zoom last (previously stored position)
+        """
+        self.MapWindow.ZoomBack()
+
+    def OnPan(self, event):
+        """
+        Panning, set mouse to drag
+        """
+        if self.toolbars['map']:
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "pan"
+        self.MapWindow.mouse['box'] = "pan"
+        self.MapWindow.zoomtype = 0
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["hand"])
+
+        if self.MapWindow == self.SrcMapWindow:
+            win = self.TgtMapWindow
+        elif self.MapWindow == self.TgtMapWindow:
+            win = self.SrcMapWindow
+
+        win.mouse['use'] = "pan"
+        win.mouse['box'] = "pan"
+        win.zoomtype = 0
+        
+        # change the cursor
+        win.SetCursor(self.cursors["hand"])
+
+    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 OnZoomRegion(self, event):
+        """
+        Zoom to region
+        """
+        self.Map.getRegion()
+        self.Map.getResolution()
+        self.UpdateMap()
+        # event.Skip()
+
+    def OnAlignRegion(self, event):
+        """
+        Align region
+        """
+        if not self.Map.alignRegion:
+            self.Map.alignRegion = True
+        else:
+            self.Map.alignRegion = False
+        # event.Skip()
+
+    def OnToggleRender(self, event):
+        """
+        Enable/disable auto-rendering
+        """
+        if self.statusbarWin['render'].GetValue():
+            self.OnRender(None)
+
+    def OnToggleShowRegion(self, event):
+        """
+        Show/Hide extent in map canvas
+        """
+        if self.statusbarWin['region'].GetValue():
+            # show extent
+            self.MapWindow.regionCoords = []
+        else:
+            del self.MapWindow.regionCoords
+
+        # redraw map if auto-rendering is enabled
+        if self.statusbarWin['render'].GetValue():
+            self.OnRender(None)
+
+    def OnToggleResolution(self, event):
+        """
+        Use resolution of computation region settings
+        for redering image instead of display resolution
+        """
+        # redraw map if auto-rendering is enabled
+        if self.statusbarWin['render'].GetValue():
+            self.OnRender(None)
+        
+    def OnToggleStatus(self, event):
+        """
+        Toggle status text
+        """
+        self.StatusbarUpdate()
+
+    def OnChangeMapScale(self, event):
+        """
+        Map scale changed by user
+        """
+        scale = event.GetString()
+
+        try:
+            if scale[:2] != '1:':
+                raise ValueError
+            value = int(scale[2:])
+        except ValueError:
+            self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
+            return
+
+        dEW = value * (self.Map.region['cols'] / self.ppm[0])
+        dNS = value * (self.Map.region['rows'] / self.ppm[1])
+        self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
+        self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
+        self.Map.region['w'] = self.Map.region['center_easting']  - dEW / 2.
+        self.Map.region['e'] = self.Map.region['center_easting']  + dEW / 2.
+        
+        # add to zoom history
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                                   self.Map.region['e'], self.Map.region['w'])
+        
+        # redraw a map
+        self.MapWindow.UpdateMap()
+        self.statusbarWin['mapscale'].SetFocus()
+        
+    def OnGoTo(self, event):
+        """
+        Go to position
+        """
+        #GCPNo = int(event.GetString())
+        GCPNo = self.statusbarWin['goto'].GetValue()
+
+        if GCPNo < 0 or GCPNo > len(self.mapcoordlist):
+            wx.MessageBox(parent=self,
+                  message="%s 1 - %s." % (_("Valid Range:"),
+                                 len(self.mapcoordlist)),
+                  caption=_("Invalid GCP Number"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+
+        if GCPNo == 0:
+            return
+
+        self.list.selectedkey = GCPNo
+        self.list.selected = self.list.FindItemData(-1, GCPNo)
+        self.list.render = False
+        self.list.SetItemState(self.list.selected,
+                          wx.LIST_STATE_SELECTED,
+                          wx.LIST_STATE_SELECTED)
+        self.list.render = True
+        
+        # Source MapWindow:
+        begin = (self.mapcoordlist[GCPNo][1], self.mapcoordlist[GCPNo][2])
+        begin = self.SrcMapWindow.Cell2Pixel(begin)
+        end = begin
+        self.SrcMapWindow.Zoom(begin, end, 0)
+
+        # redraw map
+        self.SrcMapWindow.UpdateMap()
+
+        if self.show_target:
+            # Target MapWindow:
+            begin = (self.mapcoordlist[GCPNo][3], self.mapcoordlist[GCPNo][4])
+            begin = self.TgtMapWindow.Cell2Pixel(begin)
+            end = begin
+            self.TgtMapWindow.Zoom(begin, end, 0)
+
+            # redraw map
+            self.TgtMapWindow.UpdateMap()
+
+        self.statusbarWin['goto'].SetFocus()
+        
+    def StatusbarUpdate(self):
+        """!Update statusbar content"""
+
+        self.statusbarWin['region'].Hide()
+        self.statusbarWin['resolution'].Hide()
+        self.statusbarWin['mapscale'].Hide()
+        self.statusbarWin['goto'].Hide()
+        self.mapScaleValue = self.ppm = None
+
+        if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
+            self.statusbar.SetStatusText("", 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
+            sel = self.statusbarWin['toggle'].GetSelection()
+            if sel == 1:
+                region = self.Map.region
+            else:
+                region = self.Map.GetRegion() # computation region
+
+            precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                                             subkey = 'precision'))
+            format = UserSettings.Get(group = 'projection', key = 'format',
+                                      subkey = 'll')
+            
+            if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
+                w, s = utils.Deg2DMS(region["w"], region["s"],
+                                     string = False, precision = precision)
+                e, n = utils.Deg2DMS(region["e"], region["n"],
+                                     string = False, precision = precision)
+                if sel == 1:
+                    self.statusbar.SetStatusText("%s - %s, %s - %s" %
+                                                 (w, e, s, n), 0)
+                else:
+                    ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
+                                                 string = False, precision = precision)
+                    self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
+                                                 (w, e, s, n, ewres, nsres), 0)
+            else:
+                w, s = region["w"], region["s"]
+                e, n = region["e"], region["n"]
+                if sel == 1:
+                    self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
+                                                 (precision, w, precision, e,
+                                                  precision, s, precision, n), 0)
+                else:
+                    ewres, nsres = region['ewres'], region['nsres']
+                    self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
+                                                 (precision, w, precision, e,
+                                                  precision, s, precision, n,
+                                                  precision, ewres, precision, nsres), 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
+            self.statusbar.SetStatusText("", 0)
+            self.statusbarWin['region'].Show()
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
+            self.statusbar.SetStatusText("", 0)
+            self.statusbarWin['resolution'].Show()
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
+            self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
+                                         (self.Map.region["rows"], self.Map.region["cols"],
+                                          self.Map.region["nsres"], self.Map.region["ewres"]), 0)
+            # enable long help
+            self.StatusbarEnableLongHelp()
+
+        elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
+            # TODO: need to be fixed...
+            ### screen X region problem
+            ### user should specify ppm
+            dc = wx.ScreenDC()
+            dpSizePx = wx.DisplaySize()   # display size in pixels
+            dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
+            dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
+            sysPpi  = dc.GetPPI()
+            comPpi = (dpSizePx[0] / dpSizeIn[0],
+                      dpSizePx[1] / dpSizeIn[1])
+
+            ppi = comPpi                  # pixel per inch
+            self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
+                        (ppi[1] / 2.54) * 100)
+
+            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
+                      "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
+                          (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
+                           dpSizeIn[0], dpSizeIn[1],
+                           sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
+                           self.ppm[0], self.ppm[1]))
+
+            region = self.Map.region
+
+            heightCm = region['rows'] / self.ppm[1] * 100
+            widthCm  = region['cols'] / self.ppm[0] * 100
+
+            Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
+                      (widthCm, heightCm))
+
+            xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
+            yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
+            scale = (xscale + yscale) / 2.
+            
+            Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
+                          (xscale, yscale, scale))
+
+            self.statusbar.SetStatusText("")
+            try:
+                self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
+            except TypeError:
+                pass
+            self.mapScaleValue = scale
+            self.statusbarWin['mapscale'].Show()
+
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+
+        elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
+
+            self.statusbar.SetStatusText("")
+            max = self.list.GetItemCount()
+            if max < 1:
+                max = 1
+            self.statusbarWin['goto'].SetRange(0, max)
+
+            self.statusbarWin['goto'].Show()
+
+            # disable long help
+            self.StatusbarEnableLongHelp(False)
+        
+        elif self.statusbarWin['toggle'].GetSelection() == 8: # RMS error
+            self.statusbar.SetStatusText(_("Forward: %s, Backward: %s") %
+                                         (self.fwd_rmserror, self.bkw_rmserror))
+            # disable long help
+            # self.StatusbarEnableLongHelp(False)
+            
+        else:
+            self.statusbar.SetStatusText("", 1)
+
+    def StatusbarEnableLongHelp(self, enable=True):
+        """!Enable/disable toolbars long help"""
+        for toolbar in self.toolbars.itervalues():
+            if toolbar:
+                toolbar.EnableLongHelp(enable)
+                
+    def StatusbarReposition(self):
+        """!Reposition checkbox in statusbar"""
+        # reposition checkbox
+        widgets = [(0, self.statusbarWin['region']),
+                   (0, self.statusbarWin['resolution']),
+                   (0, self.statusbarWin['mapscale']),
+                   (0, self.statusbarWin['progress']),
+                   (0, self.statusbarWin['goto']),
+                   (1, self.statusbarWin['toggle']),
+                   (2, self.statusbarWin['mask']),
+                   (3, self.statusbarWin['render'])]
+        for idx, win in widgets:
+            rect = self.statusbar.GetFieldRect(idx)
+            wWin, hWin = win.GetBestSize()
+            if idx == 0: # show region / mapscale / process bar
+                # -> size
+                if win == self.statusbarWin['progress']:
+                    wWin = rect.width - 6
+                # -> position
+                # if win == self.statusbarWin['region']:
+                # x, y = rect.x + rect.width - wWin, rect.y - 1
+                # align left
+                # else:
+                x, y = rect.x + 3, rect.y - 1
+                w, h = wWin, rect.height + 2
+            else: # choice || auto-rendering
+                x, y = rect.x, rect.y - 1
+                w, h = rect.width, rect.height + 2
+                if idx == 1: # choice
+                    h = hWin
+                elif idx == 2: # mask
+                    x += 5
+                    y += 4
+                elif idx == 3: # render
+                    x += 5
+
+            win.SetPosition((x, y))
+            win.SetSize((w, h))
+
+    def SaveToFile(self, event):
+        """!Save map to image
+        """
+        img = self.MapWindow.img
+        if not img:
+            gcmd.GMessage(parent = self,
+                          message = _("Nothing to render (empty map). Operation canceled."))
+            return
+        filetype, ltype = gdialogs.GetImageHandlers(img)
+
+        # get size
+        dlg = gdialogs.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.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 GetRender(self):
+        """!Returns current instance of render.Map()
+        """
+        return self.Map
+
+    def GetWindow(self):
+        """!Get map window"""
+        return self.MapWindow
+    
+    def FormatDist(self, dist):
+        """!Format length numbers and units in a nice way,
+        as a function of length. From code by Hamish Bowman
+        Grass Development Team 2006"""
+
+        mapunits = self.Map.projinfo['units']
+        if mapunits == 'metres': mapunits = 'meters'
+        outunits = mapunits
+        dist = float(dist)
+        divisor = 1.0
+
+        # figure out which units to use
+        if mapunits == 'meters':
+            if dist > 2500.0:
+                outunits = 'km'
+                divisor = 1000.0
+            else: outunits = 'm'
+        elif mapunits == 'feet':
+            # nano-bug: we match any "feet", but US Survey feet is really
+            #  5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
+            #  miles the tick markers are rounded to the nearest 10th of a
+            #  mile (528'), the difference in foot flavours is ignored.
+            if dist > 5280.0:
+                outunits = 'miles'
+                divisor = 5280.0
+            else:
+                outunits = 'ft'
+        elif 'degree' in mapunits:
+            if dist < 1:
+                outunits = 'min'
+                divisor = (1/60.0)
+            else:
+                outunits = 'deg'
+
+        # format numbers in a nice way
+        if (dist/divisor) >= 2500.0:
+            outdist = round(dist/divisor)
+        elif (dist/divisor) >= 1000.0:
+            outdist = round(dist/divisor,1)
+        elif (dist/divisor) > 0.0:
+            outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
+        else:
+            outdist = float(dist/divisor)
+
+        return (outdist, outunits)
+
+    def OnZoomToMap(self, event):
+        """!
+        Set display extents to match selected raster (including NULLs)
+        or vector map.
+        """
+        self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
+
+    def OnZoomToRaster(self, event):
+        """!
+        Set display extents to match selected raster map (ignore NULLs)
+        """
+        self.MapWindow.ZoomToMap(ignoreNulls = True)
+
+    def OnZoomToWind(self, event):
+        """!Set display geometry to match computational region
+        settings (set with g.region)
+        """
+        self.MapWindow.ZoomToWind()
+        
+    def OnZoomToDefault(self, event):
+        """!Set display geometry to match default region settings
+        """
+        self.MapWindow.ZoomToDefault()
+        
+    def OnZoomToSaved(self, event):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        self.MapWindow.ZoomToSaved()
+        
+    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 SetProperties(self, render=False, mode=0, showCompExtent=False,
+                      constrainRes=False, projection=False):
+        """!Set properies of map display window"""
+        self.statusbarWin['render'].SetValue(render)
+        self.statusbarWin['toggle'].SetSelection(mode)
+        self.StatusbarUpdate()
+        self.statusbarWin['region'].SetValue(showCompExtent)
+        self.statusbarWin['resolution'].SetValue(constrainRes)
+        if showCompExtent:
+            self.MapWindow.regionCoords = []
+        
+    def IsStandalone(self):
+        """!Check if Map display is standalone"""
+        if self._layerManager:
+            return False
+        
+        return True
+    
+    def GetLayerManager(self):
+        """!Get reference to Layer Manager
+
+        @return window reference
+        @return None (if standalone)
+        """
+        return self._layerManager
+    
+# end of class MapFrame


Property changes on: grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:keywords
   + Author Date Id
Added: svn:eol-style
   + native

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -143,6 +143,7 @@
         self.toolbars = { 'map' : None,
                           'vdigit' : None,
                           'georect' : None, 
+                          'gcpdisp' : None, 
                           'nviz' : None }
         for toolb in toolbars:
             self.AddToolbar(toolb)
@@ -303,6 +304,7 @@
         Currently known toolbars are:
          - 'map'     - basic map toolbar
          - 'vdigit'  - vector digitizer
+         - 'gcpdisp' - GCP Manager Display
          - 'georect' - georectifier
          - 'nviz'    - 3D view mode
         """
@@ -507,7 +509,7 @@
         """
         if self._layerManager and \
                 self._layerManager.georectifying:
-            # in georectifying session; display used to get get geographic
+            # in georectifying session; display used to get geographic
             # coordinates for GCPs
             self.OnPointer(event)
         else:

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -868,6 +868,17 @@
                 coordtype = 'mapcoord'
             self.parent.GetLayerManager().georectifying.DrawGCP(coordtype)
             
+        if not self.parent.IsStandalone() and \
+                self.parent.GetLayerManager().gcpmanagement:
+            # -> georectifier (redraw GCPs)
+            if self.parent.toolbars['gcpdisp']:
+                if self == self.parent.TgtMapWindow:
+                    coordtype = 'target'
+                else:
+                    coordtype = 'source'
+
+                self.parent.DrawGCP(coordtype)
+
         # 
         # clear measurement
         #
@@ -1180,6 +1191,9 @@
         elif event.RightUp():
             self.OnRightUp(event)
 
+        elif event.Entering():
+            self.OnMouseEnter(event)
+
         elif event.Moving():
             self.OnMouseMoving(event)
         
@@ -1977,6 +1991,19 @@
             self.DrawLines(pdc=self.pdcTmp)
         
         elif self.mouse["use"] == "pointer" and \
+                self.parent.GetLayerManager().gcpmanagement:
+            # -> GCP manager
+            if self.parent.toolbars['gcpdisp']:
+                coord = self.Pixel2Cell(self.mouse['end'])
+                if self.parent.MapWindow == self.parent.SrcMapWindow:
+                    coordtype = 'source'
+                else:
+                    coordtype = 'target'
+
+                self.parent.GetLayerManager().gcpmanagement.SetGCPData(coordtype, coord, self, confirm=True)
+                self.UpdateMap(render=False, renderVector=False)
+
+        elif self.mouse["use"] == "pointer" and \
                 self.parent.GetLayerManager().georectifying:
             # -> georectifying
             coord = self.Pixel2Cell(self.mouse['end'])
@@ -2396,6 +2423,21 @@
         # update statusbar
         self.parent.StatusbarUpdate()
         
+    def OnMouseEnter(self, event):
+        """!
+        Mouse entered window and no mouse buttons were pressed
+        """
+        if self.parent.GetLayerManager().gcpmanagement:
+            if self.parent.toolbars['gcpdisp']:
+                if not self.parent.MapWindow == self:
+                    self.parent.MapWindow = self
+                    self.parent.Map = self.Map
+                    self.parent.UpdateActive(self)
+                    # needed for wingrass
+                    self.SetFocus()
+        else:
+            event.Skip()
+
     def OnMouseMoving(self, event):
         """!
         Motion event and no mouse buttons were pressed
@@ -2570,6 +2612,9 @@
         elif zoomtype == 0:
             dx = x1 - x2
             dy = y1 - y2
+            if dx == 0 and dy == 0:
+                dx = x1 - self.Map.width / 2
+                dy = y1 - self.Map.height / 2
             newreg['w'], newreg['n'] = self.Pixel2Cell((dx, dy))
             newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + dx,
                                                         self.Map.height + dy))
@@ -2628,6 +2673,8 @@
                 toolbar = self.parent.toolbars['map']
             elif self.parent.GetName() == 'GRMapWindow':
                 toolbar = self.parent.toolbars['georect']
+            elif self.parent.GetName() == 'GCPMapWindow':
+                toolbar = self.parent.toolbars['gcpdisp']
             
             toolbar.Enable('zoomback', enable = False)
         
@@ -2672,6 +2719,8 @@
             toolbar = self.parent.toolbars['map']
         elif self.parent.GetName() == 'GRMapWindow':
             toolbar = self.parent.toolbars['georect']
+        elif self.parent.GetName() == 'GCPMapWindow':
+            toolbar = self.parent.toolbars['gcpdisp']
         
         toolbar.Enable('zoomback', enable)
         

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -434,6 +434,21 @@
                     'enabled' : True
                     },
                 },
+            'gcpman' : {
+                'rms' : {
+                    'highestonly' : True,
+                    'sdfactor' : 1,
+                    },
+                'symbol' : {
+                    'color' : (0, 0, 255, 255),
+                    'hcolor' : (255, 0, 0, 255),
+                    'scolor' : (0, 255, 0, 255),
+                    'ucolor' : (255, 165, 0, 255),
+                    'unused' : True,
+                    'size' : 8,
+                    'width' : 2,
+                    },
+                },
             'georect' : {
                 'symbol' : {
                     'color' : (0, 0, 255, 255),

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -346,6 +346,153 @@
                      self.printmap):
             self.EnableTool(tool, enabled)
         
+class GCPManToolbar(AbstractToolbar):
+    """!
+    Toolbar for managing ground control points
+
+    @param parent reference to GCP widget
+    """
+    def __init__(self, parent):
+        AbstractToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self.ToolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def ToolbarData(self):
+        self.gcpSave = wx.NewId()
+        self.gcpReload = wx.NewId()
+        self.gcpAdd = wx.NewId()
+        self.gcpDelete = wx.NewId()
+        self.gcpClear = wx.NewId()
+        self.rms = wx.NewId()
+        self.georect = wx.NewId()
+
+        return (
+            (self.gcpSave, 'grGcpSave', Icons["grGcpSave"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpSave"].GetLabel(), Icons["grGcpSave"].GetDesc(),
+             self.parent.SaveGCPs),
+            (self.gcpReload, 'grGcpReload', Icons["grGcpReload"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpReload"].GetLabel(), Icons["grGcpReload"].GetDesc(), 
+             self.parent.ReloadGCPs),
+            ("", "", "", "", "", "", ""),
+            (self.gcpAdd, 'grGrGcpAdd', Icons["grGcpAdd"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpAdd"].GetLabel(), Icons["grGcpAdd"].GetDesc(),
+             self.parent.AddGCP),
+            (self.gcpDelete, 'grGrGcpDelete', Icons["grGcpDelete"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpDelete"].GetLabel(), Icons["grGcpDelete"].GetDesc(), 
+             self.parent.DeleteGCP),
+            (self.gcpClear, 'grGcpClear', Icons["grGcpClear"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpClear"].GetLabel(), Icons["grGcpClear"].GetDesc(), 
+             self.parent.ClearGCP),
+            ("", "", "", "", "", "", ""),
+            (self.rms, 'grGcpRms', Icons["grGcpRms"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["grGcpRms"].GetLabel(), Icons["grGcpRms"].GetDesc(),
+             self.parent.OnRMS),
+            (self.georect, 'grGeorect', Icons["grGeorect"].GetBitmap(), 
+             wx.ITEM_NORMAL, Icons["grGeorect"].GetLabel(), Icons["grGeorect"].GetDesc(),
+             self.parent.OnGeorect),
+            )
+    
+class GCPDisplayToolbar(AbstractToolbar):
+    """
+    GCP Display toolbar
+    """
+    def __init__(self, parent):
+        """!
+        GCP Display toolbar constructor
+        """
+        AbstractToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self.ToolbarData())
+        
+        # add tool to toggle active map window
+        self.togglemapid = wx.NewId()
+        self.togglemap = wx.Choice(parent=self, id=self.togglemapid,
+						    choices = [_('source'), _('target')],
+						    style=wx.CB_READONLY)
+
+        self.InsertControl(10, self.togglemap)
+
+        self.SetToolShortHelp(self.togglemapid, '%s %s %s' % (_('Set map canvas for '),
+                                                              Icons["zoom_back"].GetLabel(),
+                                                              _(' / Zoom to map')))
+
+        # realize the toolbar
+        self.Realize()
+        
+        self.action = { 'id' : self.gcpset }
+        self.defaultAction = { 'id' : self.gcpset,
+                               'bind' : self.parent.OnPointer }
+        
+        self.OnTool(None)
+        
+        self.EnableTool(self.zoomback, False)
+        
+    def ToolbarData(self):
+        """!Toolbar data"""
+        self.displaymap = wx.NewId()
+        self.rendermap = wx.NewId()
+        self.erase = wx.NewId()
+        self.gcpset = wx.NewId()
+        self.pan = wx.NewId()
+        self.zoomin = wx.NewId()
+        self.zoomout = wx.NewId()
+        self.zoomback = wx.NewId()
+        self.zoomtomap = wx.NewId()
+        self.zoommenu = wx.NewId()
+        self.settings = wx.NewId()
+        self.helpid = wx.NewId()
+        self.quit = wx.NewId()
+        
+        # tool, label, bitmap, kind, shortHelp, longHelp, handler
+        return (
+            (self.displaymap, "displaymap", Icons["displaymap"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["displaymap"].GetLabel(), Icons["displaymap"].GetDesc(),
+             self.parent.OnDraw),
+            (self.rendermap, "rendermap", Icons["rendermap"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["rendermap"].GetLabel(), Icons["rendermap"].GetDesc(),
+             self.parent.OnRender),
+            (self.erase, "erase", Icons["erase"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["erase"].GetLabel(), Icons["erase"].GetDesc(),
+             self.parent.OnErase),
+            ("", "", "", "", "", "", ""),
+            (self.gcpset, "grGcpSet", Icons["grGcpSet"].GetBitmap(),
+             wx.ITEM_RADIO, Icons["grGcpSet"].GetLabel(), Icons["grGcpSet"].GetDesc(),
+             self.parent.OnPointer),
+            (self.pan, "pan", Icons["pan"].GetBitmap(),
+             wx.ITEM_RADIO, Icons["pan"].GetLabel(), Icons["pan"].GetDesc(),
+             self.parent.OnPan),
+            (self.zoomin, "zoom_in", Icons["zoom_in"].GetBitmap(),
+             wx.ITEM_RADIO, Icons["zoom_in"].GetLabel(), Icons["zoom_in"].GetDesc(),
+             self.parent.OnZoomIn),
+            (self.zoomout, "zoom_out", Icons["zoom_out"].GetBitmap(),
+             wx.ITEM_RADIO, Icons["zoom_out"].GetLabel(), Icons["zoom_out"].GetDesc(),
+             self.parent.OnZoomOut),
+            (self.zoommenu, "zoommenu", Icons["zoommenu"].GetBitmap(),
+             wx.ITEM_NORMAL, _("Adjust display zoom"), Icons["zoommenu"].GetDesc(),
+             self.parent.OnZoomMenuGCP),
+            ("", "", "", "", "", "", ""),
+            (self.zoomback, "zoom_back", Icons["zoom_back"].GetBitmap(),
+             wx.ITEM_NORMAL, Icons["zoom_back"].GetLabel(), Icons["zoom_back"].GetDesc(),
+             self.parent.OnZoomBack),
+            (self.zoomtomap, "zoomtomap", Icons["zoom_extent"].GetBitmap(),
+             wx.ITEM_NORMAL, _("Zoom to map"), _("Zoom to displayed map"),
+             self.parent.OnZoomToMap),
+            ("", "", "", "", "", "", ""),
+            (self.settings, 'grSettings', Icons["grSettings"].GetBitmap(), 
+             wx.ITEM_NORMAL, Icons["grSettings"].GetLabel(), Icons["grSettings"].GetDesc(),
+             self.parent.OnSettings),
+            (self.helpid, 'grHelp', wx.ArtProvider.GetBitmap(id=wx.ART_HELP, client=wx.ART_TOOLBAR, size=globalvar.toolbarSize), 
+             wx.ITEM_NORMAL, _('Show Help'), _('Show Help for GCP Manager'),
+             self.parent.OnHelp),
+            ("", "", "", "", "", "", ""),
+            (self.quit, 'grGcpQuit', Icons["grGcpQuit"].GetBitmap(), 
+             wx.ITEM_NORMAL, Icons["grGcpQuit"].GetLabel(), Icons["grGcpQuit"].GetDesc(),
+             self.parent.OnQuit)
+            )
+    
 class GRToolbar(AbstractToolbar):
     """
     Georectification toolbar

Added: grass/branches/develbranch_6/gui/wxpython/images/small_down_arrow.png
===================================================================
(Binary files differ)


Property changes on: grass/branches/develbranch_6/gui/wxpython/images/small_down_arrow.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: grass/branches/develbranch_6/gui/wxpython/images/small_up_arrow.png
===================================================================
(Binary files differ)


Property changes on: grass/branches/develbranch_6/gui/wxpython/images/small_up_arrow.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: grass/branches/develbranch_6/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxgui.py	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/wxgui.py	2010-09-01 13:04:23 UTC (rev 43384)
@@ -120,6 +120,7 @@
         self.workspaceFile = workspace    # workspace file
         self.workspaceChanged = False     # track changes in workspace
         self.georectifying = None         # reference to GCP class or None
+        self.gcpmanagement = None         # reference to GCP class or None
         # list of open dialogs
         self.dialogs        = dict()
         self.dialogs['preferences'] = None
@@ -252,6 +253,12 @@
         """
         georect.GeorectWizard(self)
 
+    def OnGCPManager(self, event):
+        """!Launch georectifier module
+        """
+        import gui_modules.gcpmanager as gcpmanager
+        gcpmanager.GCPWizard(self)
+
     def OnGModeler(self, event):
         """!Launch Graphical Modeler"""
         win = gmodeler.ModelFrame(parent = self)

Modified: grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml	2010-09-01 13:02:05 UTC (rev 43383)
+++ grass/branches/develbranch_6/gui/wxpython/xml/menudata.xml	2010-09-01 13:04:23 UTC (rev 43384)
@@ -621,6 +621,11 @@
 	</menu>
 	<separator />
 	<menuitem>
+	  <label>Manage Ground Control Points</label>
+	  <help>Manage Ground Control Points for Georectification</help>
+	  <handler>OnGCPManager</handler>
+	</menuitem>
+	<menuitem>
 	  <label>Georectify</label>
 	  <help>Georectify raster and vector maps</help>
 	  <handler>OnGeorectify</handler>



More information about the grass-commit mailing list