[GRASS-SVN] r49347 - in grass/trunk/gui/wxpython: . core dbm gcp gmodeler gui_core gui_modules icons lmgr location_wizard mapdisp modules nviz psmap scripts tools vdigit wxplot

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Nov 24 06:46:55 EST 2011


Author: martinl
Date: 2011-11-24 03:46:55 -0800 (Thu, 24 Nov 2011)
New Revision: 49347

Added:
   grass/trunk/gui/wxpython/core/
   grass/trunk/gui/wxpython/core/debug.py
   grass/trunk/gui/wxpython/core/gcmd.py
   grass/trunk/gui/wxpython/core/globalvar.py
   grass/trunk/gui/wxpython/core/menudata.py
   grass/trunk/gui/wxpython/core/render.py
   grass/trunk/gui/wxpython/core/settings.py
   grass/trunk/gui/wxpython/core/units.py
   grass/trunk/gui/wxpython/core/utils.py
   grass/trunk/gui/wxpython/core/workspace.py
   grass/trunk/gui/wxpython/create__init__.py
   grass/trunk/gui/wxpython/dbm/
   grass/trunk/gui/wxpython/dbm/dialogs.py
   grass/trunk/gui/wxpython/dbm/manager.py
   grass/trunk/gui/wxpython/dbm/sqlbuilder.py
   grass/trunk/gui/wxpython/dbm/vinfo.py
   grass/trunk/gui/wxpython/gcp/
   grass/trunk/gui/wxpython/gcp/manager.py
   grass/trunk/gui/wxpython/gcp/mapdisp.py
   grass/trunk/gui/wxpython/gcp/toolbars.py
   grass/trunk/gui/wxpython/gmodeler/
   grass/trunk/gui/wxpython/gmodeler/dialogs.py
   grass/trunk/gui/wxpython/gmodeler/frame.py
   grass/trunk/gui/wxpython/gmodeler/model.py
   grass/trunk/gui/wxpython/gmodeler/model_file.py
   grass/trunk/gui/wxpython/gmodeler/preferences.py
   grass/trunk/gui/wxpython/gui_core/
   grass/trunk/gui/wxpython/gui_core/dialogs.py
   grass/trunk/gui/wxpython/gui_core/forms.py
   grass/trunk/gui/wxpython/gui_core/ghelp.py
   grass/trunk/gui/wxpython/gui_core/goutput.py
   grass/trunk/gui/wxpython/gui_core/gselect.py
   grass/trunk/gui/wxpython/gui_core/mapdisp.py
   grass/trunk/gui/wxpython/gui_core/mapwindow.py
   grass/trunk/gui/wxpython/gui_core/menu.py
   grass/trunk/gui/wxpython/gui_core/preferences.py
   grass/trunk/gui/wxpython/gui_core/prompt.py
   grass/trunk/gui/wxpython/gui_core/toolbars.py
   grass/trunk/gui/wxpython/gui_core/widgets.py
   grass/trunk/gui/wxpython/lmgr/
   grass/trunk/gui/wxpython/lmgr/layertree.py
   grass/trunk/gui/wxpython/lmgr/menudata.py
   grass/trunk/gui/wxpython/lmgr/pyshell.py
   grass/trunk/gui/wxpython/lmgr/toolbars.py
   grass/trunk/gui/wxpython/location_wizard/
   grass/trunk/gui/wxpython/location_wizard/base.py
   grass/trunk/gui/wxpython/location_wizard/dialogs.py
   grass/trunk/gui/wxpython/location_wizard/wizard.py
   grass/trunk/gui/wxpython/mapdisp/
   grass/trunk/gui/wxpython/mapdisp/frame.py
   grass/trunk/gui/wxpython/mapdisp/gprint.py
   grass/trunk/gui/wxpython/mapdisp/mapwindow.py
   grass/trunk/gui/wxpython/mapdisp/statusbar.py
   grass/trunk/gui/wxpython/mapdisp/toolbars.py
   grass/trunk/gui/wxpython/modules/
   grass/trunk/gui/wxpython/modules/colorrules.py
   grass/trunk/gui/wxpython/modules/histogram.py
   grass/trunk/gui/wxpython/modules/mcalc_builder.py
   grass/trunk/gui/wxpython/modules/ogc_services.py
   grass/trunk/gui/wxpython/modules/vclean.py
   grass/trunk/gui/wxpython/nviz/
   grass/trunk/gui/wxpython/nviz/animation.py
   grass/trunk/gui/wxpython/nviz/main.py
   grass/trunk/gui/wxpython/nviz/mapwindow.py
   grass/trunk/gui/wxpython/nviz/preferences.py
   grass/trunk/gui/wxpython/nviz/tools.py
   grass/trunk/gui/wxpython/nviz/workspace.py
   grass/trunk/gui/wxpython/nviz/wxnviz.py
   grass/trunk/gui/wxpython/psmap/
   grass/trunk/gui/wxpython/psmap/dialogs.py
   grass/trunk/gui/wxpython/psmap/frame.py
   grass/trunk/gui/wxpython/psmap/menudata.py
   grass/trunk/gui/wxpython/psmap/toolbars.py
   grass/trunk/gui/wxpython/states.txt
   grass/trunk/gui/wxpython/vdigit/
   grass/trunk/gui/wxpython/vdigit/dialogs.py
   grass/trunk/gui/wxpython/vdigit/main.py
   grass/trunk/gui/wxpython/vdigit/mapwindow.py
   grass/trunk/gui/wxpython/vdigit/preferences.py
   grass/trunk/gui/wxpython/vdigit/toolbars.py
   grass/trunk/gui/wxpython/vdigit/wxdigit.py
   grass/trunk/gui/wxpython/vdigit/wxdisplay.py
   grass/trunk/gui/wxpython/wxplot/
   grass/trunk/gui/wxpython/wxplot/base.py
   grass/trunk/gui/wxpython/wxplot/dialogs.py
   grass/trunk/gui/wxpython/wxplot/histogram.py
   grass/trunk/gui/wxpython/wxplot/profile.py
   grass/trunk/gui/wxpython/wxplot/scatter.py
Removed:
   grass/trunk/gui/wxpython/gui_modules/__init__.py
   grass/trunk/gui/wxpython/gui_modules/colorrules.py
   grass/trunk/gui/wxpython/gui_modules/dbm.py
   grass/trunk/gui/wxpython/gui_modules/dbm_base.py
   grass/trunk/gui/wxpython/gui_modules/dbm_dialogs.py
   grass/trunk/gui/wxpython/gui_modules/debug.py
   grass/trunk/gui/wxpython/gui_modules/disp_print.py
   grass/trunk/gui/wxpython/gui_modules/gcmd.py
   grass/trunk/gui/wxpython/gui_modules/gcpmanager.py
   grass/trunk/gui/wxpython/gui_modules/gcpmapdisp.py
   grass/trunk/gui/wxpython/gui_modules/gdialogs.py
   grass/trunk/gui/wxpython/gui_modules/ghelp.py
   grass/trunk/gui/wxpython/gui_modules/globalvar.py
   grass/trunk/gui/wxpython/gui_modules/gmodeler.py
   grass/trunk/gui/wxpython/gui_modules/goutput.py
   grass/trunk/gui/wxpython/gui_modules/gpyshell.py
   grass/trunk/gui/wxpython/gui_modules/gselect.py
   grass/trunk/gui/wxpython/gui_modules/histogram.py
   grass/trunk/gui/wxpython/gui_modules/layertree.py
   grass/trunk/gui/wxpython/gui_modules/location_wizard.py
   grass/trunk/gui/wxpython/gui_modules/mapdisp.py
   grass/trunk/gui/wxpython/gui_modules/mapdisp_statusbar.py
   grass/trunk/gui/wxpython/gui_modules/mapdisp_vdigit.py
   grass/trunk/gui/wxpython/gui_modules/mapdisp_window.py
   grass/trunk/gui/wxpython/gui_modules/mcalc_builder.py
   grass/trunk/gui/wxpython/gui_modules/menu.py
   grass/trunk/gui/wxpython/gui_modules/menudata.py
   grass/trunk/gui/wxpython/gui_modules/menuform.py
   grass/trunk/gui/wxpython/gui_modules/nviz.py
   grass/trunk/gui/wxpython/gui_modules/nviz_animation.py
   grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py
   grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py
   grass/trunk/gui/wxpython/gui_modules/nviz_tools.py
   grass/trunk/gui/wxpython/gui_modules/ogc_services.py
   grass/trunk/gui/wxpython/gui_modules/preferences.py
   grass/trunk/gui/wxpython/gui_modules/prompt.py
   grass/trunk/gui/wxpython/gui_modules/psmap.py
   grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py
   grass/trunk/gui/wxpython/gui_modules/render.py
   grass/trunk/gui/wxpython/gui_modules/sqlbuilder.py
   grass/trunk/gui/wxpython/gui_modules/states.txt
   grass/trunk/gui/wxpython/gui_modules/toolbars.py
   grass/trunk/gui/wxpython/gui_modules/units.py
   grass/trunk/gui/wxpython/gui_modules/utils.py
   grass/trunk/gui/wxpython/gui_modules/vclean.py
   grass/trunk/gui/wxpython/gui_modules/vdigit.py
   grass/trunk/gui/wxpython/gui_modules/workspace.py
   grass/trunk/gui/wxpython/gui_modules/wxnviz.py
   grass/trunk/gui/wxpython/gui_modules/wxplot.py
   grass/trunk/gui/wxpython/gui_modules/wxplot_dialogs.py
   grass/trunk/gui/wxpython/gui_modules/wxvdigit.py
   grass/trunk/gui/wxpython/gui_modules/wxvdriver.py
Modified:
   grass/trunk/gui/wxpython/Makefile
   grass/trunk/gui/wxpython/icons/grass_icons.py
   grass/trunk/gui/wxpython/icons/icon.py
   grass/trunk/gui/wxpython/scripts/r.li.setup.py
   grass/trunk/gui/wxpython/scripts/vkrige.py
   grass/trunk/gui/wxpython/tools/update_menudata.py
   grass/trunk/gui/wxpython/wxgui.py
Log:
wxGUI major code reorganization

Modified: grass/trunk/gui/wxpython/Makefile
===================================================================
--- grass/trunk/gui/wxpython/Makefile	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/Makefile	2011-11-24 11:46:55 UTC (rev 49347)
@@ -9,21 +9,30 @@
 
 ETCDIR = $(ETC)/gui/wxpython
 
-SRCFILES := $(wildcard scripts/* compat/* gui_modules/* icons/*.* xml/*) gis_set.py gis_set_error.py wxgui.py README
+SRCFILES := $(wildcard compat/* icons/*.* scripts/* xml/*) \
+	$(wildcard core/* dbm/* gcp/* gmodeler/* gui_core/* lmgr/* \
+	mapdisp/* modules/* nviz/* psmap/* vdigit/* wxplot/* ) \
+	gis_set.py gis_set_error.py wxgui.py README
 DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
 
-DSTDIRS := $(patsubst %,$(ETCDIR)/%,compat gui_modules icons scripts xml)
+PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbm gcp gmodeler gui_core lmgr \
+	mapdisp modules nviz psmap vdigit wxplot)
+DSTDIRS := $(patsubst %,$(ETCDIR)/%,compat icons scripts xml)
 
 default: $(DSTFILES) menustrings.py
 	$(MAKE) parsubdirs
 
-$(ETCDIR)/%: % | $(DSTDIRS)
+$(ETCDIR)/%: % | $(PYDSTDIRS) $(DSTDIRS)
 	$(INSTALL_DATA) $< $@
 
-menustrings.py: gui_modules/menudata.py $(ETCDIR)/xml/menudata.xml $(ETCDIR)/xml/menudata_modeler.xml 
+menustrings.py: core/menudata.py $(ETCDIR)/xml/menudata.xml $(ETCDIR)/xml/menudata_modeler.xml 
 	$(call run_grass,$(PYTHON) $< > $@)
 	$(call run_grass,$(PYTHON) $< "modeler" >> $@)
 
+$(PYDSTDIRS): %: | $(ETCDIR)
+	$(MKDIR) $@
+	$(call run_grass,$(PYTHON) create__init__.py $@)
+
 $(DSTDIRS): %: | $(ETCDIR)
 	$(MKDIR) $@
 

Copied: grass/trunk/gui/wxpython/core/debug.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/debug.py)
===================================================================
--- grass/trunk/gui/wxpython/core/debug.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/debug.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,75 @@
+"""!
+ at package core.debug
+
+ at brief wxGUI debugging
+
+Classes:
+ - DebugMsg
+
+ at code
+from core.debug import Debug
+Debug.msg (3, 'debug message')
+ at endcode
+         
+(C) 2007-2009, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+
+import grass.script as grass
+
+class DebugMsg:
+    """!wxGUI debugging
+
+    @code
+    g.gisenv set=WX_DEBUG=[0-5]
+    @endcode
+    """
+    def __init__(self):
+        # default level
+        self.debuglevel = 0
+        
+        self.SetLevel()
+
+    def SetLevel(self):
+        """!Initialize gui debug level
+        """
+        self.debuglevel = int(grass.gisenv().get('WX_DEBUG', 0))
+        
+    def msg(self, level, message, *args):
+        """!Print debug message
+
+        @param level debug level (0-5)
+        @param message message to be printed
+        @param *args formatting params
+        """
+        # self.SetLevel()
+        if self.debuglevel > 0 and level > 0 and level <= self.debuglevel:
+            if args:
+                sys.stderr.write("GUI D%d/%d: " % (level, self.debuglevel) + \
+                    message % args + os.linesep)
+            else:
+                sys.stderr.write("GUI D%d/%d: " % (level, self.debuglevel) + \
+                                     message + os.linesep)
+            sys.stderr.flush() # force flush (required for MS Windows)
+        
+    def GetLevel(self):
+        """!Return current GUI debug level"""
+        return self.debuglevel
+
+# Debug instance
+Debug = DebugMsg()
+
+# testing
+if __name__ == "__main__":
+    from core import cmd as gcmd
+    gcmd.RunCommand('g.gisenv',
+                    set = 'DEBUG=3')
+                
+    for level in range (4):
+        Debug.msg (level, "message level=%d" % level)

Copied: grass/trunk/gui/wxpython/core/gcmd.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/gcmd.py)
===================================================================
--- grass/trunk/gui/wxpython/core/gcmd.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/gcmd.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,673 @@
+"""!
+ at package core.gcmd
+
+ at brief wxGUI command interface
+
+Classes:
+ - GError
+ - GWarning
+ - GMessage
+ - GException
+ - Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
+ - Command
+ - CommandThread
+
+Functions:
+ - RunCommand
+
+(C) 2007-2008, 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import time
+import errno
+import signal
+import locale
+import traceback
+
+import wx
+
+try:
+    import subprocess
+except:
+    compatPath = os.path.join(globalvar.ETCWXDIR, "compat")
+    sys.path.append(compatPath)
+    import subprocess
+if subprocess.mswindows:
+    from win32file import ReadFile, WriteFile
+    from win32pipe import PeekNamedPipe
+    import msvcrt
+else:
+    import select
+    import fcntl
+from threading import Thread
+
+from grass.script import core as grass
+
+from core       import globalvar
+from core.debug import Debug
+
+def DecodeString(string):
+    """!Decode string using system encoding
+    
+    @param string string to be decoded
+    
+    @return decoded string
+    """
+    if not string:
+        return string
+    
+    enc = locale.getdefaultlocale()[1]
+    if enc:
+        Debug.msg(5, "DecodeString(): enc=%s" % enc)
+        return string.decode(enc)
+    
+    return string
+
+def EncodeString(string):
+    """!Return encoded string using system locales
+    
+    @param string string to be encoded
+    
+    @return encoded string
+    """
+    if not string:
+        return string
+    enc = locale.getdefaultlocale()[1]
+    if enc:
+        Debug.msg(5, "EncodeString(): enc=%s" % enc)
+        return string.encode(enc)
+    
+    return string
+
+class GError:
+    def __init__(self, message, parent = None, caption = None, showTraceback = True):
+        if not caption:
+            caption = _('Error')
+        style = wx.OK | wx.ICON_ERROR | wx.CENTRE
+        exc_type, exc_value, exc_traceback = sys.exc_info()
+        if exc_traceback:
+            exception = traceback.format_exc()
+            reason = exception.splitlines()[-1].split(':', 1)[-1].strip()
+        
+        if Debug.GetLevel() > 0 and exc_traceback:
+            sys.stderr.write(exception)
+        
+        if showTraceback and exc_traceback:
+            wx.MessageBox(parent = parent,
+                          message = message + '\n\n%s: %s\n\n%s' % \
+                              (_('Reason'),
+                               reason, exception),
+                          caption = caption,
+                          style = style)
+        else:
+            wx.MessageBox(parent = parent,
+                          message = message,
+                          caption = caption,
+                          style = style)
+
+class GWarning:
+    def __init__(self, message, parent = None):
+        caption = _('Warning')
+        style = wx.OK | wx.ICON_WARNING | wx.CENTRE
+        wx.MessageBox(parent = parent,
+                      message = message,
+                      caption = caption,
+                      style = style)
+        
+class GMessage:
+    def __init__(self, message, parent = None):
+        caption = _('Message')
+        style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE
+        wx.MessageBox(parent = parent,
+                      message = message,
+                      caption = caption,
+                      style = style)
+
+class GException(Exception):
+    def __init__(self, value = ''):
+        self.value = value
+
+    def __str__(self):
+        return str(self.value)
+
+class Popen(subprocess.Popen):
+    """!Subclass subprocess.Popen"""
+    def __init__(self, args, **kwargs):
+        if subprocess.mswindows:
+            args = map(EncodeString, args)
+        
+        subprocess.Popen.__init__(self, args, **kwargs)
+        
+    def recv(self, maxsize = None):
+        return self._recv('stdout', maxsize)
+    
+    def recv_err(self, maxsize = None):
+        return self._recv('stderr', maxsize)
+
+    def send_recv(self, input = '', maxsize = None):
+        return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
+
+    def get_conn_maxsize(self, which, maxsize):
+        if maxsize is None:
+            maxsize = 1024
+        elif maxsize < 1:
+            maxsize = 1
+        return getattr(self, which), maxsize
+    
+    def _close(self, which):
+        getattr(self, which).close()
+        setattr(self, which, None)
+
+    def kill(self):
+        """!Try to kill running process"""
+        if subprocess.mswindows:
+            import win32api
+            handle = win32api.OpenProcess(1, 0, self.pid)
+            return (0 != win32api.TerminateProcess(handle, 0))
+	else:
+            try:
+                os.kill(-self.pid, signal.SIGTERM) # kill whole group
+            except OSError:
+                pass
+
+    if subprocess.mswindows:
+        def send(self, input):
+            if not self.stdin:
+                return None
+
+            try:
+                x = msvcrt.get_osfhandle(self.stdin.fileno())
+                (errCode, written) = WriteFile(x, input)
+            except ValueError:
+                return self._close('stdin')
+            except (subprocess.pywintypes.error, Exception), why:
+                if why[0] in (109, errno.ESHUTDOWN):
+                    return self._close('stdin')
+                raise
+
+            return written
+
+        def _recv(self, which, maxsize):
+            conn, maxsize = self.get_conn_maxsize(which, maxsize)
+            if conn is None:
+                return None
+            
+            try:
+                x = msvcrt.get_osfhandle(conn.fileno())
+                (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
+                if maxsize < nAvail:
+                    nAvail = maxsize
+                if nAvail > 0:
+                    (errCode, read) = ReadFile(x, nAvail, None)
+            except ValueError:
+                return self._close(which)
+            except (subprocess.pywintypes.error, Exception), why:
+                if why[0] in (109, errno.ESHUTDOWN):
+                    return self._close(which)
+                raise
+            
+            if self.universal_newlines:
+                read = self._translate_newlines(read)
+            return read
+
+    else:
+        def send(self, input):
+            if not self.stdin:
+                return None
+
+            if not select.select([], [self.stdin], [], 0)[1]:
+                return 0
+
+            try:
+                written = os.write(self.stdin.fileno(), input)
+            except OSError, why:
+                if why[0] == errno.EPIPE: #broken pipe
+                    return self._close('stdin')
+                raise
+
+            return written
+
+        def _recv(self, which, maxsize):
+            conn, maxsize = self.get_conn_maxsize(which, maxsize)
+            if conn is None:
+                return None
+            
+            flags = fcntl.fcntl(conn, fcntl.F_GETFL)
+            if not conn.closed:
+                fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+            
+            try:
+                if not select.select([conn], [], [], 0)[0]:
+                    return ''
+                
+                r = conn.read(maxsize)
+                
+                if not r:
+                    return self._close(which)
+    
+                if self.universal_newlines:
+                    r = self._translate_newlines(r)
+                return r
+            finally:
+                if not conn.closed:
+                    fcntl.fcntl(conn, fcntl.F_SETFL, flags)
+
+message = "Other end disconnected!"
+
+def recv_some(p, t = .1, e = 1, tr = 5, stderr = 0):
+    if tr < 1:
+        tr = 1
+    x = time.time()+t
+    y = []
+    r = ''
+    pr = p.recv
+    if stderr:
+        pr = p.recv_err
+    while time.time() < x or r:
+        r = pr()
+        if r is None:
+            if e:
+                raise Exception(message)
+            else:
+                break
+        elif r:
+            y.append(r)
+        else:
+            time.sleep(max((x-time.time())/tr, 0))
+    return ''.join(y)
+    
+def send_all(p, data):
+    while len(data):
+        sent = p.send(data)
+        if sent is None:
+            raise Exception(message)
+        data = buffer(data, sent)
+
+class Command:
+    """!Run command in separate thread. Used for commands launched
+    on the background.
+
+    If stdout/err is redirected, write() method is required for the
+    given classes.
+
+    @code
+        cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
+
+        if cmd.returncode == None:
+            print 'RUNNING?'
+        elif cmd.returncode == 0:
+            print 'SUCCESS'
+        else:
+            print 'FAILURE (%d)' % cmd.returncode
+    @endcode
+    """
+    def __init__ (self, cmd, stdin = None,
+                  verbose = None, wait = True, rerr = False,
+                  stdout = None, stderr = None):
+        """
+        @param cmd     command given as list
+        @param stdin   standard input stream
+        @param verbose verbose level [0, 3] (--q, --v)
+        @param wait    wait for child execution terminated
+        @param rerr    error handling (when GException raised).
+        True for redirection to stderr, False for GUI dialog,
+        None for no operation (quiet mode)
+        @param stdout  redirect standard output or None
+        @param stderr  redirect standard error output or None
+        """
+        Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
+        self.cmd = cmd
+        self.stderr = stderr
+	
+        #
+        # set verbosity level
+        #
+        verbose_orig = None
+        if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
+                ('--v' not in self.cmd and '--verbose' not in self.cmd):
+            if verbose is not None:
+                if verbose == 0:
+                    self.cmd.append('--quiet')
+                elif verbose == 3:
+                    self.cmd.append('--verbose')
+                else:
+                    verbose_orig = os.getenv("GRASS_VERBOSE")
+                    os.environ["GRASS_VERBOSE"] = str(verbose)
+
+        #
+        # create command thread
+        #
+        self.cmdThread = CommandThread(cmd, stdin,
+                                       stdout, stderr)
+        self.cmdThread.start()
+        
+        if wait:
+            self.cmdThread.join()
+            if self.cmdThread.module:
+                self.cmdThread.module.wait()
+                self.returncode = self.cmdThread.module.returncode
+            else:
+                self.returncode = 1
+        else:
+            self.cmdThread.join(0.5)
+            self.returncode = None
+
+        if self.returncode is not None:
+            Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % \
+                           (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
+            if rerr is not None and self.returncode != 0:
+                if rerr is False: # GUI dialog
+                    raise GException("%s '%s'%s%s%s %s%s" % \
+                                         (_("Execution failed:"),
+                                          ' '.join(self.cmd),
+                                          os.linesep, os.linesep,
+                                          _("Details:"),
+                                          os.linesep,
+                                          _("Error: ") + self.__GetError()))
+                elif rerr == sys.stderr: # redirect message to sys
+                    stderr.write("Execution failed: '%s'" % (' '.join(self.cmd)))
+                    stderr.write("%sDetails:%s%s" % (os.linesep,
+                                                     _("Error: ") + self.__GetError(),
+                                                     os.linesep))
+            else:
+                pass # nop
+        else:
+            Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % \
+                           (' '.join(cmd), wait, self.cmdThread.isAlive()))
+
+        if verbose_orig:
+            os.environ["GRASS_VERBOSE"] = verbose_orig
+        elif "GRASS_VERBOSE" in os.environ:
+            del os.environ["GRASS_VERBOSE"]
+            
+    def __ReadOutput(self, stream):
+        """!Read stream and return list of lines
+
+        @param stream stream to be read
+        """
+        lineList = []
+
+        if stream is None:
+            return lineList
+
+        while True:
+            line = stream.readline()
+            if not line:
+                break
+            line = line.replace('%s' % os.linesep, '').strip()
+            lineList.append(line)
+
+        return lineList
+                    
+    def __ReadErrOutput(self):
+        """!Read standard error output and return list of lines"""
+        return self.__ReadOutput(self.cmdThread.module.stderr)
+
+    def __ProcessStdErr(self):
+        """
+        Read messages/warnings/errors from stderr
+
+        @return list of (type, message)
+        """
+        if self.stderr is None:
+            lines = self.__ReadErrOutput()
+        else:
+            lines = self.cmdThread.error.strip('%s' % os.linesep). \
+                split('%s' % os.linesep)
+        
+        msg = []
+
+        type    = None
+        content = ""
+        for line in lines:
+            if len(line) == 0:
+                continue
+            if 'GRASS_' in line: # error or warning
+                if 'GRASS_INFO_WARNING' in line: # warning
+                    type = "WARNING"
+                elif 'GRASS_INFO_ERROR' in line: # error
+                    type = "ERROR"
+                elif 'GRASS_INFO_END': # end of message
+                    msg.append((type, content))
+                    type = None
+                    content = ""
+                
+                if type:
+                    content += line.split(':', 1)[1].strip()
+            else: # stderr
+                msg.append((None, line.strip()))
+
+        return msg
+
+    def __GetError(self):
+        """!Get error message or ''"""
+        if not self.cmdThread.module:
+            return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
+
+        for type, msg in self.__ProcessStdErr():
+            if type == 'ERROR':
+                enc = locale.getdefaultlocale()[1]
+                if enc:
+                    return unicode(msg, enc)
+                else:
+                    return msg
+        
+        return ''
+    
+class CommandThread(Thread):
+    """!Create separate thread for command. Used for commands launched
+    on the background."""
+    def __init__ (self, cmd, stdin = None,
+                  stdout = sys.stdout, stderr = sys.stderr):
+        """
+        @param cmd command (given as list)
+        @param stdin standard input stream 
+        @param stdout redirect standard output or None
+        @param stderr redirect standard error output or None
+        """
+        Thread.__init__(self)
+        
+        self.cmd    = cmd
+        self.stdin  = stdin
+        self.stdout = stdout
+        self.stderr = stderr
+        
+        self.module = None
+        self.error  = ''
+        
+        self._want_abort = False
+        self.aborted = False
+        
+        self.setDaemon(True)
+        
+        # set message formatting
+        self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
+        os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
+        
+    def __del__(self):
+        if self.message_format:
+            os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
+        else:
+            del os.environ["GRASS_MESSAGE_FORMAT"]
+        
+    def run(self):
+        """!Run command"""
+        if len(self.cmd) == 0:
+            return
+
+        Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
+
+        self.startTime = time.time()
+        try:
+            self.module = Popen(self.cmd,
+                                stdin = subprocess.PIPE,
+                                stdout = subprocess.PIPE,
+                                stderr = subprocess.PIPE,
+                                shell = sys.platform == "win32")
+        except OSError, e:
+            self.error = str(e)
+            return 1
+        
+        if self.stdin: # read stdin if requested ...
+            self.module.stdin.write(self.stdin)
+            self.module.stdin.close()
+            
+        # redirect standard outputs...
+        self._redirect_stream()
+        
+    def _redirect_stream(self):
+        """!Redirect stream"""
+        if self.stdout:
+            # make module stdout/stderr non-blocking
+            out_fileno = self.module.stdout.fileno()
+	    if not subprocess.mswindows:
+                flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
+                fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+                
+        if self.stderr:
+            # make module stdout/stderr non-blocking
+            out_fileno = self.module.stderr.fileno()
+	    if not subprocess.mswindows:
+                flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
+                fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+        
+        # wait for the process to end, sucking in stuff until it does end
+        while self.module.poll() is None:
+            if self._want_abort: # abort running process
+                self.module.kill()
+                self.aborted = True
+                return 
+            if self.stdout:
+                line = recv_some(self.module, e = 0, stderr = 0)
+                self.stdout.write(line)
+            if self.stderr:
+                line = recv_some(self.module, e = 0, stderr = 1)
+                self.stderr.write(line)
+                if len(line) > 0:
+                    self.error = line
+
+        # get the last output
+        if self.stdout:
+            line = recv_some(self.module, e = 0, stderr = 0)
+            self.stdout.write(line)
+        if self.stderr:
+            line = recv_some(self.module, e = 0, stderr = 1)
+            self.stderr.write(line)
+            if len(line) > 0:
+                self.error = line
+            
+    def abort(self):
+        """!Abort running process, used by main thread to signal an abort"""
+        self._want_abort = True
+    
+def _formatMsg(text):
+    """!Format error messages for dialogs
+    """
+    message = ''
+    for line in text.splitlines():
+        if len(line) == 0:
+            continue
+        elif 'GRASS_INFO_MESSAGE' in line:
+            message += line.split(':', 1)[1].strip() + '\n'
+        elif 'GRASS_INFO_WARNING' in line:
+            message += line.split(':', 1)[1].strip() + '\n'
+        elif 'GRASS_INFO_ERROR' in line:
+            message += line.split(':', 1)[1].strip() + '\n'
+        elif 'GRASS_INFO_END' in line:
+            return message
+        else:
+            message += line.strip() + '\n'
+    
+    return message
+
+def RunCommand(prog, flags = "", overwrite = False, quiet = False, verbose = False,
+               parent = None, read = False, parse = None, stdin = None, getErrorMsg = False, **kwargs):
+    """!Run GRASS command
+
+    @param prog program to run
+    @param flags flags given as a string
+    @param overwrite, quiet, verbose flags
+    @param parent parent window for error messages
+    @param read fetch stdout
+    @param parse fn to parse stdout (e.g. grass.parse_key_val) or None
+    @param stdin stdin or None
+    @param getErrorMsg get error messages on failure
+    @param kwargs program parameters
+    
+    @return returncode (read == False and getErrorMsg == False)
+    @return returncode, messages (read == False and getErrorMsg == True)
+    @return stdout (read == True and getErrorMsg == False)
+    @return returncode, stdout, messages (read == True and getErrorMsg == True)
+    @return stdout, stderr
+    """
+    cmdString = ' '.join(grass.make_command(prog, flags, overwrite,
+                                            quiet, verbose, **kwargs))
+    
+    Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
+    
+    kwargs['stderr'] = subprocess.PIPE
+    
+    if read:
+        kwargs['stdout'] = subprocess.PIPE
+    
+    if stdin:
+        kwargs['stdin'] = subprocess.PIPE
+
+    Debug.msg(2, "gcmd.RunCommand(): command started")
+    start = time.time()
+    
+    ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
+    
+    if stdin:
+        ps.stdin.write(stdin)
+        ps.stdin.close()
+        ps.stdin = None
+    
+    Debug.msg(3, "gcmd.RunCommand(): decoding string")
+    stdout, stderr = map(DecodeString, ps.communicate())
+    
+    ret = ps.returncode
+    Debug.msg(1, "gcmd.RunCommand(): get return code %d (%.6f sec)" % \
+                  (ret, (time.time() - start)))
+    
+    Debug.msg(3, "gcmd.RunCommand(): print error")
+    if ret != 0 and parent:
+        Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr)
+        if (stderr == None):
+            Debug.msg(2, "gcmd.RunCommand(): nothing to print ???")
+        else:
+            GError(parent = parent,
+                   message = stderr)
+    
+    Debug.msg(3, "gcmd.RunCommand(): print read error")
+    if not read:
+        if not getErrorMsg:
+            return ret
+        else:
+            return ret, _formatMsg(stderr)
+
+    if stdout:
+        Debug.msg(2, "gcmd.RunCommand(): return stdout\n'%s'" % stdout)
+    else:
+        Debug.msg(2, "gcmd.RunCommand(): return stdout = None")
+    
+    if parse:
+        stdout = parse(stdout)
+    
+    if not getErrorMsg:
+        return stdout
+    
+    Debug.msg(2, "gcmd.RunCommand(): return ret, stdout")
+    if read and getErrorMsg:
+        return ret, stdout, _formatMsg(stderr)
+    
+    Debug.msg(2, "gcmd.RunCommand(): return result")
+    return stdout, _formatMsg(stderr)

Copied: grass/trunk/gui/wxpython/core/globalvar.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/globalvar.py)
===================================================================
--- grass/trunk/gui/wxpython/core/globalvar.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/globalvar.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,177 @@
+"""!
+ at package core.globalvar
+
+ at brief Global variables used by wxGUI
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import locale
+
+if not os.getenv("GISBASE"):
+    sys.exit("GRASS is not running. Exiting...")
+
+# path to python scripts
+ETCDIR = os.path.join(os.getenv("GISBASE"), "etc")
+ETCICONDIR = os.path.join(os.getenv("GISBASE"), "etc", "gui", "icons")
+ETCWXDIR = os.path.join(ETCDIR, "gui", "wxpython")
+ETCIMGDIR = os.path.join(ETCDIR, "gui", "images")
+
+sys.path.append(os.path.join(ETCDIR, "python"))
+import grass.script as grass
+
+def CheckWxVersion(version = [2, 8, 11, 0]):
+    """!Check wx version"""
+    ver = wx.version().split(' ')[0]
+    if map(int, ver.split('.')) < version:
+        return False
+    
+    return True
+
+def CheckForWx():
+    """!Try to import wx module and check its version"""
+    if 'wx' in sys.modules.keys():
+        return
+    
+    minVersion = [2, 8, 1, 1]
+    try:
+        try:
+            import wxversion
+        except ImportError, e:
+            raise ImportError(e)
+        # wxversion.select(str(minVersion[0]) + '.' + str(minVersion[1]))
+        wxversion.ensureMinimal(str(minVersion[0]) + '.' + str(minVersion[1]))
+        import wx
+        version = wx.version().split(' ')[0]
+        
+        if map(int, version.split('.')) < minVersion:
+            raise ValueError('Your wxPython version is %s.%s.%s.%s' % tuple(version.split('.')))
+
+    except ImportError, e:
+        print >> sys.stderr, 'ERROR: wxGUI requires wxPython. %s' % str(e)
+        sys.exit(1)
+    except (ValueError, wxversion.VersionError), e:
+        print >> sys.stderr, 'ERROR: wxGUI requires wxPython >= %d.%d.%d.%d. ' % tuple(minVersion) + \
+            '%s.' % (str(e))
+        sys.exit(1)
+    except locale.Error, e:
+        print >> sys.stderr, "Unable to set locale:", e
+        os.environ['LC_ALL'] = ''
+    
+if not os.getenv("GRASS_WXBUNDLED"):
+    CheckForWx()
+import wx
+import wx.lib.flatnotebook as FN
+
+"""
+Query layer (generated for example by selecting item in the Attribute Table Manager)
+Deleted automatically on re-render action
+"""
+# temporal query layer (removed on re-render action)
+QUERYLAYER = 'qlayer'
+
+"""!Style definition for FlatNotebook pages"""
+FNPageStyle = FN.FNB_VC8 | \
+    FN.FNB_BACKGROUND_GRADIENT | \
+    FN.FNB_NODRAG | \
+    FN.FNB_TABS_BORDER_SIMPLE 
+
+FNPageDStyle = FN.FNB_FANCY_TABS | \
+    FN.FNB_BOTTOM | \
+    FN.FNB_NO_NAV_BUTTONS | \
+    FN.FNB_NO_X_BUTTON
+
+FNPageColor = wx.Colour(125,200,175)
+
+"""!Dialog widget dimension"""
+DIALOG_SPIN_SIZE = (150, -1)
+DIALOG_COMBOBOX_SIZE = (300, -1)
+DIALOG_GSELECT_SIZE = (400, -1)
+DIALOG_TEXTCTRL_SIZE = (400, -1)
+DIALOG_LAYER_SIZE = (100, -1)
+DIALOG_COLOR_SIZE = (30, 30)
+
+MAP_WINDOW_SIZE = (725, 600)
+HIST_WINDOW_SIZE = (500, 350)
+GM_WINDOW_SIZE = (500, 600)
+
+
+"""!File name extension binaries/scripts"""
+if sys.platform == 'win32':
+    EXT_BIN = '.exe'
+    EXT_SCT = '.py'
+else:
+    EXT_BIN = ''
+    EXT_SCT = ''
+
+def GetGRASSCmds(bin = True, scripts = True, gui_scripts = True, addons = True):
+    """!Create list of available GRASS commands to use when parsing
+    string from the command line
+
+    @param bin True to include executable into list
+    @param scripts True to include scripts into list
+    @param gui_scripts True to include GUI scripts into list
+    """
+    gisbase = os.environ['GISBASE']
+    cmd = list()
+    
+    if bin:
+        for executable in os.listdir(os.path.join(gisbase, 'bin')):
+            ext = os.path.splitext(executable)[1]
+            if not EXT_BIN or \
+                    ext in (EXT_BIN, EXT_SCT):
+                cmd.append(executable)
+        
+        # add special call for setting vector colors
+        cmd.append('vcolors')
+    
+    if scripts:
+        cmd += os.listdir(os.path.join(gisbase, 'scripts'))
+    
+    if gui_scripts:
+        os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'gui', 'scripts')
+        cmd = cmd + os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts'))
+    
+    if addons and os.getenv('GRASS_ADDON_PATH'):
+        path = os.getenv('GRASS_ADDON_PATH')
+        bpath = os.path.join(path, 'bin')
+        spath = os.path.join(path, 'scripts')
+        if os.path.exists(bpath) and os.path.isdir(bpath):
+            for executable in os.listdir(bpath):
+                ext = os.path.splitext(executable)[1]
+                if not EXT_BIN or \
+                        ext in (EXT_BIN, EXT_SCT):
+                    cmd.append(executable)
+        if os.path.exists(spath) and os.path.isdir(spath):
+            cmd += os.listdir(spath)
+    
+    if sys.platform == 'win32':
+        for idx in range(len(cmd)):
+            name, ext = os.path.splitext(cmd[idx])
+            if ext in (EXT_BIN, EXT_SCT):
+                cmd[idx] = name
+    
+    return cmd
+
+"""@brief Collected GRASS-relared binaries/scripts"""
+grassCmd = {}
+grassCmd['all']    = GetGRASSCmds()
+grassCmd['script'] = GetGRASSCmds(bin = False, gui_scripts = False)
+
+"""@Toolbar icon size"""
+toolbarSize = (24, 24)
+
+"""@Is g.mlist available?"""
+if 'g.mlist' in grassCmd['all']:
+    have_mlist = True
+else:
+    have_mlist = False
+
+"""@Check version of wxPython, use agwStyle for 2.8.11+"""
+hasAgw = CheckWxVersion()

Copied: grass/trunk/gui/wxpython/core/menudata.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/menudata.py)
===================================================================
--- grass/trunk/gui/wxpython/core/menudata.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/menudata.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,231 @@
+"""!
+ at package core.menudata
+
+ at brief Complex list for menu entries for wxGUI
+
+Classes:
+ - MenuData
+
+Usage:
+ at code
+python menudata.py [action] [manager|modeler]
+ at endcode
+
+where <i>action</i>:
+ - strings (default)
+ - tree
+ - commands
+ - dump
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Yann Chemin <yann.chemin gmail.com>
+ at author Martin Landa <landa.martin gmail.com>
+ at author Glynn Clements
+"""
+
+import os
+import sys
+import pprint
+try:
+    import xml.etree.ElementTree   as etree
+except ImportError:
+    import elementtree.ElementTree as etree # Python <= 2.4
+
+from wx import ID_ANY
+
+if not os.getenv("GISBASE"):
+    sys.exit("GRASS is not running. Exiting...")
+
+class MenuData:
+    """!Abstract menu data class"""
+    def __init__(self, filename):
+	self.tree = etree.parse(filename)
+
+    def _getMenuItem(self, mi):
+        """!Get menu item
+
+        @param mi menu item instance
+        """
+	if mi.tag == 'separator':
+	    return ('', '', '', '', '')
+	elif mi.tag == 'menuitem':
+	    label    = _(mi.find('label').text)
+	    help     = _(mi.find('help').text)
+	    handler  = mi.find('handler').text
+	    gcmd     = mi.find('command')  # optional
+            keywords = mi.find('keywords') # optional
+            shortcut = mi.find('shortcut') # optional
+            wxId     = mi.find('id')       # optional
+	    if gcmd != None:
+		gcmd = gcmd.text
+	    else:
+		gcmd = ""
+            if keywords != None:
+                keywords = keywords.text
+            else:
+                keywords = ""
+            if shortcut != None:
+                shortcut = shortcut.text
+            else:
+                shortcut = ""
+            if wxId != None:
+                wxId = eval('wx.' + wxId.text)
+            else:
+                wxId = ID_ANY
+	    return (label, help, handler, gcmd, keywords, shortcut, wxId)
+	elif mi.tag == 'menu':
+	    return self._getMenu(mi)
+	else:
+	    raise Exception(_("Unknow tag"))
+
+    def _getMenu(self, m):
+        """!Get menu
+
+        @param m menu
+
+        @return label, menu items
+        """
+	label = _(m.find('label').text)
+	items = m.find('items')
+	return (label, tuple(map(self._getMenuItem, items)))
+    
+    def _getMenuBar(self, mb):
+        """!Get menu bar
+
+        @param mb menu bar instance
+        
+        @return menu items
+        """
+	return tuple(map(self._getMenu, mb.findall('menu')))
+
+    def _getMenuData(self, md):
+        """!Get menu data
+
+        @param md menu data instace
+        
+        @return menu data
+        """
+	return list(map(self._getMenuBar, md.findall('menubar')))
+
+    def GetMenu(self):
+        """!Get menu
+
+        @return menu data
+        """
+	return self._getMenuData(self.tree.getroot())
+
+    def PrintStrings(self, fh):
+        """!Print menu strings to file (used for localization)
+
+        @param fh file descriptor"""
+        className = str(self.__class__).split('.', 1)[1]
+	fh.write('menustrings_%s = [\n' % className)
+	for node in self.tree.getiterator():
+	    if node.tag in ['label', 'help']:
+		fh.write('     _(%r),\n' % node.text)
+	fh.write('    \'\']\n')
+
+    def PrintTree(self, fh):
+        """!Print menu tree to file
+
+        @param fh file descriptor"""
+        level = 0
+        for eachMenuData in self.GetMenu():
+            for label, items in eachMenuData:
+                fh.write('- %s\n' % label.replace('&', ''))
+                self._PrintTreeItems(fh, level + 1, items)
+        
+    def _PrintTreeItems(self, fh, level, menuData):
+        """!Print menu tree items to file (used by PrintTree)
+
+        @param fh file descriptor
+        @param level menu level
+        @param menuData menu data to print out"""
+        for eachItem in menuData:
+            if len(eachItem) == 2:
+                if eachItem[0]:
+                    fh.write('%s - %s\n' % (' ' * level, eachItem[0]))
+                self._PrintTreeItems(fh, level + 1, eachItem[1])
+            else:
+                if eachItem[0]:
+                    fh.write('%s - %s\n' % (' ' * level, eachItem[0]))
+    
+    def PrintCommands(self, fh, itemSep = ' | ', menuSep = ' > '):
+        """!Print commands list (command | menu item > menu item)
+
+        @param fh file descriptor
+        """
+        level = 0
+        for eachMenuData in self.GetMenu():
+            for label, items in eachMenuData:
+                menuItems = [label, ]
+                self._PrintCommandsItems(fh, level + 1, items,
+                                         menuItems, itemSep, menuSep)
+        
+    def _PrintCommandsItems(self, fh, level, menuData,
+                             menuItems, itemSep, menuSep):
+        """!Print commands item (used by PrintCommands)
+
+        @param fh file descriptor
+        @param menuItems list of menu items
+        """
+        for eachItem in menuData:
+            if len(eachItem) == 2:
+                if eachItem[0]:
+                    try:
+                        menuItems[level] = eachItem[0]
+                    except IndexError:
+                        menuItems.append(eachItem[0])
+                self._PrintCommandsItems(fh, level + 1, eachItem[1],
+                                          menuItems, itemSep, menuSep)
+            else:
+                try:
+                    del menuItems[level]
+                except IndexError:
+                    pass
+                
+                if eachItem[3]:
+                    fh.write('%s%s' % (eachItem[3], itemSep))
+                    fh.write(menuSep.join(map(lambda x: x.replace('&', ''), menuItems)))
+                    fh.write('%s%s' % (menuSep, eachItem[0]))
+                    fh.write('\n')
+
+if __name__ == "__main__":
+    import os
+    import sys
+    
+    # i18N
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+
+    action = 'strings'
+    menu   = 'manager'
+    
+    for arg in sys.argv:
+        if arg in ('strings', 'tree', 'commands', 'dump'):
+            action =  arg
+        elif arg in ('manager', 'modeler'):
+            menu = arg
+    
+    sys.path.append(os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython"))
+    if menu == 'manager':
+        from lmgr.menudata import ManagerData
+        data = ManagerData()
+    else:
+        from gmodeler.frame import ModelerData
+        data = ModelerData()
+    
+    if action == 'strings':
+        data.PrintStrings(sys.stdout)
+    elif action == 'tree':
+        data.PrintTree(sys.stdout)
+    elif action == 'commands':
+        data.PrintCommands(sys.stdout)
+    elif action == 'dump':
+	pprint.pprint(data.GetMenu(), stream = sys.stdout, indent = 2)
+    
+    sys.exit(0)

Copied: grass/trunk/gui/wxpython/core/render.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/render.py)
===================================================================
--- grass/trunk/gui/wxpython/core/render.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/render.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1423 @@
+"""!
+ at package core.render
+
+ at brief Rendering map layers and overlays into map composition image.
+
+Classes:
+ - Layer
+ - MapLayer
+ - Overlay
+ - Map
+
+(C) 2006-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import glob
+import math
+import copy
+import tempfile
+import types
+
+import wx
+from wx.lib.newevent import NewEvent
+
+from grass.script import core as grass
+
+from core          import utils
+from core.gcmd     import GException, GError, RunCommand
+from core.debug    import Debug
+from core.settings import UserSettings
+
+wxUpdateProgressBar, EVT_UPDATE_PRGBAR = NewEvent()
+
+USE_GPNMCOMP = True
+
+class Layer(object):
+    """!Virtual class which stores information about layers (map layers and
+    overlays) of the map composition.
+    
+    - For map layer use MapLayer class.
+    - For overlays use Overlay class.
+    """
+    def __init__(self, type, cmd, name = None,
+                 active = True, hidden = False, opacity = 1.0):
+        """!Create new instance
+        
+        @todo pass cmd as tuple instead of list
+        
+        @param type layer type ('raster', 'vector', 'overlay', 'command', etc.)
+        @param cmd GRASS command to render layer,
+        given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
+        @param name layer name, e.g. 'elevation at PERMANENT' (for layer tree)
+        @param active layer is active, will be rendered only if True
+        @param hidden layer is hidden, won't be listed in Layer Manager if True
+        @param opacity layer opacity <0;1>
+        """
+        self.type  = type
+        self.name  = name
+        
+        if self.type == 'command':
+            self.cmd = list()
+            for c in cmd:
+                self.cmd.append(utils.CmdToTuple(c))
+        else:
+            self.cmd = utils.CmdToTuple(cmd)
+        
+        self.active  = active
+        self.hidden  = hidden
+        self.opacity = opacity
+        
+        self.force_render = True
+        
+        Debug.msg (3, "Layer.__init__(): type=%s, cmd='%s', name=%s, " \
+                       "active=%d, opacity=%d, hidden=%d" % \
+                       (self.type, self.GetCmd(string = True), self.name, self.active,
+                        self.opacity, self.hidden))
+        
+        # generated file for each layer
+        if USE_GPNMCOMP or self.type == 'overlay':
+            tmpfile = tempfile.mkstemp()[1]
+            self.maskfile = tmpfile + '.pgm'
+            if self.type == 'overlay':
+                self.mapfile  = tmpfile + '.png'
+            else:
+                self.mapfile  = tmpfile + '.ppm'
+            grass.try_remove(tmpfile)
+        else:
+            self.mapfile = self.maskfile = None
+        
+    def __del__(self):
+        Debug.msg (3, "Layer.__del__(): layer=%s, cmd='%s'" %
+                   (self.name, self.GetCmd(string = True)))
+        
+    def Render(self):
+        """!Render layer to image
+        
+        @return rendered image filename
+        @return None on error or if cmdfile is defined
+        """
+        if not self.cmd:
+            return None
+        
+        # ignore in 2D
+        if self.type == '3d-raster':
+            return None
+        
+        Debug.msg (3, "Layer.Render(): type=%s, name=%s" % \
+                       (self.type, self.name))
+        
+        # prepare command for each layer
+        layertypes = ('raster', 'rgb', 'his', 'shaded', 'rastarrow', 'rastnum',
+                      'vector','thememap','themechart',
+                      'grid', 'geodesic', 'rhumb', 'labels',
+                      'command', 'rastleg','maplegend',
+                      'overlay')
+        
+        if self.type not in layertypes:
+            raise GException(_("<%(name)s>: layer type <%(type)s> is not supported") % \
+                                 {'type' : self.type, 'name' : self.name})
+        
+        # start monitor
+	if self.mapfile:
+	    os.environ["GRASS_PNGFILE"] = self.mapfile
+        
+        # execute command
+        try:
+            if self.type == 'command':
+                read = False
+                for c in self.cmd:
+                    ret, msg = RunCommand(c[0],
+                                          getErrorMsg = True,
+                                          quiet = True,
+                                          **c[1])
+                    if ret != 0:
+                        break
+                    if not read:
+                        os.environ["GRASS_PNG_READ"] = "TRUE"
+                
+                os.environ["GRASS_PNG_READ"] = "FALSE"
+            else:
+                ret, msg = RunCommand(self.cmd[0],
+                                      getErrorMsg = True,
+                                      quiet = True,
+                                      **self.cmd[1])
+                
+            if msg:
+                sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
+                sys.stderr.write(_("Details: %s\n") % msg)
+            if ret != 0:
+                raise GException()
+        
+        except GException:
+            # clean up after problems
+            for f in [self.mapfile, self.maskfile]:
+                if not f:
+                    continue
+                grass.try_remove(f)
+                f = None
+        
+        # stop monitor
+        if self.mapfile and "GRASS_PNGFILE" in os.environ:
+            del os.environ["GRASS_PNGFILE"]
+        
+        self.force_render = False
+        
+        return self.mapfile
+    
+    def GetCmd(self, string = False):
+        """!Get GRASS command as list of string.
+        
+        @param string get command as string if True otherwise as list
+        
+        @return command list/string
+        """
+        if string:
+            if self.type == 'command':
+                scmd = []
+                for c in self.cmd:
+                    scmd.append(utils.GetCmdString(c))
+                
+                return ';'.join(scmd)
+            else:
+                return utils.GetCmdString(self.cmd)
+        else:
+            return self.cmd
+
+    def GetType(self):
+        """!Get map layer type"""
+        return self.type
+    
+    def GetElement(self):
+        """!Get map element type"""
+        if self.type == 'raster':
+            return 'cell'
+        return self.type
+    
+    def GetOpacity(self, float = False):
+        """
+        Get layer opacity level
+        
+        @param float get opacity level in <0,1> otherwise <0,100>
+        
+        @return opacity level
+        """
+        if float:
+            return self.opacity
+        
+        return int (self.opacity * 100)
+
+    def GetName(self, fullyQualified = True):
+        """!Get map layer name
+
+        @param fullyQualified True to return fully qualified name as a
+        string 'name at mapset' otherwise directory { 'name', 'mapset' }
+        is returned
+
+        @return string / directory
+        """
+        if fullyQualified:
+            return self.name
+        else:
+            if '@' in self.name:
+                return { 'name' : self.name.split('@')[0],
+                         'mapset' : self.name.split('@')[1] }
+            else:
+                return { 'name' : self.name,
+                         'mapset' : '' }
+        
+    def IsActive(self):
+        """!Check if layer is activated for rendering"""
+        return self.active
+    
+    def SetType(self, type):
+        """!Set layer type"""
+        if type not in ('raster', '3d-raster', 'vector',
+                        'overlay', 'command',
+                        'shaded', 'rgb', 'his', 'rastarrow', 'rastnum','maplegend',
+                        'thememap', 'themechart', 'grid', 'labels',
+                        'geodesic','rhumb'):
+            raise GException(_("Unsupported map layer type '%s'") % type)
+        
+        self.type = type
+
+    def SetName(self, name):
+        """!Set layer name"""
+        self.name = name
+        
+    def SetActive(self, enable = True):
+        """!Active or deactive layer"""
+        self.active = bool(enable)
+
+    def SetHidden(self, enable = False):
+        """!Hide or show map layer in Layer Manager"""
+        self.hidden = bool(enable)
+
+    def SetOpacity(self, value):
+        """!Set opacity value"""
+        if value < 0:
+            value = 0.
+        elif value > 1:
+            value = 1.
+        
+        self.opacity = float(value)
+        
+    def SetCmd(self, cmd):
+        """!Set new command for layer"""
+        if self.type == 'command':
+            self.cmd = []
+            for c in cmd:
+                self.cmd.append(utils.CmdToTuple(c))
+        else:
+            self.cmd  = utils.CmdToTuple(cmd)
+        Debug.msg(3, "Layer.SetCmd(): cmd='%s'" % self.GetCmd(string = True))
+        
+        # for re-rendering
+        self.force_render = True
+        
+class MapLayer(Layer):
+    def __init__(self, type, cmd, name = None,
+                 active = True, hidden = False, opacity = 1.0): 
+        """!Represents map layer in the map canvas
+        
+        @param type layer type ('raster', 'vector', 'command', etc.)
+        @param cmd GRASS command to render layer,
+        given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
+        @param name layer name, e.g. 'elevation at PERMANENT' (for layer tree) or None
+        @param active layer is active, will be rendered only if True
+        @param hidden layer is hidden, won't be listed in Layer Manager if True
+        @param opacity layer opacity <0;1>
+        """
+        Layer.__init__(self, type, cmd, name,
+                       active, hidden, opacity)
+        
+    def GetMapset(self):
+        """!Get mapset of map layer
+        
+        @return mapset name
+        @return '' on error (no name given)
+        """
+        if not self.name:
+            return ''
+        
+        try:
+            return self.name.split('@')[1]
+        except IndexError:
+            return self.name
+        
+class Overlay(Layer):
+    def __init__(self, id, type, cmd,
+                 active = True, hidden = True, opacity = 1.0):
+        """!Represents overlay displayed in map canvas
+        
+        @param id overlay id (for PseudoDC)
+        @param type overlay type ('barscale', 'legend', etc.)
+        @param cmd GRASS command to render overlay,
+        given as list, e.g. ['d.legend', 'map=elevation at PERMANENT']
+        @param active layer is active, will be rendered only if True
+        @param hidden layer is hidden, won't be listed in Layer Manager if True
+        @param opacity layer opacity <0;1>
+        """
+        Layer.__init__(self, 'overlay', cmd, type,
+                       active, hidden, opacity)
+        
+        self.id = id
+        
+class Map(object):
+    def __init__(self, gisrc = None, cmdfile = None, mapfile = None, envfile = None, monitor = None):
+        """!Map composition (stack of map layers and overlays)
+
+        @param gisrc alternative gisrc (used eg. by georectifier)
+        @param cmdline full path to the cmd file (defined by d.mon)
+        @param mapfile full path to the map file (defined by d.mon)
+        @param envfile full path to the env file (defined by d.mon)
+        @param monitor name of monitor (defined by d.mon)
+        """
+        # region/extent settigns
+        self.wind      = dict() # WIND settings (wind file)
+        self.region    = dict() # region settings (g.region)
+        self.width     = 640    # map width
+        self.height    = 480    # map height
+        
+        # list of layers
+        self.layers    = list()  # stack of available GRASS layer
+        
+        self.overlays  = list()  # stack of available overlays
+        self.ovlookup  = dict()  # lookup dictionary for overlay items and overlays
+        
+        # environment settings
+        self.env   = dict()
+        # path to external gisrc
+        self.gisrc = gisrc
+        
+        self.cmdfile = cmdfile
+        self.envfile = envfile
+        self.monitor = monitor
+        
+        if mapfile:
+            self.mapfileCmd = mapfile
+            self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
+        
+        # generated file for g.pnmcomp output for rendering the map
+        self.mapfile = grass.tempfile(create = False) + '.ppm'
+        
+        # setting some initial env. variables
+        self._initGisEnv() # g.gisenv
+        self.GetWindow()
+        # GRASS environment variable (for rendering)
+        env = {"GRASS_BACKGROUNDCOLOR" : "FFFFFF",
+               "GRASS_COMPRESSION"     : "0",
+               "GRASS_TRUECOLOR"       : "TRUE",
+               "GRASS_TRANSPARENT"     : "TRUE",
+               "GRASS_PNG_READ"        : "FALSE",
+               }
+        
+        self._writeEnvFile(env)
+        self._writeEnvFile({"GRASS_PNG_READ" : "TRUE"})
+        for k, v in env.iteritems():
+            os.environ[k] = v
+        
+        # projection info
+        self.projinfo = self._projInfo()
+        
+    def _runCommand(self, cmd, **kwargs):
+        """!Run command in environment defined by self.gisrc if
+        defined"""
+        # use external gisrc if defined
+        gisrc_orig = os.getenv("GISRC")
+        if self.gisrc:
+            os.environ["GISRC"] = self.gisrc
+        
+        ret = cmd(**kwargs)
+        
+        # back to original gisrc
+        if self.gisrc:
+            os.environ["GISRC"] = gisrc_orig
+        
+        return ret
+    
+    def _initGisEnv(self):
+        """!Stores GRASS variables (g.gisenv) to self.env variable
+        """
+        if not os.getenv("GISBASE"):
+            sys.exit(_("GISBASE not set. You must be in GRASS GIS to run this program."))
+        
+        self.env = self._runCommand(grass.gisenv)
+            
+    def GetProjInfo(self):
+        """!Get projection info"""
+        return self.projinfo
+    
+    def _projInfo(self):
+        """!Return region projection and map units information
+        """
+        projinfo = dict()
+        if not grass.find_program('g.proj', ['--help']):
+            sys.exit(_("GRASS module '%s' not found. Unable to start map "
+                       "display window.") % 'g.proj')
+        
+        ret = self._runCommand(RunCommand, prog = 'g.proj',
+                               read = True, flags = 'p')
+        
+        if not ret:
+            return projinfo
+        
+        for line in ret.splitlines():
+            if ':' in line:
+                key, val = map(lambda x: x.strip(), line.split(':'))
+                if key in ['units']:
+                    val = val.lower()
+                projinfo[key] = val
+            elif "XY location (unprojected)" in line:
+                projinfo['proj'] = 'xy'
+                projinfo['units'] = ''
+                break
+        
+        return projinfo
+    
+    def GetWindow(self):
+        """!Read WIND file and set up self.wind dictionary"""
+        # FIXME: duplicated region WIND == g.region (at least some values)
+        filename = os.path.join (self.env['GISDBASE'],
+                                 self.env['LOCATION_NAME'],
+                                 self.env['MAPSET'],
+                                 "WIND")
+        try:
+            windfile = open (filename, "r")
+        except IOError, e:
+            sys.exit(_("Error: Unable to open '%(file)s'. Reason: %(ret)s. wxGUI exited.\n") % \
+                         { 'file' : filename, 'ret' : e})
+        
+        for line in windfile.readlines():
+            line = line.strip()
+            key, value = line.split(":", 1)
+            self.wind[key.strip()] = value.strip()
+        
+        windfile.close()
+        
+        return self.wind
+        
+    def AdjustRegion(self):
+        """!Adjusts display resolution to match monitor size in
+        pixels. Maintains constant display resolution, not related to
+        computational region. Do NOT use the display resolution to set
+        computational resolution. Set computational resolution through
+        g.region.
+        """
+        mapwidth    = abs(self.region["e"] - self.region["w"])
+        mapheight   = abs(self.region['n'] - self.region['s'])
+        
+        self.region["nsres"] =  mapheight / self.height
+        self.region["ewres"] =  mapwidth  / self.width
+        self.region['rows']  = round(mapheight / self.region["nsres"])
+        self.region['cols']  = round(mapwidth / self.region["ewres"])
+        self.region['cells'] = self.region['rows'] * self.region['cols']
+        
+        Debug.msg (3, "Map.AdjustRegion(): %s" % self.region)
+        
+        return self.region
+
+    def AlignResolution(self):
+        """!Sets display extents to even multiple of current
+        resolution defined in WIND file from SW corner. This must be
+        done manually as using the -a flag can produce incorrect
+        extents.
+        """
+        # new values to use for saving to region file
+        new = {}
+        n = s = e = w = 0.0
+        nwres = ewres = 0.0
+        
+        # Get current values for region and display
+        reg = self.GetRegion()
+        nsres = reg['nsres']
+        ewres = reg['ewres']
+        
+        n = float(self.region['n'])
+        s = float(self.region['s'])
+        e = float(self.region['e'])
+        w = float(self.region['w'])
+        
+        # Calculate rows, columns, and extents
+        new['rows'] = math.fabs(round((n-s)/nsres))
+        new['cols'] = math.fabs(round((e-w)/ewres))
+        
+        # Calculate new extents
+        new['s'] = nsres * round(s / nsres)
+        new['w'] = ewres * round(w / ewres)
+        new['n'] = new['s'] + (new['rows'] * nsres)
+        new['e'] = new['w'] + (new['cols'] * ewres)
+        
+        return new
+
+    def AlignExtentFromDisplay(self):
+        """!Align region extent based on display size from center
+        point"""
+        # calculate new bounding box based on center of display
+        if self.region["ewres"] > self.region["nsres"]:
+            res = self.region["ewres"]
+        else:
+            res = self.region["nsres"]
+        
+        Debug.msg(3, "Map.AlignExtentFromDisplay(): width=%d, height=%d, res=%f, center=%f,%f" % \
+                      (self.width, self.height, res, self.region['center_easting'],
+                       self.region['center_northing']))
+            
+        ew = (self.width / 2) * res
+        ns = (self.height / 2) * res
+        
+        self.region['n'] = self.region['center_northing'] + ns
+        self.region['s'] = self.region['center_northing'] - ns
+        self.region['e'] = self.region['center_easting'] + ew
+        self.region['w'] = self.region['center_easting'] - ew
+        
+        # LL locations
+        if self.projinfo['proj'] == 'll':
+            self.region['n'] = min(self.region['n'], 90.0)
+            self.region['s'] = max(self.region['s'], -90.0)
+        
+    def _writeEnvFile(self, data):
+        """!Write display-related variable to the file (used for
+        standalone app)
+        """
+        if not self.envfile:
+            return
+        
+        try:
+            fd = open(self.envfile, "r")
+            for line in fd.readlines():
+                key, value = line.split('=')
+                if key not in data.keys():
+                    data[key] = value
+            fd.close()
+            
+            fd = open(self.envfile, "w")
+            for k, v in data.iteritems():
+                fd.write('%s=%s\n' % (k.strip(), str(v).strip()))
+        except IOError, e:
+            grass.warning(_("Unable to open file '%(file)s' for writting. Details: %(det)s") % \
+                              { 'cmd' : self.envfile, 'det' : e })
+            return
+        
+        fd.close()
+        
+    def ChangeMapSize(self, (width, height)):
+        """!Change size of rendered map.
+        
+        @param width,height map size
+        """
+        try:
+            self.width  = int(width)
+            self.height = int(height)
+        except:
+            self.width  = 640
+            self.height = 480
+
+        Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
+                      (self.width, self.height))
+        self._writeEnvFile({'GRASS_WIDTH' : self.width,
+                            'GRASS_HEIGHT' : self.height})
+        
+    def GetRegion(self, rast = [], zoom = False, vect = [], regionName = None,
+                  n = None, s = None, e = None, w = None, default = False,
+                  update = False):
+        """!Get region settings (g.region -upgc)
+        
+        Optionally extent, raster or vector map layer can be given.
+        
+        @param rast list of raster maps
+        @param zoom zoom to raster map (ignore NULLs)
+        @param vect list of vector maps
+        @param regionName  named region or None
+        @param n,s,e,w force extent
+        @param default force default region settings
+        @param update if True update current display region settings
+        
+        @return region settings as directory, e.g. {
+        'n':'4928010', 's':'4913700', 'w':'589980',...}
+        
+        @see GetCurrentRegion()
+        """
+        region = {}
+        
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        # use external gisrc if defined
+        gisrc_orig = os.getenv("GISRC")
+        if self.gisrc:
+            os.environ["GISRC"] = self.gisrc
+        
+        # do not update & shell style output
+        cmd = {}
+        cmd['flags'] = 'ugpc'
+        
+        if default:
+            cmd['flags'] += 'd'
+        
+        if regionName:
+            cmd['region'] = regionName
+        
+        if n:
+            cmd['n'] = n
+        if s:
+            cmd['s'] = s
+        if e:
+            cmd['e'] = e
+        if w:
+            cmd['w'] = w
+        
+        if rast:
+            if zoom:
+                cmd['zoom'] = rast[0]
+            else:
+                cmd['rast'] = ','.join(rast)
+        
+        if vect:
+            cmd['vect'] = ','.join(vect)
+        
+        ret, reg, msg = RunCommand('g.region',
+                                   read = True,
+                                   getErrorMsg = True,
+                                   **cmd)
+        
+        if ret != 0:
+            if rast:
+                message = _("Unable to zoom to raster map <%s>.") % rast[0] + \
+                    "\n\n" + _("Details:") + " %s" % msg
+            elif vect:
+                message = _("Unable to zoom to vector map <%s>.") % vect[0] + \
+                    "\n\n" + _("Details:") + " %s" % msg
+            else:
+                message = _("Unable to get current geographic extent. "
+                            "Force quiting wxGUI. Please manually run g.region to "
+                            "fix the problem.")
+            GError(message)
+            return self.region
+        
+        for r in reg.splitlines():
+            key, val = r.split("=", 1)
+            try:
+                region[key] = float(val)
+            except ValueError:
+                region[key] = val
+        
+        # back to original gisrc
+        if self.gisrc:
+            os.environ["GISRC"] = gisrc_orig
+        
+        # restore region
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+        
+        Debug.msg (3, "Map.GetRegion(): %s" % region)
+        
+        if update:
+            self.region = region
+        
+        return region
+
+    def GetCurrentRegion(self):
+        """!Get current display region settings
+        
+        @see GetRegion()
+        """
+        return self.region
+
+    def SetRegion(self, windres = False):
+        """!Render string for GRASS_REGION env. variable, so that the
+        images will be rendered from desired zoom level.
+        
+        @param windres uses resolution from WIND file rather than
+        display (for modules that require set resolution like
+        d.rast.num)
+
+        @return String usable for GRASS_REGION variable or None
+        """
+        grass_region = ""
+        
+        if windres:
+            compRegion = self.GetRegion()
+            region = copy.copy(self.region)
+            for key in ('nsres', 'ewres', 'cells'):
+                region[key] = compRegion[key]
+        else:
+            # adjust region settings to match monitor
+            region = self.AdjustRegion()
+        
+        # read values from wind file
+        try:
+            for key in self.wind.keys():
+                if key == 'north':
+                    grass_region += "north: %s; " % \
+                        (region['n'])
+                    continue
+                elif key == "south":
+                    grass_region += "south: %s; " % \
+                        (region['s'])
+                    continue
+                elif key == "east":
+                    grass_region += "east: %s; " % \
+                        (region['e'])
+                    continue
+                elif key == "west":
+                    grass_region += "west: %s; " % \
+                        (region['w'])
+                    continue
+                elif key == "e-w resol":
+                    grass_region += "e-w resol: %f; " % \
+                        (region['ewres'])
+                    continue
+                elif key == "n-s resol":
+                    grass_region += "n-s resol: %f; " % \
+                        (region['nsres'])
+                    continue
+                elif key == "cols":
+                    if windres:
+                        continue
+                    grass_region += 'cols: %d; ' % \
+                        region['cols']
+                    continue
+                elif key == "rows":
+                    if windres:
+                        continue
+                    grass_region += 'rows: %d; ' % \
+                        region['rows']
+                    continue
+                else:
+                    grass_region += key + ": "  + self.wind[key] + "; "
+            
+            Debug.msg (3, "Map.SetRegion(): %s" % grass_region)
+            
+            return grass_region
+        
+        except:
+            return None
+        
+    def GetListOfLayers(self, l_type = None, l_mapset = None, l_name = None,
+                        l_active = None, l_hidden = None):
+        """!Returns list of layers of selected properties or list of
+        all layers.
+
+        @param l_type layer type, e.g. raster/vector/wms/overlay (value or tuple of values)
+        @param l_mapset all layers from given mapset (only for maplayers)
+        @param l_name all layers with given name
+        @param l_active only layers with 'active' attribute set to True or False
+        @param l_hidden only layers with 'hidden' attribute set to True or False
+        
+        @return list of selected layers
+        """
+        selected = []
+        
+        if type(l_type) == types.StringType:
+            one_type = True
+        else:
+            one_type = False
+        
+        if one_type and l_type == 'overlay':
+            llist = self.overlays
+        else:
+            llist = self.layers
+        
+        # ["raster", "vector", "wms", ... ]
+        for layer in llist:
+            # specified type only
+            if l_type != None:
+                if one_type and layer.type != l_type:
+                    continue
+                elif not one_type and layer.type not in l_type:
+                    continue
+            
+            # mapset
+            if (l_mapset != None and l_type != 'overlay') and \
+                    layer.GetMapset() != l_mapset:
+                continue
+            
+            # name
+            if l_name != None and layer.name != l_name:
+                continue
+            
+            # hidden and active layers
+            if l_active != None and \
+                   l_hidden != None:
+                if layer.active == l_active and \
+                       layer.hidden == l_hidden:
+                    selected.append(layer)
+            
+            # active layers
+            elif l_active != None:
+                if layer.active == l_active:
+                    selected.append(layer)
+            
+            # hidden layers
+            elif l_hidden != None:
+                if layer.hidden == l_hidden:
+                    selected.append(layer)
+            
+            # all layers
+            else:
+                selected.append(layer)
+        
+        Debug.msg (3, "Map.GetListOfLayers(): numberof=%d" % len(selected))
+        
+        return selected
+
+    def _renderLayers(self, force = False, mapWindow = None, overlaysOnly = False):
+        maps = list()
+        masks = list()
+        opacities = list()
+        # render map layers
+        ilayer = 1
+        if overlaysOnly:
+            layers = self.overlays
+        else:
+            layers = self.layers + self.overlays
+        
+        for layer in layers:
+            # skip non-active map layers
+            if not layer or not layer.active:
+                continue
+            
+            # render
+            if force or layer.force_render:
+                if not layer.Render():
+                    continue
+            
+            if mapWindow:
+                # update progress bar
+                ### wx.SafeYield(mapWindow)
+                event = wxUpdateProgressBar(value = ilayer)
+                wx.PostEvent(mapWindow, event)
+            
+            # add image to compositing list
+            if layer.type != "overlay":
+                maps.append(layer.mapfile)
+                masks.append(layer.maskfile)
+                opacities.append(str(layer.opacity))
+            
+            Debug.msg(3, "Map.Render() type=%s, layer=%s " % (layer.type, layer.name))
+            ilayer += 1
+        
+        return maps, masks, opacities
+    
+    def GetLayersFromCmdFile(self):
+        """!Get list of map layers from cmdfile
+        """
+        if not self.cmdfile:
+            return
+        
+        nlayers = 0
+        try:
+            fd = open(self.cmdfile, 'r')
+            for line in fd.readlines():
+                cmd = utils.split(line.strip())
+                ltype = None
+                if cmd[0] == 'd.rast':
+                    ltype = 'raster'
+                elif cmd[0] == 'd.vect':
+                    ltype = 'vector'
+                
+                name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
+                                                 layerType = ltype)[0]
+                
+                self.AddLayer(type = ltype, command = cmd, l_active = False, name = name)
+                nlayers += 1
+        except IOError, e:
+            grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
+                              { 'cmd' : self.cmdfile, 'det' : e })
+            return
+        
+        fd.close()
+
+        Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
+        Debug.msg(1, "                            nlayers=%d" % nlayers)
+                
+    def _parseCmdFile(self):
+        """!Parse cmd file for standalone application
+        """
+        nlayers = 0
+        try:
+            fd = open(self.cmdfile, 'r')
+            grass.try_remove(self.mapfile)
+            cmdLines = fd.readlines()
+            RunCommand('g.gisenv',
+                       set = 'MONITOR_%s_CMDFILE=' % self.monitor)
+
+            for cmd in cmdLines:
+                cmdStr = utils.split(cmd.strip())
+                cmd = utils.CmdToTuple(cmdStr)
+                RunCommand(cmd[0], **cmd[1])
+                nlayers += 1
+            
+            RunCommand('g.gisenv',
+                       set = 'MONITOR_%s_CMDFILE=%s' % (self.monitor, self.cmdfile))
+        except IOError, e:
+            grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
+                              { 'cmd' : self.cmdfile, 'det' : e })
+            return
+        
+        fd.close()
+
+        Debug.msg(1, "Map.__parseCmdFile(): cmdfile=%s" % self.cmdfile)
+        Debug.msg(1, "                      nlayers=%d" % nlayers)
+        
+        return nlayers
+
+    def _renderCmdFile(self, force, windres):
+        if not force:
+            return ([self.mapfileCmd],
+                    [self.maskfileCmd],
+                    ['1.0'])
+        
+        region = os.environ["GRASS_REGION"] = self.SetRegion(windres)
+        self._writeEnvFile({'GRASS_REGION' : region})
+        currMon = grass.gisenv()['MONITOR']
+        if currMon != self.monitor:
+            RunCommand('g.gisenv',
+                       set = 'MONITOR=%s' % self.monitor)
+        
+        grass.try_remove(self.mapfileCmd) # GRASS_PNG_READ is TRUE
+        
+        nlayers = self._parseCmdFile()
+        if self.overlays:
+            RunCommand('g.gisenv',
+                       unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
+            driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
+            if driver == 'png':
+                os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
+            else:
+                os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
+            self._renderLayers(overlaysOnly = True)
+            del os.environ["GRASS_RENDER_IMMEDIATE"]
+            RunCommand('g.gisenv',
+                       set = 'MONITOR=%s' % currMon)
+        
+        if currMon != self.monitor:
+            RunCommand('g.gisenv',
+                       set = 'MONITOR=%s' % currMon)
+            
+        if nlayers > 0:
+            return ([self.mapfileCmd],
+                    [self.maskfileCmd],
+                    ['1.0'])
+        else:
+            return ([], [], [])
+    
+    def Render(self, force = False, mapWindow = None, windres = False):
+        """!Creates final image composite
+        
+        This function can conditionaly use high-level tools, which
+        should be avaliable in wxPython library
+        
+        @param force force rendering
+        @param reference for MapFrame instance (for progress bar)
+        @param windres use region resolution (True) otherwise display resolution
+        
+        @return name of file with rendered image or None
+        """
+        wx.BeginBusyCursor()
+        # use external gisrc if defined
+        gisrc_orig = os.getenv("GISRC")
+        if self.gisrc:
+            os.environ["GISRC"] = self.gisrc
+        
+        tmp_region = os.getenv("GRASS_REGION")
+        os.environ["GRASS_REGION"] = self.SetRegion(windres)
+        os.environ["GRASS_WIDTH"]  = str(self.width)
+        os.environ["GRASS_HEIGHT"] = str(self.height)
+        driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
+        if driver == 'png':
+            os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
+        else:
+            os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
+        
+        if self.cmdfile:
+            maps, masks, opacities = self._renderCmdFile(force, windres)
+        else:
+            maps, masks, opacities = self._renderLayers(force, mapWindow)
+        
+        # ugly hack for MSYS
+        if sys.platform != 'win32':
+            mapstr = ",".join(maps)
+            maskstr = ",".join(masks)
+            mapoutstr = self.mapfile
+        else:
+            mapstr = ""
+            for item in maps:
+                mapstr += item.replace('\\', '/')		
+            mapstr = mapstr.rstrip(',')
+            maskstr = ""
+            for item in masks:
+                maskstr += item.replace('\\', '/')
+            maskstr = maskstr.rstrip(',')
+            mapoutstr = self.mapfile.replace('\\', '/')
+            
+        # run g.pngcomp to get composite image
+        bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
+                                                     subkey = 'color')))
+        
+        if maps:
+            ret, msg = RunCommand('g.pnmcomp',
+                                  getErrorMsg = True,
+                                  overwrite = True,
+                                  input = '%s' % ",".join(maps),
+                                  mask = '%s' % ",".join(masks),
+                                  opacity = '%s' % ",".join(opacities),
+                                  bgcolor = bgcolor,
+                                  width = self.width,
+                                  height = self.height,
+                                  output = self.mapfile)
+            
+            if ret != 0:
+                print >> sys.stderr, _("ERROR: Rendering failed. Details: %s") % msg
+                wx.EndBusyCursor()
+                return None
+        
+        Debug.msg (3, "Map.Render() force=%s file=%s" % (force, self.mapfile))
+        
+        # back to original region
+        if tmp_region:
+            os.environ["GRASS_REGION"] = tmp_region
+        else:
+            del os.environ["GRASS_REGION"]
+        
+        # back to original gisrc
+        if self.gisrc:
+            os.environ["GISRC"] = gisrc_orig
+        
+        wx.EndBusyCursor()
+        if not maps:
+            return None
+        
+        return self.mapfile
+
+    def AddLayer(self, type, command, name = None,
+                 l_active = True, l_hidden = False, l_opacity = 1.0, l_render = False,
+                 pos = -1):
+        """!Adds generic map layer to list of layers
+        
+        @param type layer type ('raster', 'vector', etc.)
+        @param command  GRASS command given as list
+        @param name layer name
+        @param l_active layer render only if True
+        @param l_hidden layer not displayed in layer tree if True
+        @param l_opacity opacity level range from 0(transparent) - 1(not transparent)
+        @param l_render render an image if True
+        @param pos position in layer list (-1 for append)
+        
+        @return new layer on success
+        @return None on failure
+        """
+        wx.BeginBusyCursor()
+        # l_opacity must be <0;1>
+        if l_opacity < 0:
+            l_opacity = 0
+        elif l_opacity > 1:
+            l_opacity = 1
+        layer = MapLayer(type = type, name = name, cmd = command,
+                         active = l_active, hidden = l_hidden, opacity = l_opacity)
+        
+        # add maplayer to the list of layers
+        if pos > -1:
+            self.layers.insert(pos, layer)
+        else:
+            self.layers.append(layer)
+        
+        Debug.msg (3, "Map.AddLayer(): layer=%s" % layer.name)
+        if l_render:
+            if not layer.Render():
+                raise GException(_("Unable to render map layer <%s>.") % name)
+        
+        wx.EndBusyCursor()
+        
+        return layer
+
+    def DeleteAllLayers(self, overlay = False):
+        """!Delete all layers 
+
+        @param overlay True to delete also overlayes
+        """
+        self.layers = []
+        if overlay:
+            self.overlays = []
+        
+    def DeleteLayer(self, layer, overlay = False):
+        """!Removes layer from list of layers
+        
+        @param layer layer instance in layer tree
+        @param overlay delete overlay (use self.DeleteOverlay() instead)
+
+        @return removed layer on success or None
+        """
+        Debug.msg (3, "Map.DeleteLayer(): name=%s" % layer.name)
+        
+        if overlay:
+            list = self.overlays
+        else:
+            list = self.layers
+        
+        if layer in list:
+            if layer.mapfile:
+                base = os.path.split(layer.mapfile)[0]
+                mapfile = os.path.split(layer.mapfile)[1]
+                tempbase = mapfile.split('.')[0]
+                if base == '' or tempbase == '':
+                    return None
+                basefile = os.path.join(base, tempbase) + r'.*'
+                for f in glob.glob(basefile):
+                    os.remove(f)
+            list.remove(layer)
+            
+            return layer
+        
+        return None
+
+    def ReorderLayers(self, layerList):
+        """!Reorder list to match layer tree
+        
+        @param layerList list of layers
+        """
+        self.layers = layerList
+        
+        layerNameList = ""
+        for layer in self.layers:
+            if layer.name:
+                layerNameList += layer.name + ','
+        Debug.msg (4, "Map.ReoderLayers(): layers=%s" % \
+                   (layerNameList))
+        
+    def ChangeLayer(self, layer, render = False, **kargs):
+        """!Change map layer properties
+
+        @param layer map layer instance
+        @param type layer type ('raster', 'vector', etc.)
+        @param command  GRASS command given as list
+        @param name layer name
+        @param active layer render only if True
+        @param hidden layer not displayed in layer tree if True
+        @param opacity opacity level range from 0(transparent) - 1(not transparent)
+        @param render render an image if True
+        """
+        Debug.msg (3, "Map.ChangeLayer(): layer=%s" % layer.name)
+        
+        if 'type' in kargs:
+            layer.SetType(kargs['type']) # check type
+        
+        if 'command' in kargs:
+            layer.SetCmd(kargs['command'])
+        
+        if 'name' in kargs:
+            layer.SetName(kargs['name'])
+        
+        if 'active' in kargs:
+            layer.SetActive(kargs['active'])
+        
+        if 'hidden' in kargs:
+            layer.SetHidden(kargs['hidden'])
+        
+        if 'opacity' in kargs:
+            layer.SetOpacity(kargs['opacity'])
+        
+        if render and not layer.Render():
+            raise GException(_("Unable to render map layer <%s>.") % 
+                             name)
+        
+        return layer
+
+    def ChangeOpacity(self, layer, l_opacity):
+        """!Changes opacity value of map layer
+
+        @param layer layer instance in layer tree
+        @param l_opacity opacity level <0;1>
+        """
+        # l_opacity must be <0;1>
+        if l_opacity < 0: l_opacity = 0
+        elif l_opacity > 1: l_opacity = 1
+        
+        layer.opacity = l_opacity
+        Debug.msg (3, "Map.ChangeOpacity(): layer=%s, opacity=%f" % \
+                   (layer.name, layer.opacity))
+
+    def ChangeLayerActive(self, layer, active):
+        """!Enable or disable map layer
+        
+        @param layer layer instance in layer tree
+        @param active to be rendered (True)
+        """
+        layer.active = active
+        
+        Debug.msg (3, "Map.ChangeLayerActive(): name='%s' -> active=%d" % \
+                   (layer.name, layer.active))
+
+    def ChangeLayerName (self, layer, name):
+        """!Change name of the layer
+        
+        @param layer layer instance in layer tree
+        @param name  layer name to set up
+        """
+        Debug.msg (3, "Map.ChangeLayerName(): from=%s to=%s" % \
+                   (layer.name, name))
+        layer.name =  name
+
+    def RemoveLayer(self, name = None, id = None):
+        """!Removes layer from layer list
+        
+        Layer is defined by name at mapset or id.
+        
+        @param name layer name (must be unique)
+        @param id layer index in layer list
+
+        @return removed layer on success
+        @return None on failure
+        """
+        # delete by name
+        if name:
+            retlayer = None
+            for layer in self.layers:
+                if layer.name == name:
+                    retlayer = layer
+                    os.remove(layer.mapfile)
+                    os.remove(layer.maskfile)
+                    self.layers.remove(layer)
+                    return layer
+        # del by id
+        elif id != None:
+            return self.layers.pop(id)
+        
+        return None
+
+    def GetLayerIndex(self, layer, overlay = False):
+        """!Get index of layer in layer list.
+        
+        @param layer layer instace in layer tree
+        @param overlay use list of overlays instead
+        
+        @return layer index
+        @return -1 if layer not found
+        """
+        if overlay:
+            list = self.overlay
+        else:
+            list = self.layers
+            
+        if layer in list:
+            return list.index(layer)
+        
+        return -1
+
+    def AddOverlay(self, id, type, command,
+                   l_active = True, l_hidden = True, l_opacity = 1.0, l_render = False):
+        """!Adds overlay (grid, barscale, legend, etc.) to list of
+        overlays
+        
+        @param id overlay id (PseudoDC)
+        @param type overlay type (barscale, legend)
+        @param command GRASS command to render overlay
+        @param l_active overlay activated (True) or disabled (False)
+        @param l_hidden overlay is not shown in layer tree (if True)
+        @param l_render render an image (if True)
+        
+        @return new layer on success
+        @retutn None on failure
+        """
+        Debug.msg (2, "Map.AddOverlay(): cmd=%s, render=%d" % (command, l_render))
+        overlay = Overlay(id = id, type = type, cmd = command,
+                          active = l_active, hidden = l_hidden, opacity = l_opacity)
+        
+        # add maplayer to the list of layers
+        self.overlays.append(overlay)
+        
+        if l_render and command != '' and not overlay.Render():
+            raise GException(_("Unable render overlay <%s>.") % 
+                             name)
+        
+        return self.overlays[-1]
+
+    def ChangeOverlay(self, id, render = False, **kargs):
+        """!Change overlay properities
+        
+        Add new overlay if overlay with 'id' doesn't exist.
+        
+        @param id overlay id (PseudoDC)
+        @param type overlay type (barscale, legend)
+        @param command GRASS command to render overlay
+        @param l_active overlay activated (True) or disabled (False)
+        @param l_hidden overlay is not shown in layer tree (if True)
+        @param l_render render an image (if True)
+        
+        @return new layer on success
+        """
+        overlay = self.GetOverlay(id, list = False)
+        if  overlay is None:
+            overlay = Overlay(id, type = None, cmd = None)
+        
+        if 'type' in kargs:
+            overlay.SetName(kargs['type']) # type -> overlay
+        
+        if 'command' in kargs:
+            overlay.SetCmd(kargs['command'])
+        
+        if 'active' in kargs:
+            overlay.SetActive(kargs['active'])
+        
+        if 'hidden' in kargs:
+            overlay.SetHidden(kargs['hidden'])
+        
+        if 'opacity' in kargs:
+            overlay.SetOpacity(kargs['opacity'])
+        
+        if render and overlay.GetCmd() != [] and not overlay.Render():
+            raise GException(_("Unable render overlay <%s>") % 
+                             name)
+        
+        return overlay
+
+    def GetOverlay(self, id, list = False):
+        """!Return overlay(s) with 'id'
+        
+        @param id overlay id
+        @param list return list of overlays of True
+        otherwise suppose 'id' to be unique
+        
+        @return list of overlays (list=True)
+        @return overlay (list=False)
+        @retur None (list=False) if no overlay or more overlays found
+        """
+        ovl = []
+        for overlay in self.overlays:
+            if overlay.id == id:
+                ovl.append(overlay)
+                
+        if not list:
+            if len(ovl) != 1:
+                return None
+            else:
+                return ovl[0]
+        
+        return ovl
+
+    def DeleteOverlay(self, overlay):
+        """!Delete overlay
+        
+        @param overlay overlay layer
+        
+        @return removed overlay on success or None
+        """
+        return self.DeleteLayer(overlay, overlay = True)
+
+    def _clean(self, llist):
+        for layer in llist:
+            if layer.maskfile:
+                grass.try_remove(layer.maskfile)
+            if layer.mapfile:
+                grass.try_remove(layer.mapfile)
+            llist.remove(layer)
+        
+    def Clean(self):
+        """!Clean layer stack - go trough all layers and remove them
+        from layer list.
+
+        Removes also mapfile and maskfile.
+        """
+        self._clean(self.layers)
+        self._clean(self.overlays)
+        
+    def ReverseListOfLayers(self):
+        """!Reverse list of layers"""
+        return self.layers.reverse()
+
+    def RenderOverlays(self, force):
+        """!Render overlays only (for nviz)"""
+        for layer in self.overlays:
+            if force or layer.force_render:
+                layer.Render()
+                
+if __name__ == "__main__":
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    Map = Map()
+    Map.GetRegion(update = True)
+    
+    Map.AddLayer(type = "raster",
+                 name = "elevation",
+                 command = ["d.rast", "map=elevation at PERMANENT"],
+                 l_opacity = .7)
+    
+    Map.AddLayer(type = "vector",
+                 name = "roadsmajor",
+                 command = ["d.vect", "map=roadsmajor at PERMANENT", "color=red", "width=3", "type=line"])
+    
+    image = Map.Render(force = True)
+    
+    if image:
+        grass.call(["display", image])

Added: grass/trunk/gui/wxpython/core/settings.py
===================================================================
--- grass/trunk/gui/wxpython/core/settings.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/settings.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1046 @@
+"""!
+ at package core.settings
+
+ at brief Default GUI settings
+
+List of classes:
+ - Settings
+
+Usage:
+ at code
+from core.settings import UserSettings
+ at endcode
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import copy
+import types
+
+from core       import globalvar
+from core.gcmd  import GException, GError
+from core.utils import GetSettingsPath, PathJoin
+
+class Settings:
+    """!Generic class where to store settings"""
+    def __init__(self):
+        # settings file
+        self.filePath = os.path.join(GetSettingsPath(), 'wx')
+        
+        # key/value separator
+        self.sep = ';'
+        
+        try:
+            projFile = PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
+        except KeyError:
+            projFile = ''
+        
+        #
+        # default settings
+        #
+        self.defaultSettings = {
+            #
+            # general
+            #
+            'general': {
+                # use default window layout (layer manager, displays, ...)
+                'defWindowPos' : {
+                    'enabled' : True,
+                    'dim' : '0,0,%d,%d,%d,0,%d,%d' % \
+                        (globalvar.GM_WINDOW_SIZE[0],
+                         globalvar.GM_WINDOW_SIZE[1],
+                         globalvar.GM_WINDOW_SIZE[0],
+                         globalvar.MAP_WINDOW_SIZE[0],
+                         globalvar.MAP_WINDOW_SIZE[1])
+                    },
+                # workspace
+                'workspace' : {
+                    'posDisplay' : {
+                        'enabled' : False
+                        },
+                    'posManager' : {
+                        'enabled' : False
+                        },
+                    },
+                },
+            'manager' : {
+                # show opacity level widget
+                'changeOpacityLevel' : {
+                    'enabled' : False
+                    }, 
+                # ask when removing layer from layer tree
+                'askOnRemoveLayer' : {
+                    'enabled' : True
+                    },
+                # ask when quiting wxGUI or closing display
+                'askOnQuit' : {
+                    'enabled' : True
+                    },
+                # hide tabs
+                'hideTabs' : {
+                    'search' : False,
+                    'pyshell' : False,
+                    },
+                'copySelectedTextToClipboard' : {
+                    'enabled' : False
+                    },
+                },
+            #
+            # appearance
+            #
+            'appearance': {
+                'outputfont' : {
+                    'type' : 'Courier New',
+                    'size': '10',
+                    },
+                # expand/collapse element list
+                'elementListExpand' : {
+                    'selection' : 0 
+                    },
+                'menustyle' : {
+                    'selection' : 1
+                    },
+                'gSelectPopupHeight' : {
+                    'value' : 200
+                    },
+                'iconTheme' : {
+                    'type' : 'grass'
+                    },
+                },
+            #
+            # display
+            #
+            'display': {
+                'font' : {
+                    'type' : '',
+                    'encoding': 'ISO-8859-1',
+                    },
+                'driver': {
+                    'type': 'cairo'
+                    },
+                'alignExtent' : {
+                    'enabled' : True
+                    },
+                'compResolution' : {
+                    'enabled' : False
+                    },
+                'autoRendering': {
+                    'enabled' : True
+                    },
+                'autoZooming' : {
+                    'enabled' : False
+                    },
+                'statusbarMode': {
+                    'selection' : 0
+                    },
+                'bgcolor': {
+                    'color' : (255, 255, 255, 255),
+                    },
+                },
+            #
+            # projection
+            #
+            'projection' : {
+                'statusbar' : {
+                    'proj4'    : '',
+                    'epsg'     : '',
+                    'projFile' : projFile,
+                    },
+                'format' : {
+                    'll'  : 'DMS',
+                    'precision' : 2,
+                    },
+                },
+            #
+            # Attribute Table Manager
+            #
+            'atm' : {
+                'highlight' : {
+                    'color' : (255, 255, 0, 255),
+                    'width' : 2
+                    },
+                'leftDbClick' : {
+                    'selection' : 1 # draw selected
+                    },
+                'askOnDeleteRec' : {
+                    'enabled' : True
+                    },
+                'keycolumn' : {
+                    'value' : 'cat'
+                    },
+                'encoding' : {
+                    'value' : '',
+                    }
+                },
+            #
+            # Command
+            #
+            'cmd': {
+                'overwrite' : {
+                    'enabled' : False
+                    },
+                'closeDlg' : {
+                    'enabled' : False
+                    },
+                'verbosity' : {
+                    'selection' : 'grassenv'
+                    },
+                # d.rast
+                'rasterOpaque' : {
+                    'enabled' : False
+                    },
+                'rasterColorTable' : {
+                    'enabled'   : False,
+                    'selection' : 'rainbow',
+                    },
+                # d.vect
+                'showType': {
+                    'point' : {
+                        'enabled' : True
+                        },
+                    'line' : {
+                        'enabled' : True
+                        },
+                    'centroid' : {
+                        'enabled' : True
+                        },
+                    'boundary' : {
+                        'enabled' : True
+                        },
+                    'area' : {
+                        'enabled' : True
+                        },
+                    'face' : {
+                        'enabled' : True
+                        },
+                    },
+                'addNewLayer' : {
+                    'enabled' : True,
+                    },
+                'interactiveInput' : {
+                    'enabled' : True,
+                    },
+                },
+            #
+            # vdigit
+            #
+            'vdigit' : {
+                # symbology
+                'symbol' : {
+                    'highlight' : {
+                        'enabled' : None,
+                        'color' : (255, 255, 0, 255)
+                        }, # yellow
+                    'highlightDupl' : {
+                        'enabled' : None,
+                        'color' : (255, 72, 0, 255)
+                        }, # red
+                    'point' : {
+                        'enabled' : True,
+                        'color' : (0, 0, 0, 255)
+                        }, # black
+                    'line' : {
+                        'enabled' : True,
+                        'color' : (0, 0, 0, 255)
+                        }, # black
+                    'boundaryNo' : {
+                        'enabled' : True,
+                        'color' : (126, 126, 126, 255)
+                        }, # grey
+                    'boundaryOne' : {
+                        'enabled' : True,
+                        'color' : (0, 255, 0, 255)
+                        }, # green
+                    'boundaryTwo' : {
+                        'enabled' : True,
+                        'color' : (255, 135, 0, 255)
+                        }, # orange
+                    'centroidIn' : {
+                        'enabled' : True,
+                        'color' : (0, 0, 255, 255)
+                        }, # blue
+                    'centroidOut' : {
+                        'enabled' : True,
+                        'color' : (165, 42, 42, 255)
+                        }, # brown
+                    'centroidDup' : {
+                        'enabled' : True,
+                        'color' : (156, 62, 206, 255)
+                        }, # violet
+                    'nodeOne' : {
+                        'enabled' : True,
+                        'color' : (255, 0, 0, 255)
+                        }, # red
+                    'nodeTwo' : {
+                        'enabled' : True,
+                        'color' : (0, 86, 45, 255)
+                        }, # dark green
+                    'vertex' : {
+                        'enabled' : False,
+                        'color' : (255, 20, 147, 255)
+                        }, # deep pink
+                    'area' : {
+                        'enabled' : False,
+                        'color' : (217, 255, 217, 255)
+                        }, # green
+                    'direction' : {
+                        'enabled' : False,
+                        'color' : (255, 0, 0, 255)
+                        }, # red
+                    },
+                # display
+                'lineWidth' : {
+                    'value' : 2,
+                    'units' : 'screen pixels'
+                    },
+                # snapping
+                'snapping' : {
+                    'value' : 10,
+                    'units' : 'screen pixels'
+                    },
+                'snapToVertex' : {
+                    'enabled' : False
+                    },
+                # digitize new record
+                'addRecord' : {
+                    'enabled' : True
+                    },
+                'layer' :{
+                    'value' : 1
+                    },
+                'category' : {
+                    'value' : 1
+                    },
+                'categoryMode' : {
+                    'selection' : 0
+                    },
+                # delete existing feature(s)
+                'delRecord' : {
+                    'enabled' : True
+                    },
+                # query tool
+                'query' : {
+                    'selection' : 0,
+                    'box' : True
+                    },
+                'queryLength' : {
+                    'than-selection' : 0,
+                    'thresh' : 0
+                    },
+                'queryDangle' : {
+                    'than-selection' : 0,
+                    'thresh' : 0
+                    },
+                # select feature (point, line, centroid, boundary)
+                'selectType': {
+                    'point' : {
+                        'enabled' : True
+                        },
+                    'line' : {
+                        'enabled' : True
+                        },
+                    'centroid' : {
+                        'enabled' : True
+                        },
+                    'boundary' : {
+                        'enabled' : True
+                        },
+                    },
+                'selectThresh' : {
+                    'value' : 10,
+                    'units' : 'screen pixels'
+                    },
+                'checkForDupl' : {
+                    'enabled' : False
+                    },
+                'selectInside' : {
+                    'enabled' : False
+                    },
+                # exit
+                'saveOnExit' : {
+                    'enabled' : False,
+                    },
+                # break lines on intersection
+                'breakLines' : {
+                    'enabled' : False,
+                    },
+                },
+             # 
+             # plots for profiles, histograms, and scatterplots
+             #
+            'profile': {
+                'raster' : {
+                    'pcolor'        : (0, 0, 255, 255), # line color
+                    'pwidth'        : 1, # line width
+                    'pstyle'        : 'solid', # line pen style
+                    'datatype'      : 'cell', # raster type
+                    },
+                'font' : {
+                    'titleSize' : 12,
+                    'axisSize' : 11,
+                    'legendSize' : 10,
+                    },
+                'marker' : {
+                    'color' : (0, 0, 0, 255),
+                    'fill' : 'transparent',
+                    'size' : 2,
+                    'type' : 'triangle',
+                    'legend' : _('Segment break'),
+                    },
+                'grid' : {
+                    'color' : (200, 200, 200, 255),
+                    'enabled' : True,
+                    },
+                'x-axis' : {
+                    'type' : 'auto', # axis format
+                    'min' : 0, # axis min for custom axis range
+                    'max': 0, # axis max for custom axis range
+                    'log' : False,
+                    },
+                'y-axis' : {
+                    'type' : 'auto', # axis format
+                    'min' : 0, # axis min for custom axis range
+                    'max': 0, # axis max for custom axis range
+                    'log' : False,
+                    },
+                'legend' : {
+                    'enabled' : True
+                    },
+                },
+             'histogram': {
+                'raster' : {
+                    'pcolor'        : (0, 0, 255, 255), # line color
+                    'pwidth'        : 1, # line width
+                    'pstyle'        : 'solid', # line pen style
+                    'datatype'      : 'cell', # raster type
+                    },
+                'font' : {
+                    'titleSize'     : 12,
+                    'axisSize'      : 11,
+                    'legendSize'    : 10,
+                    },
+                'grid' : {
+                    'color'         : (200, 200, 200, 255),
+                    'enabled'       : True,
+                    },
+                'x-axis' : {
+                    'type'          : 'auto', # axis format
+                    'min'           : 0, # axis min for custom axis range
+                    'max'           : 0, # axis max for custom axis range
+                    'log'           : False,
+                    },
+                'y-axis' : {
+                    'type'          : 'auto', # axis format
+                    'min'           : 0, # axis min for custom axis range
+                    'max'           : 0, # axis max for custom axis range
+                    'log'           : False,
+                    },
+                'legend' : {
+                    'enabled'       : True
+                    },
+                },
+             'scatter': {
+                'rasters' : {
+                    'pcolor' : (0, 0, 255, 255),
+                    'pfill' : 'solid',
+                    'psize' : 1,
+                    'ptype' : 'dot',
+                    'plegend' : _('Data point'),
+                    0 : {'datatype' : 'CELL'},
+                    1 : {'datatype' : 'CELL'},
+                    },
+                'font' : {
+                    'titleSize'     : 12,
+                    'axisSize'      : 11,
+                    'legendSize'    : 10,
+                    },
+                'grid' : {
+                    'color'         : (200, 200, 200, 255),
+                    'enabled'       : True,
+                    },
+                'x-axis' : {
+                    'type'          : 'auto', # axis format
+                    'min'           : 0, # axis min for custom axis range
+                    'max'           : 0, # axis max for custom axis range
+                    'log'           : False,
+                    },
+                'y-axis' : {
+                    'type'          : 'auto', # axis format
+                    'min'           : 0, # axis min for custom axis range
+                    'max'           : 0, # axis max for custom axis range
+                    'log'           : False,
+                    },
+                'legend' : {
+                    '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,
+                    },
+                },
+            'nviz' : {
+                'view' : {
+                    'persp' : {
+                        'value' : 20,
+                        'step' : 2,
+                        },
+                    'position' : {
+                        'x' : 0.84,
+                        'y' : 0.16,
+                        },
+                    'twist' : {
+                        'value' : 0,
+                        },
+                    'z-exag' : {
+                        'min' : 0,
+                        'max' : 10,
+                        'value': 1,
+                        },
+                    'background' : {
+                        'color' : (255, 255, 255, 255), # white
+                        },
+                    },
+                'fly' : {
+                    'exag' : {
+                        'move' : 5,
+                        'turn' : 5,
+                        }
+                    },
+                'animation' : {
+                    'fps' : 24,
+                    'prefix' : _("animation")
+                    },
+                'surface' : {
+                    'shine': {
+                        'map' : False,
+                        'value' : 60.0,
+                        },
+                    'color' : {
+                        'map' : True,
+                        'value' : (100, 100, 100, 255), # constant: grey
+                        },
+                    'draw' : {
+                        'wire-color' : (136, 136, 136, 255),
+                        'mode' : 1, # fine
+                        'style' : 1, # surface
+                        'shading' : 1, # gouraud
+                        'res-fine' : 6,
+                        'res-coarse' : 9,
+                        },
+                    'position' : {
+                        'x' : 0,
+                        'y' : 0,
+                        'z' : 0,
+                        },
+                    },
+                'constant' : {
+                    'color' : (100, 100, 100, 255),
+                    'value' : 0.0,
+                    'transp' : 0,
+                    'resolution': 6
+                },
+                'vector' : {
+                    'lines' : {
+                        'show' : False,
+                        'width' : 2,
+                        'color' : (0, 0, 255, 255), # blue
+                        'flat' : False,
+                        'height' : 0,
+                        'rgbcolumn': None,
+                        'sizecolumn': None,
+                        },
+                    'points' : {
+                        'show' : False,
+                        'size' : 100,
+                        'width' : 2,
+                        'marker' : 2,
+                        'color' : (0, 0, 255, 255), # blue
+                        'height' : 0,
+                        'rgbcolumn': None,
+                        'sizecolumn': None,
+                        }
+                    },
+                'volume' : {
+                    'color' : {
+                        'map' : True,
+                        'value' : (100, 100, 100, 255), # constant: grey
+                        },
+                    'draw' : {
+                        'mode'       : 0, # isosurfaces
+                        'shading'    : 1, # gouraud
+                        'resolution' : 3, # polygon resolution
+                        },
+                    'shine': {
+                        'map' : False,
+                        'value' : 60,
+                        },
+                    'topo': {
+                        'map' : None,
+                        'value' : 0.0
+                        },
+                    'transp': {
+                        'map' : None,
+                        'value': 0
+                        },
+                    'mask': {
+                        'map' : None,
+                        'value': ''
+                        },
+                    'slice_position': {
+                        'x1' : 0,
+                        'x2' : 1,
+                        'y1' : 0,
+                        'y2' : 1,
+                        'z1' : 0,
+                        'z2' : 1,
+                        'axis' : 0,
+                        }
+                    },
+                'cplane' : {
+                    'shading': 4,
+                    'rotation':{
+                        'rot': 0, 
+                        'tilt': 0
+                        }, 
+                    'position':{
+                        'x' : 0,
+                        'y' : 0,
+                        'z' : 0
+                    }   
+                },
+                'light' : {
+                    'position' : {
+                        'x' : 0.68,
+                        'y' : -0.68,
+                        'z' : 80,
+                        },
+                    'bright'  : 80,
+                    'color'   : (255, 255, 255, 255), # white
+                    'ambient' : 20,
+                    },
+                'fringe' : {
+                    'elev'   : 55,
+                    'color'  : (128, 128, 128, 255), # grey
+                    },
+                'arrow': {
+                    'color': (0, 0, 0),
+                    },
+                'scalebar': {
+                    'color': (0, 0, 0),
+                    }
+                },
+            'modeler' : {
+                'disabled': {
+                    'color': (211, 211, 211, 255), # light grey
+                    },
+                'action' : {
+                    'color' : {
+                        'valid'   :  (180, 234, 154, 255), # light green
+                        'invalid' :  (255, 255, 255, 255), # white
+                        'running' :  (255, 0, 0, 255),     # red
+                        },
+                    'size' : {
+                        'width'  : 100,
+                        'height' : 50,
+                        },
+                    'width': {
+                        'parameterized' : 2,
+                        'default'       : 1,
+                        },
+                    },
+                'data' : { 
+                    'color': {
+                        'raster'   : (215, 215, 248, 255), # light blue
+                        'raster3d' : (215, 248, 215, 255), # light green
+                        'vector'   : (248, 215, 215, 255), # light red
+                        },
+                    'size' : {
+                        'width' : 175,
+                        'height' : 50,
+                        },
+                    },
+                'loop' : {
+                    'color' : {
+                        'valid'   :  (234, 226, 154, 255), # light yellow
+                        },
+                    'size' : {
+                        'width' : 175,
+                        'height' : 40,
+                        },
+                    },
+                'if-else' : {
+                    'size' : {
+                        'width' : 150,
+                        'height' : 40,
+                        },
+                    },
+                },
+            }
+
+        # quick fix, http://trac.osgeo.org/grass/ticket/1233
+        # TODO
+        if sys.platform == 'darwin':
+            self.defaultSettings['general']['defWindowPos']['enabled'] = False
+        
+        #
+        # user settings
+        #
+        self.userSettings = copy.deepcopy(self.defaultSettings)
+        try:
+            self.ReadSettingsFile()
+        except GException, e:
+            print >> sys.stderr, e.value
+
+        #
+        # internal settings (based on user settings)
+        #
+        self.internalSettings = {}
+        for group in self.userSettings.keys():
+            self.internalSettings[group] = {}
+            for key in self.userSettings[group].keys():
+                self.internalSettings[group][key] = {}
+
+        # self.internalSettings['general']["mapsetPath"]['value'] = self.GetMapsetPath()
+        self.internalSettings['appearance']['elementListExpand']['choices'] = \
+            (_("Collapse all except PERMANENT and current"),
+             _("Collapse all except PERMANENT"),
+             _("Collapse all except current"),
+             _("Collapse all"),
+             _("Expand all"))
+        self.internalSettings['atm']['leftDbClick']['choices'] = (_('Edit selected record'),
+                                                                  _('Display selected'))
+        
+        self.internalSettings['cmd']['verbosity']['choices'] = ('grassenv',
+                                                                'verbose',
+                                                                'quiet')
+                                                                
+        self.internalSettings['appearance']['iconTheme']['choices'] = ('grass',)
+        self.internalSettings['appearance']['menustyle']['choices'] = \
+                   (_("Classic (labels only)"),
+                    _("Combined (labels and module names)"),
+                    _("Professional (module names only)"))
+        self.internalSettings['appearance']['gSelectPopupHeight']['min'] = 50
+        # there is also maxHeight given to TreeCtrlComboPopup.GetAdjustedSize
+        self.internalSettings['appearance']['gSelectPopupHeight']['max'] = 1000
+        
+        self.internalSettings['display']['driver']['choices'] = ['cairo', 'png']
+        self.internalSettings['display']['statusbarMode']['choices'] = None # set during MapFrame init
+
+        self.internalSettings['nviz']['view'] = {}
+        self.internalSettings['nviz']['view']['twist'] = {}
+        self.internalSettings['nviz']['view']['twist']['min'] = -180
+        self.internalSettings['nviz']['view']['twist']['max'] = 180
+        self.internalSettings['nviz']['view']['persp'] = {}
+        self.internalSettings['nviz']['view']['persp']['min'] = 1
+        self.internalSettings['nviz']['view']['persp']['max'] = 100
+        self.internalSettings['nviz']['view']['height'] = {}
+        self.internalSettings['nviz']['view']['height']['value'] = -1
+        self.internalSettings['nviz']['view']['z-exag'] = {}
+        self.internalSettings['nviz']['view']['z-exag']['original'] = 1
+        self.internalSettings['nviz']['view']['rotation'] = None
+        self.internalSettings['nviz']['view']['focus'] = {}
+        self.internalSettings['nviz']['view']['focus']['x'] = -1
+        self.internalSettings['nviz']['view']['focus']['y'] = -1
+        self.internalSettings['nviz']['view']['focus']['z'] = -1
+        self.internalSettings['nviz']['view']['dir'] = {}
+        self.internalSettings['nviz']['view']['dir']['x'] = -1
+        self.internalSettings['nviz']['view']['dir']['y'] = -1
+        self.internalSettings['nviz']['view']['dir']['z'] = -1
+        self.internalSettings['nviz']['view']['dir']['use'] = False
+        
+        for decor in ('arrow', 'scalebar'):
+            self.internalSettings['nviz'][decor] = {}
+            self.internalSettings['nviz'][decor]['position'] = {}
+            self.internalSettings['nviz'][decor]['position']['x'] = 0
+            self.internalSettings['nviz'][decor]['position']['y'] = 0
+            self.internalSettings['nviz'][decor]['size'] = 100
+        self.internalSettings['nviz']['vector'] = {}
+        self.internalSettings['nviz']['vector']['points'] = {}
+        self.internalSettings['nviz']['vector']['points']['marker'] = ("x",
+                                                                       _("box"),
+                                                                       _("sphere"),
+                                                                       _("cube"),
+                                                                       _("diamond"),
+                                                                       _("dtree"),
+                                                                       _("ctree"),
+                                                                       _("aster"),
+                                                                       _("gyro"),
+                                                                       _("histogram"))
+        self.internalSettings['vdigit']['bgmap'] = {}
+        self.internalSettings['vdigit']['bgmap']['value'] = ''
+        
+    def ReadSettingsFile(self, settings = None):
+        """!Reads settings file (mapset, location, gisdbase)"""
+        if settings is None:
+            settings = self.userSettings
+        
+        self._readFile(self.filePath, settings)
+        
+        # set environment variables
+        font = self.Get(group = 'display', key = 'font', subkey = 'type')
+        enc  = self.Get(group = 'display', key = 'font', subkey = 'encoding')
+        if font:
+            os.environ["GRASS_FONT"] = font
+        if enc:
+            os.environ["GRASS_ENCODING"] = enc
+        
+    def _readFile(self, filename, settings = None):
+        """!Read settings from file to dict
+
+        @param filename settings file path
+        @param settings dict where to store settings (None for self.userSettings)
+        """
+        if settings is None:
+            settings = self.userSettings
+        
+        if not os.path.exists(filename):
+            return
+        
+        try:
+            fd = open(filename, "r")
+        except IOError:
+            sys.stderr.write(_("Unable to read settings file <%s>\n") % filename)
+            return
+        
+        try:
+            line = ''
+            for line in fd.readlines():
+                line = line.rstrip('%s' % os.linesep)
+                group, key = line.split(self.sep)[0:2]
+                kv = line.split(self.sep)[2:]
+                subkeyMaster = None
+                if len(kv) % 2 != 0: # multiple (e.g. nviz)
+                    subkeyMaster = kv[0]
+                    del kv[0]
+                idx = 0
+                while idx < len(kv):
+                    if subkeyMaster:
+                        subkey = [subkeyMaster, kv[idx]]
+                    else:
+                        subkey = kv[idx]
+                    value = kv[idx+1]
+                    value = self._parseValue(value, read = True)
+                    self.Append(settings, group, key, subkey, value)
+                    idx += 2
+        except ValueError, e:
+            print >> sys.stderr, _("Error: Reading settings from file <%(file)s> failed.\n"
+                                   "\t\tDetails: %(detail)s\n"
+                                   "\t\tLine: '%(line)s'\n") % { 'file' : filename,
+                                                               'detail' : e,
+                                                               'line' : line }
+            fd.close()
+        
+        fd.close()
+        
+    def SaveToFile(self, settings = None):
+        """!Save settings to the file"""
+        if settings is None:
+            settings = self.userSettings
+        
+        dirPath = GetSettingsPath()
+        if not os.path.exists(dirPath):
+            try:
+                os.mkdir(dirPath)
+            except:
+                GError(_('Unable to create settings directory'))
+                return
+        
+        try:
+            file = open(self.filePath, "w")
+            for group in settings.keys():
+                for key in settings[group].keys():
+                    subkeys = settings[group][key].keys()
+                    file.write('%s%s%s%s' % (group, self.sep, key, self.sep))
+                    for idx in range(len(subkeys)):
+                        value = settings[group][key][subkeys[idx]]
+                        if type(value) == types.DictType:
+                            if idx > 0:
+                                file.write('%s%s%s%s%s' % (os.linesep, group, self.sep, key, self.sep))
+                            file.write('%s%s' % (subkeys[idx], self.sep))
+                            kvalues = settings[group][key][subkeys[idx]].keys()
+                            srange = range(len(kvalues))
+                            for sidx in srange:
+                                svalue = self._parseValue(settings[group][key][subkeys[idx]][kvalues[sidx]])
+                                file.write('%s%s%s' % (kvalues[sidx], self.sep,
+                                                       svalue))
+                                if sidx < len(kvalues) - 1:
+                                    file.write('%s' % self.sep)
+                        else:
+                            if idx > 0 and \
+                                    type(settings[group][key][subkeys[idx - 1]]) == types.DictType:
+                                file.write('%s%s%s%s%s' % (os.linesep, group, self.sep, key, self.sep))
+                            value = self._parseValue(settings[group][key][subkeys[idx]])
+                            file.write('%s%s%s' % (subkeys[idx], self.sep, value))
+                            if idx < len(subkeys) - 1 and \
+                                    type(settings[group][key][subkeys[idx + 1]]) != types.DictType:
+                                file.write('%s' % self.sep)
+                    file.write(os.linesep)
+        except IOError, e:
+            raise GException(e)
+        except StandardError, e:
+            raise GException(_('Writing settings to file <%(file)s> failed.'
+                               '\n\nDetails: %(detail)s') % { 'file' : self.filePath,
+                                                              'detail' : e })
+        
+        file.close()
+        
+    def _parseValue(self, value, read = False):
+        """!Parse value to be store in settings file"""
+        if read: # -> read settings (cast values)
+            if value == 'True':
+                value = True
+            elif value == 'False':
+                value = False
+            elif value == 'None':
+                value = None
+            elif ':' in value: # -> color
+                try:
+                    value = tuple(map(int, value.split(':')))
+                except ValueError: # -> string
+                    pass
+            else:
+                try:
+                    value = int(value)
+                except ValueError:
+                    try:
+                        value = float(value)
+                    except ValueError:
+                        pass
+        else: # -> write settings
+            if type(value) == type(()): # -> color
+                value = str(value[0]) + ':' +\
+                    str(value[1]) + ':' + \
+                    str(value[2])
+                
+        return value
+
+    def Get(self, group, key = None, subkey = None, internal = False):
+        """!Get value by key/subkey
+
+        Raise KeyError if key is not found
+        
+        @param group settings group
+        @param key (value, None)
+        @param subkey (value, list or None)
+        @param internal use internal settings instead
+
+        @return value
+        """
+        if internal is True:
+            settings = self.internalSettings
+        else:
+            settings = self.userSettings
+            
+        try:
+            if subkey is None:
+                if key is None:
+                    return settings[group]
+                else:
+                    return settings[group][key]
+            else:
+                if type(subkey) == type(tuple()) or \
+                        type(subkey) == type(list()):
+                    return settings[group][key][subkey[0]][subkey[1]]
+                else:
+                    return settings[group][key][subkey]  
+
+        except KeyError:
+            print >> sys.stderr, "Settings: unable to get value '%s:%s:%s'\n" % \
+                (group, key, subkey)
+        
+    def Set(self, group, value, key = None, subkey = None, internal = False):
+        """!Set value of key/subkey
+        
+        Raise KeyError if group/key is not found
+        
+        @param group settings group
+        @param key key (value, None)
+        @param subkey subkey (value, list or None)
+        @param value value
+        @param internal use internal settings instead
+        """
+        if internal is True:
+            settings = self.internalSettings
+        else:
+            settings = self.userSettings
+        
+        try:
+            if subkey is None:
+                if key is None:
+                    settings[group] = value
+                else:
+                    settings[group][key] = value
+            else:
+                if type(subkey) == type(tuple()) or \
+                        type(subkey) == type(list()):
+                    settings[group][key][subkey[0]][subkey[1]] = value
+                else:
+                    settings[group][key][subkey] = value
+        except KeyError:
+            raise GException("%s '%s:%s:%s'" % (_("Unable to set "), group, key, subkey))
+        
+    def Append(self, dict, group, key, subkey, value):
+        """!Set value of key/subkey
+
+        Create group/key/subkey if not exists
+        
+        @param dict settings dictionary to use
+        @param group settings group
+        @param key key
+        @param subkey subkey (value or list)
+        @param value value
+        """
+        if group not in dict:
+            dict[group] = {}
+
+        if key not in dict[group]:
+            dict[group][key] = {}
+
+        if type(subkey) == types.ListType:
+            # TODO: len(subkey) > 2
+            if subkey[0] not in dict[group][key]:
+                dict[group][key][subkey[0]] = {}
+            try:
+                dict[group][key][subkey[0]][subkey[1]] = value
+            except TypeError:
+                print >> sys.stderr, _("Unable to parse settings '%s'") % value + \
+                    ' (' + group + ':' + key + ':' + subkey[0] + ':' + subkey[1] + ')'
+        else:
+            try:
+                dict[group][key][subkey] = value
+            except TypeError:
+                print >> sys.stderr, _("Unable to parse settings '%s'") % value + \
+                    ' (' + group + ':' + key + ':' + subkey + ')'
+        
+    def GetDefaultSettings(self):
+        """!Get default user settings"""
+        return self.defaultSettings
+
+    def Reset(self, key = None):
+        """!Reset to default settings
+
+        @key key in settings dict (None for all keys)
+        """
+        if not key:
+            self.userSettings = copy.deepcopy(self.defaultSettings)
+        else:
+            self.userSettings[key] = copy.deepcopy(self.defaultSettings[key])
+        
+UserSettings = Settings()


Property changes on: grass/trunk/gui/wxpython/core/settings.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/core/units.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/units.py)
===================================================================
--- grass/trunk/gui/wxpython/core/units.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/units.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,116 @@
+"""!
+ at package core.units
+
+ at brief Units management
+
+ at todo Probably will be replaced by Python ctypes fns in the near
+future(?)
+
+Usage:
+ at code
+from core.units import Units
+ at endcode
+
+Classes:
+ - BaseUnits
+
+(C) 2009, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+class BaseUnits:
+    def __init__(self):
+        self._units = dict()
+        self._units['length'] = { 0 : { 'key' : 'mu', 'label' : _('map units') },
+                             1 : { 'key' : 'me', 'label' : _('meters') },
+                             2 : { 'key' : 'km', 'label' : _('kilometers') },
+                             3 : { 'key' : 'mi', 'label' : _('miles') },
+                             4 : { 'key' : 'ft', 'label' : _('feet') } }
+        
+        self._units['area']   = { 0 : { 'key' : 'mu', 'label' : _('sq map units') },
+                             1 : { 'key' : 'me', 'label' : _('sq meters') },
+                             2 : { 'key' : 'km', 'label' : _('sq kilometers') },
+                             3 : { 'key' : 'ar', 'label' : _('acres') },
+                             4 : { 'key' : 'ht', 'label' : _('hectares') } }
+
+    def GetUnitsList(self, type):
+        """!Get list of units (their labels)
+        
+        @param type units type ('length' or 'area')
+        
+        @return list of units labels
+        """
+        result = list()
+        try:
+            keys = self._units[type].keys()
+            keys.sort()
+            for idx in keys:
+                result.append(self._units[type][idx]['label'])
+        except KeyError:
+            pass
+        
+        return result
+
+    def GetUnitsKey(self, type, index):
+        """!Get units key based on index
+        
+        @param type units type ('length' or 'area')
+        @param index units index
+        """
+        return self._units[type][index]['key']
+
+    def GetUnitsIndex(self, type, key):
+        """!Get units index based on key
+        
+        @param type units type ('length' or 'area')
+        @param key units key, e.g. 'me' for meters
+
+        @return index
+        """
+        for k, u in self._units[type].iteritems():
+            if u['key'] == key:
+                return k
+        return 0
+
+Units = BaseUnits()
+
+def ConvertValue(value, type, units):
+    """!Convert value from map units to given units
+
+    Inspired by vector/v.to.db/units.c
+
+    @param value value to be converted
+    @param type units type ('length', 'area')
+    @param unit  destination units
+    """
+    # get map units
+    # TODO
+    
+    f = 1
+    if type == 'length':
+        if units == 'me':
+            f = 1.0
+        elif units == 'km':
+            f = 1.0e-3
+        elif units == 'mi':
+            f = 6.21371192237334e-4
+        elif units == 'ft':
+            f = 3.28083989501312
+    else: # -> area
+        if units == 'me':
+            f = 1.0
+        elif units == 'km':
+            f = 1.0e-6
+        elif units == 'mi':
+            f = 3.86102158542446e-7
+        elif units == 'ft':
+            f = 10.7639104167097
+        elif units == 'ar':
+            f = 2.47105381467165e-4
+        elif units == 'ht':
+            f = 1.0e-4
+
+    return f * value

Copied: grass/trunk/gui/wxpython/core/utils.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/utils.py)
===================================================================
--- grass/trunk/gui/wxpython/core/utils.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/utils.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,745 @@
+"""!
+ at package core.utils
+
+ at brief Misc utilities for wxGUI
+
+(C) 2007-2009, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Jachym Cepicky
+"""
+
+import os
+import sys
+import platform
+import string
+import glob
+import shlex
+import re
+
+from core.globalvar import ETCDIR
+sys.path.append(os.path.join(ETCDIR, "python"))
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+from core.gcmd  import RunCommand
+from core.debug import Debug
+
+def normalize_whitespace(text):
+    """!Remove redundant whitespace from a string"""
+    return string.join(string.split(text), ' ')
+
+def split(s):
+    """!Platform spefic shlex.split"""
+    if sys.version_info >= (2, 6):
+        return shlex.split(s, posix = (sys.platform != "win32"))
+    elif sys.platform == "win32":
+        return shlex.split(s.replace('\\', r'\\'))
+    else:
+        return shlex.split(s)
+
+def GetTempfile(pref=None):
+    """!Creates GRASS temporary file using defined prefix.
+
+    @todo Fix path on MS Windows/MSYS
+
+    @param pref prefer the given path
+
+    @return Path to file name (string) or None
+    """
+    from core import cmd as gcmd
+    
+    ret = RunCommand('g.tempfile',
+                     read = True,
+                     pid = os.getpid())
+
+    tempfile = ret.splitlines()[0].strip()
+
+    # FIXME
+    # ugly hack for MSYS (MS Windows)
+    if platform.system() == 'Windows':
+	tempfile = tempfile.replace("/", "\\")
+    try:
+        path, file = os.path.split(tempfile)
+        if pref:
+            return os.path.join(pref, file)
+	else:
+	    return tempfile
+    except:
+        return None
+
+def GetLayerNameFromCmd(dcmd, fullyQualified = False, param = None,
+                        layerType = None):
+    """!Get map name from GRASS command
+    
+    Parameter dcmd can be modified when first parameter is not
+    defined.
+    
+    @param dcmd GRASS command (given as list)
+    @param fullyQualified change map name to be fully qualified
+    @param param params directory
+    @param layerType check also layer type ('raster', 'vector', '3d-raster', ...)
+    
+    @return tuple (name, found)
+    """
+    mapname = ''
+    found   = True
+    
+    if len(dcmd) < 1:
+        return mapname, False
+    
+    if 'd.grid' == dcmd[0]:
+        mapname = 'grid'
+    elif 'd.geodesic' in dcmd[0]:
+        mapname = 'geodesic'
+    elif 'd.rhumbline' in dcmd[0]:
+        mapname = 'rhumb'
+    else:
+        params = list()
+        for idx in range(len(dcmd)):
+            try:
+                p, v = dcmd[idx].split('=', 1)
+            except ValueError:
+                continue
+            
+            if p == param:
+                params = [(idx, p, v)]
+                break
+            
+            if p in ('map', 'input', 'layer',
+                     'red', 'blue', 'green',
+                     'h_map', 's_map', 'i_map',
+                     'reliefmap', 'labels'):
+                params.append((idx, p, v))
+        
+        if len(params) < 1:
+            if len(dcmd) > 1 and '=' not in dcmd[1]:
+                task = gtask.parse_interface(dcmd[0])
+                p = task.get_options()['params'][0].get('name', '')
+                params.append((1, p, dcmd[1]))
+            else:
+                return mapname, False
+        
+        mapname = params[0][2]
+        mapset = ''
+        if fullyQualified and '@' not in mapname:
+            if layerType in ('raster', 'vector', '3d-raster', 'rgb', 'his'):
+                try:
+                    if layerType in ('raster', 'rgb', 'his'):
+                        findType = 'cell'
+                    else:
+                        findType = layerType
+                    mapset = grass.find_file(mapname, element = findType)['mapset']
+                except AttributeError, e: # not found
+                    return '', False
+                if not mapset:
+                    found = False
+            else:
+                mapset = grass.gisenv()['MAPSET']
+            
+            # update dcmd
+            for i, p, v in params:
+                if p == 'layer':
+                    continue
+                dcmd[i] = p + '=' + v
+                if mapset:
+                    dcmd[i] += '@' + mapset
+        
+        maps = list()
+        ogr = False
+        for i, p, v in params:
+            if v.lower().rfind('@ogr') > -1:
+                ogr = True
+            if p == 'layer' and not ogr:
+                continue
+            maps.append(dcmd[i].split('=', 1)[1])
+        
+        mapname = '\n'.join(maps)
+    
+    return mapname, found
+
+def GetValidLayerName(name):
+    """!Make layer name SQL compliant, based on G_str_to_sql()
+    
+    @todo: Better use directly GRASS Python SWIG...
+    """
+    retName = str(name).strip()
+    
+    # check if name is fully qualified
+    if '@' in retName:
+        retName, mapset = retName.split('@')
+    else:
+        mapset = None
+    
+    cIdx = 0
+    retNameList = list(retName)
+    for c in retNameList:
+        if not (c >= 'A' and c <= 'Z') and \
+               not (c >= 'a' and c <= 'z') and \
+               not (c >= '0' and c <= '9'):
+            retNameList[cIdx] = '_'
+        cIdx += 1
+    retName = ''.join(retNameList)
+    
+    if not (retName[0] >= 'A' and retName[0] <= 'Z') and \
+           not (retName[0] >= 'a' and retName[0] <= 'z'):
+        retName = 'x' + retName[1:]
+
+    if mapset:
+        retName = retName + '@' + mapset
+        
+    return retName
+
+def ListOfCatsToRange(cats):
+    """!Convert list of category number to range(s)
+
+    Used for example for d.vect cats=[range]
+
+    @param cats category list
+
+    @return category range string
+    @return '' on error
+    """
+
+    catstr = ''
+
+    try:
+        cats = map(int, cats)
+    except:
+        return catstr
+
+    i = 0
+    while i < len(cats):
+        next = 0
+        j = i + 1
+        while j < len(cats):
+            if cats[i + next] == cats[j] - 1:
+                next += 1
+            else:
+                break
+            j += 1
+
+        if next > 1:
+            catstr += '%d-%d,' % (cats[i], cats[i + next])
+            i += next + 1
+        else:
+            catstr += '%d,' % (cats[i])
+            i += 1
+        
+    return catstr.strip(',')
+
+def ListOfMapsets(get = 'ordered'):
+    """!Get list of available/accessible mapsets
+
+    @param get method ('all', 'accessible', 'ordered')
+    
+    @return list of mapsets
+    @return None on error
+    """
+    mapsets = []
+    
+    if get == 'all' or get == 'ordered':
+        ret = RunCommand('g.mapsets',
+                         read = True,
+                         quiet = True,
+                         flags = 'l',
+                         fs = 'newline')
+        
+        if ret:
+            mapsets = ret.splitlines()
+            ListSortLower(mapsets)
+        else:
+            return None
+        
+    if get == 'accessible' or get == 'ordered':
+        ret = RunCommand('g.mapsets',
+                         read = True,
+                         quiet = True,
+                         flags = 'p',
+                         fs = 'newline')
+        if ret:
+            if get == 'accessible':
+                mapsets = ret.splitlines()
+            else:
+                mapsets_accessible = ret.splitlines()
+                for mapset in mapsets_accessible:
+                    mapsets.remove(mapset)
+                mapsets = mapsets_accessible + mapsets
+        else:
+            return None
+    
+    return mapsets
+
+def ListSortLower(list):
+    """!Sort list items (not case-sensitive)"""
+    list.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
+
+def GetVectorNumberOfLayers(parent, vector):
+    """!Get list of vector layers"""
+    layers = list()
+    if not vector:
+        return layers
+    
+    fullname = grass.find_file(name = vector, element = 'vector')['fullname']
+    if not fullname:
+        Debug.msg(5, "utils.GetVectorNumberOfLayers(): vector map '%s' not found" % vector)
+        return layers
+    
+    ret, out, msg = RunCommand('v.db.connect',
+                               getErrorMsg = True,
+                               read = True,
+                               flags = 'g',
+                               map = fullname,
+                               fs = ';')
+    if ret != 0:
+        sys.stderr.write(_("Vector map <%(map)s>: %(msg)s\n") % { 'map' : fullname, 'msg' : msg })
+        return layers
+    else:
+        Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret)
+    
+    for line in ret.splitlines():
+        try:
+            layer = line.split(';')[0]
+            if '/' in layer:
+                layer = layer.split('/')[0]
+            layers.append(layer)
+        except IndexError:
+            pass
+    
+    Debug.msg(3, "utils.GetVectorNumberOfLayers(): vector=%s -> %s" % \
+                  (fullname, ','.join(layers)))
+    
+    return layers
+
+def Deg2DMS(lon, lat, string = True, hemisphere = True, precision = 3):
+    """!Convert deg value to dms string
+
+    @param lon longitude (x)
+    @param lat latitude (y)
+    @param string True to return string otherwise tuple
+    @param hemisphere print hemisphere
+    @param precision seconds precision
+    
+    @return DMS string or tuple of values
+    @return empty string on error
+    """
+    try:
+        flat = float(lat)
+        flon = float(lon)
+    except ValueError:
+        if string:
+            return ''
+        else:
+            return None
+
+    # fix longitude
+    while flon > 180.0:
+        flon -= 360.0
+    while flon < -180.0:
+        flon += 360.0
+
+    # hemisphere
+    if hemisphere:
+        if flat < 0.0:
+            flat = abs(flat)
+            hlat = 'S'
+        else:
+            hlat = 'N'
+
+        if flon < 0.0:
+            hlon = 'W'
+            flon = abs(flon)
+        else:
+            hlon = 'E'
+    else:
+        flat = abs(flat)
+        flon = abs(flon)
+        hlon = ''
+        hlat = ''
+    
+    slat = __ll_parts(flat, precision = precision)
+    slon = __ll_parts(flon, precision = precision)
+
+    if string:
+        return slon + hlon + '; ' + slat + hlat
+    
+    return (slon + hlon, slat + hlat)
+
+def DMS2Deg(lon, lat):
+    """!Convert dms value to deg
+
+    @param lon longitude (x)
+    @param lat latitude (y)
+    
+    @return tuple of converted values
+    @return ValueError on error
+    """
+    x = __ll_parts(lon, reverse = True)
+    y = __ll_parts(lat, reverse = True)
+    
+    return (x, y)
+
+def __ll_parts(value, reverse = False, precision = 3):
+    """!Converts deg to d:m:s string
+
+    @param value value to be converted
+    @param reverse True to convert from d:m:s to deg
+    @param precision seconds precision (ignored if reverse is True)
+    
+    @return converted value (string/float)
+    @return ValueError on error (reverse == True)
+    """
+    if not reverse:
+        if value == 0.0:
+            return '%s%.*f' % ('00:00:0', precision, 0.0)
+    
+        d = int(int(value))
+        m = int((value - d) * 60)
+        s = ((value - d) * 60 - m) * 60
+        if m < 0:
+            m = '00'
+        elif m < 10:
+            m = '0' + str(m)
+        else:
+            m = str(m)
+        if s < 0:
+            s = '00.0000'
+        elif s < 10.0:
+            s = '0%.*f' % (precision, s)
+        else:
+            s = '%.*f' % (precision, s)
+        
+        return str(d) + ':' + m + ':' + s
+    else: # -> reverse
+        try:
+            d, m, s = value.split(':')
+            hs = s[-1]
+            s = s[:-1]
+        except ValueError:
+            try:
+                d, m = value.split(':')
+                hs = m[-1]
+                m = m[:-1]
+                s = '0.0'
+            except ValueError:
+                try:
+                    d = value
+                    hs = d[-1]
+                    d = d[:-1]
+                    m = '0'
+                    s = '0.0'
+                except ValueError:
+                    raise ValueError
+        
+        if hs not in ('N', 'S', 'E', 'W'):
+            raise ValueError
+        
+        coef = 1.0
+        if hs in ('S', 'W'):
+            coef = -1.0
+        
+        fm = int(m) / 60.0
+        fs = float(s) / (60 * 60)
+        
+        return coef * (float(d) + fm + fs)
+    
+def GetCmdString(cmd):
+    """
+    Get GRASS command as string.
+    
+    @param cmd GRASS command given as dictionary
+    
+    @return command string
+    """
+    scmd = ''
+    if not cmd:
+        return scmd
+    
+    scmd = cmd[0]
+    
+    if 'flags' in cmd[1]:
+        for flag in cmd[1]['flags']:
+            scmd += ' -' + flag
+    for flag in ('verbose', 'quiet', 'overwrite'):
+        if flag in cmd[1] and cmd[1][flag] is True:
+            scmd += ' --' + flag
+    
+    for k, v in cmd[1].iteritems():
+        if k in ('flags', 'verbose', 'quiet', 'overwrite'):
+            continue
+        scmd += ' %s=%s' % (k, v)
+            
+    return scmd
+
+def CmdToTuple(cmd):
+    """!Convert command list to tuple for gcmd.RunCommand()"""
+    if len(cmd) < 1:
+        return None
+        
+    dcmd = {}
+    for item in cmd[1:]:
+        if '=' in item: # params
+            key, value = item.split('=', 1)
+            dcmd[str(key)] = str(value).replace('"', '')
+        elif item[:2] == '--': # long flags
+            flag = item[2:]
+            if flag in ('verbose', 'quiet', 'overwrite'):
+                dcmd[str(flag)] = True
+        else: # -> flags
+            if 'flags' not in dcmd:
+                dcmd['flags'] = ''
+            dcmd['flags'] += item.replace('-', '')
+                
+    return (cmd[0],
+            dcmd)
+
+def PathJoin(*args):
+    """!Check path created by os.path.join"""
+    path = os.path.join(*args)
+    if platform.system() == 'Windows' and \
+            '/' in path:
+        return path[1].upper() + ':\\' + path[3:].replace('/', '\\')
+    
+    return path
+
+def ReadEpsgCodes(path):
+    """!Read EPSG code from the file
+
+    @param path full path to the file with EPSG codes
+
+    @return dictionary of EPSG code
+    @return string on error
+    """
+    epsgCodeDict = dict()
+    try:
+        try:
+            f = open(path, "r")
+        except IOError:
+            return _("failed to open '%s'" % path)
+        
+        i = 0
+        code = None
+        for line in f.readlines():
+            line = line.strip()
+            if len(line) < 1:
+                continue
+                
+            if line[0] == '#':
+                descr = line[1:].strip()
+            elif line[0] == '<':
+                code, params = line.split(" ", 1)
+                try:
+                    code = int(code.replace('<', '').replace('>', ''))
+                except ValueError:
+                    return e
+            
+            if code is not None:
+                epsgCodeDict[code] = (descr, params)
+                code = None
+            i += 1
+        
+        f.close()
+    except StandardError, e:
+        return e
+    
+    return epsgCodeDict
+
+def ReprojectCoordinates(coord, projOut, projIn = None, flags = ''):
+    """!Reproject coordinates
+
+    @param coord coordinates given as tuple
+    @param projOut output projection
+    @param projIn input projection (use location projection settings)
+
+    @return reprojected coordinates (returned as tuple)
+    """
+    coors = RunCommand('m.proj',
+                       flags = flags,
+                       input = '-',
+                       proj_input = projIn,
+                       proj_output = projOut,
+                       fs = ';',
+                       stdin = '%f;%f' % (coord[0], coord[1]),
+                       read = True)
+    if coors:
+        coors = coors.split(';')
+        e = coors[0]
+        n = coors[1]
+        try:
+            proj = projOut.split(' ')[0].split('=')[1]
+        except IndexError:
+            proj = ''
+        if proj in ('ll', 'latlong', 'longlat') and 'd' not in flags:
+            return (proj, (e, n))
+        else:
+            try:
+                return (proj, (float(e), float(n)))
+            except ValueError:
+                return (None, None)
+    
+    return (None, None)
+
+def GetListOfLocations(dbase):
+    """!Get list of GRASS locations in given dbase
+
+    @param dbase GRASS database path
+
+    @return list of locations (sorted)
+    """
+    listOfLocations = list()
+
+    try:
+        for location in glob.glob(os.path.join(dbase, "*")):
+            try:
+                if os.path.join(location, "PERMANENT") in glob.glob(os.path.join(location, "*")):
+                    listOfLocations.append(os.path.basename(location))
+            except:
+                pass
+    except UnicodeEncodeError, e:
+        raise e
+    
+    ListSortLower(listOfLocations)
+    
+    return listOfLocations
+
+def GetListOfMapsets(dbase, location, selectable = False):
+    """!Get list of mapsets in given GRASS location
+
+    @param dbase      GRASS database path
+    @param location   GRASS location
+    @param selectable True to get list of selectable mapsets, otherwise all
+
+    @return list of mapsets - sorted (PERMANENT first)
+    """
+    listOfMapsets = list()
+    
+    if selectable:
+        ret = RunCommand('g.mapset',
+                         read = True,
+                         flags = 'l',
+                         location = location,
+                         gisdbase = dbase)
+        
+        if not ret:
+            return listOfMapsets
+        
+        for line in ret.rstrip().splitlines():
+            listOfMapsets += line.split(' ')
+    else:
+        for mapset in glob.glob(os.path.join(dbase, location, "*")):
+            if os.path.isdir(mapset) and \
+                    os.path.isfile(os.path.join(dbase, location, mapset, "WIND")):
+                listOfMapsets.append(os.path.basename(mapset))
+    
+    ListSortLower(listOfMapsets)
+    return listOfMapsets
+
+def GetColorTables():
+    """!Get list of color tables"""
+    ret = RunCommand('r.colors',
+                     read = True,
+                     flags = 'l')
+    if not ret:
+        return list()
+    
+    return ret.splitlines()
+
+def _getGDALFormats():
+    """!Get dictionary of avaialble GDAL drivers"""
+    ret = grass.read_command('r.in.gdal',
+                             quiet = True,
+                             flags = 'f')
+    
+    return _parseFormats(ret), _parseFormats(ret, writableOnly = True)
+
+def _getOGRFormats():
+    """!Get dictionary of avaialble OGR drivers"""
+    ret = grass.read_command('v.in.ogr',
+                             quiet = True,
+                             flags = 'f')
+    
+    return _parseFormats(ret), _parseFormats(ret, writableOnly = True)
+
+def _parseFormats(output, writableOnly = False):
+    """!Parse r.in.gdal/v.in.ogr -f output"""
+    formats = { 'file'     : list(),
+                'database' : list(),
+                'protocol' : list()
+                }
+    
+    if not output:
+        return formats
+    
+    patt = None
+    if writableOnly:
+        patt = re.compile('\(rw\+?\)$', re.IGNORECASE)
+    
+    for line in output.splitlines():
+        key, name = map(lambda x: x.strip(), line.strip().rsplit(':', -1))
+        
+        if writableOnly and not patt.search(key):
+            continue
+        
+        if name in ('Memory', 'Virtual Raster', 'In Memory Raster'):
+            continue
+        if name in ('PostgreSQL', 'SQLite',
+                    'ODBC', 'ESRI Personal GeoDatabase',
+                    'Rasterlite',
+                    'PostGIS WKT Raster driver'):
+            formats['database'].append(name)
+        elif name in ('GeoJSON',
+                      'OGC Web Coverage Service',
+                      'OGC Web Map Service',
+                      'HTTP Fetching Wrapper'):
+            formats['protocol'].append(name)
+        else:
+            formats['file'].append(name)
+    
+    for items in formats.itervalues():
+        items.sort()
+    
+    return formats
+
+formats = None
+
+def GetFormats(writableOnly = False):
+    """!Get GDAL/OGR formats"""
+    global formats
+    if not formats:
+        gdalAll, gdalWritable = _getGDALFormats()
+        ogrAll,  ogrWritable  = _getOGRFormats()
+        formats = {
+            'all' : {
+                'gdal' : gdalAll,
+                'ogr'  : ogrAll,
+                },
+            'writable' : {
+                'gdal' : gdalWritable,
+                'ogr'  : ogrWritable,
+                },
+            }
+    
+    if writableOnly:
+        return formats['writable']
+    
+    return formats['all']
+
+def GetSettingsPath():
+    """!Get full path to the settings directory
+    """
+    try:
+        verFd = open(os.path.join(ETCDIR, "VERSIONNUMBER"))
+        version = int(verFd.readlines()[0].split(' ')[0].split('.')[0])
+    except (IOError, ValueError, TypeError, IndexError), e:
+        sys.exit(_("ERROR: Unable to determine GRASS version. Details: %s") % e)
+    
+    verFd.close()
+
+    # keep location of settings files rc and wx in sync with lib/init/grass.py
+    if sys.platform == 'win32':
+        return os.path.join(os.getenv('APPDATA'), 'grass%d' % version)
+    
+    return os.path.join(os.getenv('HOME'), '.grass%d' % version)

Copied: grass/trunk/gui/wxpython/core/workspace.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/workspace.py)
===================================================================
--- grass/trunk/gui/wxpython/core/workspace.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/workspace.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1296 @@
+"""!
+ at package core.workspace
+
+ at brief Open/save workspace definition file
+
+Classes:
+ - ProcessWorkspaceFile
+ - WriteWorkspaceFile
+ - ProcessGrcFile
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+
+from core.utils    import normalize_whitespace
+from core.settings import UserSettings
+
+class ProcessWorkspaceFile:
+    def __init__(self, tree):
+        """!A ElementTree handler for the GXW XML file, as defined in
+        grass-gxw.dtd.
+        """
+        self.tree = tree
+        self.root = self.tree.getroot()
+        
+        #
+        # layer manager properties
+        #
+        self.layerManager = {}
+        self.layerManager['pos']  = None # window position
+        self.layerManager['size'] = None # window size
+        
+        #
+        # list of mapdisplays
+        #
+        self.displays = []
+        #
+        # list of map layers
+        #
+        self.layers = []
+        #
+        # nviz state
+        #
+        self.nviz_state = {}
+        
+        self.displayIndex = -1 # first display has index '0'
+        
+        self.__processFile()
+        
+        self.nvizDefault = Nviz()
+        
+    def __filterValue(self, value):
+        """!Filter value
+        
+        @param value
+        """
+        value = value.replace('&lt;', '<')
+        value = value.replace('&gt;', '>')
+        
+        return value
+
+    def __getNodeText(self, node, tag, default = ''):
+        """!Get node text"""
+        p = node.find(tag)
+        if p is not None:
+            return normalize_whitespace(p.text)
+        
+        return default
+    
+    def __processFile(self):
+        """!Process workspace file"""
+        #
+        # layer manager
+        #
+        node_lm = self.root.find('layer_manager')
+        if node_lm is not None:
+            posAttr = node_lm.get('dim', '')
+            if posAttr:
+                posVal = map(int, posAttr.split(','))
+                try:
+                    self.layerManager['pos']  = (posVal[0], posVal[1])
+                    self.layerManager['size'] = (posVal[2], posVal[3])
+                except:
+                    pass
+        
+        #
+        # displays
+        #
+        for display in self.root.findall('display'):
+            self.displayIndex += 1
+            
+            # window position and size
+            posAttr = display.get('dim', '')
+            if posAttr:
+                posVal = map(int, posAttr.split(','))
+                try:
+                    pos  = (posVal[0], posVal[1])
+                    size = (posVal[2], posVal[3])
+                except:
+                    pos  = None
+                    size = None
+            else:
+                pos  = None
+                size = None
+            
+            extentAttr = display.get('extent', '')
+            if extentAttr:
+                # w, s, e, n
+                extent = map(float, extentAttr.split(','))
+            else:
+                extent = None
+            
+            # projection
+            node_projection = display.find('projection')
+            if node_projection is not None:
+                projection = { 'enabled' : True,
+                               'epsg' : node_projection.get('epsg', ''),
+                               'proj' : self.__getNodeText(node_projection, 'value') }
+            else:
+                projection = { 'enabled' : False }
+            
+            self.displays.append( {
+                    "render"         : bool(int(display.get('render', "0"))),
+                    "mode"           : int(display.get('mode', 0)),
+                    "showCompExtent" : bool(int(display.get('showCompExtent', "0"))),
+                    "pos"            : pos,
+                    "size"           : size,
+                    "extent"         : extent,
+                    "alignExtent"    : bool(int(display.get('alignExtent', "0"))),
+                    "constrainRes"   : bool(int(display.get('constrainRes', "0"))),
+                    "projection"     : projection,
+                    "viewMode"       : display.get('viewMode', '2d')} )
+            
+            # process all layers/groups in the display
+            self.__processLayers(display)
+            # process nviz_state
+            self.__processNvizState(display)
+
+    def __processLayers(self, node, inGroup = -1):
+        """!Process layers/groups of selected display
+        
+        @param node display tree node
+        @param inGroup in group -> index of group item otherwise -1
+        """
+        for item in node.getchildren():
+            if item.tag == 'group':
+                # -> group
+                self.layers.append( {
+                        "type"    : 'group',
+                        "name"    : item.get('name', ''),
+                        "checked" : bool(int(item.get('checked', "0"))),
+                        "opacity" : None,
+                        "cmd"     : None,
+                        "group"   : inGroup,
+                        "display" : self.displayIndex,
+                        "vdigit"  : None,
+                        "nviz"    : None})
+                
+                self.__processLayers(item, inGroup = len(self.layers) - 1) # process items in group
+                
+            elif item.tag == 'layer':
+                cmd, selected, vdigit, nviz = self.__processLayer(item)
+                
+                self.layers.append( {
+                        "type"     : item.get('type', None),
+                        "name"     : item.get('name', None),
+                        "checked"  : bool(int(item.get('checked', "0"))),
+                        "opacity"  : float(item.get('opacity', '1.0')),
+                        "cmd"      : cmd,
+                        "group"    : inGroup,
+                        "display"  : self.displayIndex,
+                        "selected" : selected,
+                        "vdigit"   : vdigit,
+                        "nviz"     : nviz } )
+            
+    def __processLayer(self, layer):
+        """!Process layer item
+
+        @param layer tree node
+        """
+        cmd = list()
+        
+        #
+        # layer attributes (task) - 2D settings
+        #
+        node_task = layer.find('task')
+        cmd.append(node_task.get('name', "unknown"))
+        
+        # flags
+        for p in node_task.findall('flag'):
+            flag = p.get('name', '')
+            if len(flag) > 1:
+                cmd.append('--' + flag)
+            else:
+                cmd.append('-' + flag)
+        
+        # parameters
+        for p in node_task.findall('parameter'):
+            cmd.append('%s=%s' % (p.get('name', ''),
+                                  self.__filterValue(self.__getNodeText(p, 'value'))))
+        
+        if layer.find('selected') is not None:
+            selected = True
+        else:
+            selected = False
+        
+        #
+        # Vector digitizer settings
+        #
+        node_vdigit = layer.find('vdigit')
+        if node_vdigit is not None:
+            vdigit = self.__processLayerVdigit(node_vdigit)
+        else:
+            vdigit = None
+        
+        #
+        # Nviz (3D settings)
+        #
+        node_nviz = layer.find('nviz')
+        if node_nviz is not None:
+            nviz = self.__processLayerNviz(node_nviz)
+        else:
+            nviz = None
+        
+        return (cmd, selected, vdigit, nviz)
+
+    def __processLayerVdigit(self, node_vdigit):
+        """!Process vector digitizer layer settings
+
+        @param node_vdigit vdigit node
+        """
+        # init nviz layer properties
+        vdigit = dict()
+        for node in node_vdigit.findall('geometryAttribute'):
+            if 'geomAttr' not in vdigit:
+                vdigit['geomAttr'] = dict()
+            type = node.get('type')
+            vdigit['geomAttr'][type] = dict()
+            vdigit['geomAttr'][type]['column'] = node.get('column') # required
+            # default map units
+            vdigit['geomAttr'][type]['units'] = node.get('units', 'mu')
+        
+        return vdigit
+    
+    def __processLayerNviz(self, node_nviz):
+        """!Process 3D layer settings
+
+        @param node_nviz nviz node
+        """
+        # init nviz layer properties
+        nviz = {}
+        if node_nviz.find('surface') is not None: # -> raster
+            nviz['surface'] = {}
+            for sec in ('attribute', 'draw', 'mask', 'position'):
+                nviz['surface'][sec] = {}
+        elif node_nviz.find('vlines') is not None or \
+                node_nviz.find('vpoints') is not None: # -> vector
+            nviz['vector'] = {}
+            for sec in ('lines', 'points'):
+                nviz['vector'][sec] = {}
+        
+        if 'surface' in nviz:
+            node_surface = node_nviz.find('surface')
+            # attributes
+            for attrb in node_surface.findall('attribute'):
+                tagName = str(attrb.tag)
+                attrbName = attrb.get('name', '')
+                dc = nviz['surface'][tagName][attrbName] = {}
+                if attrb.get('map', '0') == '0':
+                    dc['map'] = False
+                else:
+                    dc['map'] = True
+                value = self.__getNodeText(attrb, 'value')
+                try:
+                    dc['value'] = int(value)
+                except ValueError:
+                    try:
+                        dc['value'] = float(value)
+                    except ValueError:
+                        dc['value'] = str(value)
+            
+            # draw
+            node_draw = node_surface.find('draw')
+            if node_draw is not None:
+                tagName = str(node_draw.tag)
+                nviz['surface'][tagName]['all'] = False
+                nviz['surface'][tagName]['mode'] = {}
+                nviz['surface'][tagName]['mode']['value'] = -1 # to be calculated
+                nviz['surface'][tagName]['mode']['desc'] = {}
+                nviz['surface'][tagName]['mode']['desc']['shading'] = \
+                    str(node_draw.get('shading', ''))
+                nviz['surface'][tagName]['mode']['desc']['style'] = \
+                    str(node_draw.get('style', ''))
+                nviz['surface'][tagName]['mode']['desc']['mode'] = \
+                    str(node_draw.get('mode', ''))
+                
+                # resolution
+                for node_res in node_draw.findall('resolution'):
+                    resType = str(node_res.get('type', ''))
+                    if 'resolution' not in nviz['surface']['draw']:
+                        nviz['surface']['draw']['resolution'] = {}
+                    value = int(self.__getNodeText(node_res, 'value'))
+                    nviz['surface']['draw']['resolution'][resType] = value
+                
+                # wire-color
+                node_wire_color = node_draw.find('wire_color')
+                if node_wire_color is not None:
+                    nviz['surface']['draw']['wire-color'] = {}
+                    value = str(self.__getNodeText(node_wire_color, 'value'))
+                    nviz['surface']['draw']['wire-color']['value'] = value
+                
+            # position
+            node_pos = node_surface.find('position')
+            if node_pos is not None:
+                dc = nviz['surface']['position'] = {}
+                for coor in ['x', 'y', 'z']:
+                    node = node_pos.find(coor)
+                    if node is None:
+                        continue
+                    value = int(self.__getNodeText(node_pos, coor))
+                    dc[coor] = value
+            
+        elif 'vector' in nviz:
+            # vpoints
+            node_vpoints = node_nviz.find('vpoints')
+            if node_vpoints is not None:
+                marker = str(node_vpoints.get('marker', ''))
+                markerId = list(UserSettings.Get(group='nviz', key='vector',
+                                                 subkey=['points', 'marker'], internal=True)).index(marker)
+                nviz['vector']['points']['marker'] = { 'value' : markerId }
+                
+                node_mode = node_vpoints.find('mode')
+                if node_mode is not None:
+                    nviz['vector']['points']['mode'] = {}
+                    nviz['vector']['points']['mode']['type'] = str(node_mode.get('type', 'surface'))
+                    nviz['vector']['points']['mode']['surface'] = {}
+                    nviz['vector']['points']['mode']['surface']['value'] = []
+                    nviz['vector']['points']['mode']['surface']['show'] = []
+                    
+                    # map
+                    for node_map in node_mode.findall('map'):
+                        nviz['vector']['points']['mode']['surface']['value'].append(
+                            self.__processLayerNvizNode(node_map, 'name', str))
+                        nviz['vector']['points']['mode']['surface']['show'].append(bool(
+                            self.__processLayerNvizNode(node_map, 'checked', int)))
+                
+                # color
+                self.__processLayerNvizNode(node_vpoints, 'color', str,
+                                            nviz['vector']['points'])
+                
+                # width
+                self.__processLayerNvizNode(node_vpoints, 'width', int,
+                                            nviz['vector']['points'])
+                
+                # height
+                self.__processLayerNvizNode(node_vpoints, 'height', int,
+                                            nviz['vector']['points'])
+                
+                # height
+                self.__processLayerNvizNode(node_vpoints, 'size', int,
+                                            nviz['vector']['points'])
+                
+                # thematic
+                node_thematic = node_vpoints.find('thematic')
+                thematic = nviz['vector']['points']['thematic'] = {}
+                thematic['rgbcolumn'] = self.__processLayerNvizNode(node_thematic, 'rgbcolumn', str)
+                thematic['sizecolumn'] = self.__processLayerNvizNode(node_thematic, 'sizecolumn', str)
+                for col in ('rgbcolumn', 'sizecolumn'):
+                    if thematic[col] == 'None':
+                        thematic[col] = None
+                thematic['layer'] = self.__processLayerNvizNode(node_thematic, 'layer', int)
+                for use in ('usecolor', 'usesize', 'usewidth'):
+                    if node_thematic.get(use, ''):
+                        thematic[use] = int(node_thematic.get(use, '0'))
+                
+            # vlines
+            node_vlines = node_nviz.find('vlines')
+            if node_vlines is not None:
+                node_mode = node_vlines.find('mode')
+                if node_mode is not None:
+                    nviz['vector']['lines']['mode'] = {}
+                    nviz['vector']['lines']['mode']['type'] = str(node_mode.get('type', ''))
+                    nviz['vector']['lines']['mode']['surface'] = {}
+                    nviz['vector']['lines']['mode']['surface']['value'] = []
+                    nviz['vector']['lines']['mode']['surface']['show'] = []
+                    
+                    # map
+                    for node_map in node_mode.findall('map'):
+                        nviz['vector']['lines']['mode']['surface']['value'].append(
+                            self.__processLayerNvizNode(node_map, 'name', str))
+                        nviz['vector']['lines']['mode']['surface']['show'].append(bool(
+                            self.__processLayerNvizNode(node_map, 'checked', int)))
+                
+                # color
+                self.__processLayerNvizNode(node_vlines, 'color', str,
+                                            nviz['vector']['lines'])
+                
+                # width
+                self.__processLayerNvizNode(node_vlines, 'width', int,
+                                            nviz['vector']['lines'])
+                
+                # height
+                self.__processLayerNvizNode(node_vlines, 'height', int,
+                                            nviz['vector']['lines'])
+                
+                # thematic
+                node_thematic = node_vlines.find('thematic')
+                thematic = nviz['vector']['lines']['thematic'] = {}
+                thematic['rgbcolumn'] = self.__processLayerNvizNode(node_thematic, 'rgbcolumn', str)
+                thematic['sizecolumn'] = self.__processLayerNvizNode(node_thematic, 'sizecolumn', str)
+                for col in ('rgbcolumn', 'sizecolumn'):
+                    if thematic[col] == 'None':
+                        thematic[col] = None
+                thematic['layer'] = self.__processLayerNvizNode(node_thematic, 'layer', int)
+                for use in ('usecolor', 'usesize', 'usewidth'):
+                    if node_thematic.get(use, ''):
+                        thematic[use] = int(node_thematic.get(use, '0'))
+            
+        return nviz
+    
+    def __processLayerNvizNode(self, node, tag, cast, dc = None):
+        """!Process given tag nviz/vector"""
+        node_tag = node.find(tag)
+        if node_tag is not None:
+            if node_tag.find('value') is not None:
+                value = cast(self.__getNodeText(node_tag, 'value'))
+            else:
+                try:
+                    value = cast(node_tag.text)
+                except ValueError:
+                    if cast == str:
+                        value = ''
+                    else:
+                        value = None
+            if dc:
+                dc[tag] = dict()
+                dc[tag]['value'] = value
+            else:
+                return value
+    
+    def __processNvizState(self, node):
+        """!Process tag nviz_state"""
+        node_state = node.find('nviz_state')
+        if node_state is None:
+            return
+        self.nviz_state['display'] = self.displayIndex
+        #
+        # view
+        #
+        node_view = node_state.find('view')
+        view = {}
+        iview = {}
+        
+        node_position = node_view.find('v_position')
+        view['position'] = {}
+        view['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
+        view['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
+        node_persp = node_view.find('persp')
+        view['persp'] = {}
+        iview['persp'] = {}
+        view['persp']['value'] = self.__processLayerNvizNode(node_persp, 'value', int)
+        view['persp']['step'] = self.__processLayerNvizNode(node_persp, 'step', int)
+        iview['persp']['min'] = self.__processLayerNvizNode(node_persp, 'min', int)
+        iview['persp']['max'] = self.__processLayerNvizNode(node_persp, 'max', int)
+        node_height = node_view.find('v_height')
+        iview['height'] = {}
+        iview['height']['value'] = self.__processLayerNvizNode(node_height, 'value', int)
+        iview['height']['min'] = self.__processLayerNvizNode(node_height, 'min', int)
+        iview['height']['max'] = self.__processLayerNvizNode(node_height, 'max', int)
+        node_twist = node_view.find('twist')
+        view['twist'] = {}
+        iview['twist'] = {}
+        view['twist']['value'] = self.__processLayerNvizNode(node_twist, 'value', int)
+        iview['twist']['min'] = self.__processLayerNvizNode(node_twist, 'min', int)
+        iview['twist']['max'] = self.__processLayerNvizNode(node_twist, 'max', int)
+        node_zexag = node_view.find('z-exag')
+        view['z-exag'] = {}
+        iview['z-exag'] = {}
+        view['z-exag']['value'] = self.__processLayerNvizNode(node_zexag, 'value', int)
+        view['z-exag']['min'] = self.__processLayerNvizNode(node_zexag, 'min', int)
+        view['z-exag']['max'] = self.__processLayerNvizNode(node_zexag, 'max', int)
+        iview['z-exag']['original'] = self.__processLayerNvizNode(node_zexag, 'original', float)
+        node_focus = node_view.find('focus')
+        iview['focus'] = {}
+        iview['focus']['x'] = self.__processLayerNvizNode(node_focus, 'x', int)
+        iview['focus']['y'] = self.__processLayerNvizNode(node_focus, 'y', int)
+        iview['focus']['z'] = self.__processLayerNvizNode(node_focus, 'z', int)
+        node_dir = node_view.find('dir')
+        if node_dir:
+            iview['dir'] = {}
+            iview['dir']['x'] = self.__processLayerNvizNode(node_dir, 'x', int)
+            iview['dir']['y'] = self.__processLayerNvizNode(node_dir, 'y', int)
+            iview['dir']['z'] = self.__processLayerNvizNode(node_dir, 'z', int)
+            iview['dir']['use'] = True
+        else:
+            iview['dir'] = {}
+            iview['dir']['x'] = -1
+            iview['dir']['y'] = -1
+            iview['dir']['z'] = -1
+            iview['dir']['use'] = False
+        
+        view['background'] = {}
+        color = self.__processLayerNvizNode(node_view, 'background_color', str)
+        view['background']['color'] = tuple(map(int, color.split(':')))
+        
+        self.nviz_state['view'] = view
+        self.nviz_state['iview'] = iview
+        #
+        # light
+        #
+        node_light = node_state.find('light')
+        light = {}
+        
+        node_position = node_light.find('l_position')
+        light['position'] = {}
+        light['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
+        light['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
+        light['position']['z'] = self.__processLayerNvizNode(node_position, 'z', int)
+        
+        light['bright'] = self.__processLayerNvizNode(node_light, 'bright', int) 
+        light['ambient'] = self.__processLayerNvizNode(node_light, 'ambient', int)
+        color = self.__processLayerNvizNode(node_light, 'color', str)
+        light['color'] = tuple(map(int, color.split(':')))
+        
+        self.nviz_state['light'] = light
+        
+        node_constants = node_state.find('constant_planes')
+        constants = []
+        if node_constants:
+            for i, node_plane in enumerate(node_constants.findall('plane')):
+                plane = {}
+                plane['color'] = self.__processLayerNvizNode(node_plane, 'color', str)                
+                plane['resolution'] = self.__processLayerNvizNode(node_plane, 'fine_resolution', int)
+                plane['value'] = self.__processLayerNvizNode(node_plane, 'height', int)
+                plane['object'] = {}
+                constants.append({'constant': plane})
+        self.nviz_state['constants'] = constants    
+
+class WriteWorkspaceFile(object):
+    """!Generic class for writing workspace file"""
+    def __init__(self, lmgr, file):
+        self.file =  file
+        self.lmgr = lmgr
+        self.indent = 0
+        
+        # write header
+        self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+        self.file.write('<!DOCTYPE gxw SYSTEM "grass-gxw.dtd">\n')
+        self.file.write('%s<gxw>\n' % (' ' * self.indent))
+        
+        self.indent =+ 4
+        
+        # layer manager
+        windowPos = self.lmgr.GetPosition()
+        windowSize = self.lmgr.GetSize()
+        file.write('%s<layer_manager dim="%d,%d,%d,%d">\n' % (' ' * self.indent,
+                                                              windowPos[0],
+                                                              windowPos[1],
+                                                              windowSize[0],
+                                                              windowSize[1]
+                                                              ))
+        
+        file.write('%s</layer_manager>\n' % (' ' * self.indent))
+        
+        # list of displays
+        for page in range(0, self.lmgr.gm_cb.GetPageCount()):
+            mapTree = self.lmgr.gm_cb.GetPage(page).maptree
+            region = mapTree.Map.region
+            
+            displayPos = mapTree.mapdisplay.GetPosition()
+            displaySize = mapTree.mapdisplay.GetSize()
+            if mapTree.mapdisplay.toolbars['map'].combo.GetSelection() == 1:
+                viewmode = '3d'
+            else:
+                viewmode = '2d'
+            
+            file.write('%s<display render="%d" '
+                       'mode="%d" showCompExtent="%d" '
+                       'alignExtent="%d" '
+                       'constrainRes="%d" '
+                       'dim="%d,%d,%d,%d" '
+                       'extent="%f,%f,%f,%f" '
+                       'viewMode="%s" >\n' % (' ' * self.indent,
+                                              int(mapTree.mapdisplay.GetProperty('render')),
+                                              mapTree.mapdisplay.statusbarManager.GetMode(),
+                                              int(mapTree.mapdisplay.GetProperty('region')),
+                                              int(mapTree.mapdisplay.GetProperty('alignExtent')),
+                                              int(mapTree.mapdisplay.GetProperty('resolution')),
+                                              displayPos[0],
+                                              displayPos[1],
+                                              displaySize[0],
+                                              displaySize[1],
+                                              region['w'],
+                                              region['s'],
+                                              region['e'],
+                                              region['n'],
+                                              viewmode
+                                              ))
+            # projection statusbar info
+            if mapTree.mapdisplay.GetProperty('projection') and \
+                    UserSettings.Get(group='display', key='projection', subkey='proj4'):
+                self.indent += 4
+                file.write('%s<projection' % (' ' * self.indent))
+                epsg = UserSettings.Get(group='display', key='projection', subkey='epsg')
+                if epsg:
+                    file.write(' epsg="%s"' % epsg)
+                file.write('>\n')
+                proj = UserSettings.Get(group='display', key='projection', subkey='proj4')
+                self.indent += 4 
+                file.write('%s<value>%s</value>\n' % (' ' * self.indent, proj))
+                self.indent -= 4
+                file.write('%s</projection>\n' % (' ' * self.indent))
+                self.indent -= 4
+            
+            # list of layers
+            item = mapTree.GetFirstChild(mapTree.root)[0]
+            self.__writeLayer(mapTree, item)
+            
+            if mapTree.mapdisplay.MapWindow3D is not None:
+                nvizDisp = mapTree.mapdisplay.MapWindow3D
+                self.__writeNvizState(view = nvizDisp.view, iview =  nvizDisp.iview, 
+                                      light = nvizDisp.light, constants = nvizDisp.constants)
+            
+            file.write('%s</display>\n' % (' ' * self.indent))
+        
+        self.indent =- 4
+        file.write('%s</gxw>\n' % (' ' * self.indent))
+
+    def __filterValue(self, value):
+        """!Make value XML-valid"""
+        value = value.replace('<', '&lt;')
+        value = value.replace('>', '&gt;')
+        
+        return value
+    
+    def __writeLayer(self, mapTree, item):
+        """!Write bunch of layers to GRASS Workspace XML file"""
+        self.indent += 4
+        itemSelected = mapTree.GetSelections()
+        while item and item.IsOk():
+            type = mapTree.GetPyData(item)[0]['type']
+            if type != 'group':
+                maplayer = mapTree.GetPyData(item)[0]['maplayer']
+            else:
+                maplayer = None
+
+            checked = int(item.IsChecked())
+            if type == 'command':
+                cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string=True)
+                self.file.write('%s<layer type="%s" name="%s" checked="%d">\n' % \
+                               (' ' * self.indent, type, cmd, checked));
+                self.file.write('%s</layer>\n' % (' ' * self.indent));
+            elif type == 'group':
+                name = mapTree.GetItemText(item)
+                self.file.write('%s<group name="%s" checked="%d">\n' % \
+                               (' ' * self.indent, name.encode('utf8'), checked));
+                self.indent += 4
+                subItem = mapTree.GetFirstChild(item)[0]
+                self.__writeLayer(mapTree, subItem)
+                self.indent -= 4
+                self.file.write('%s</group>\n' % (' ' * self.indent));
+            else:
+                cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string=False)
+                name = mapTree.GetItemText(item)
+                opacity = maplayer.GetOpacity(float = True)
+                # remove 'opacity' part
+                if opacity < 1:
+                    name = name.split('(', -1)[0].strip()
+                self.file.write('%s<layer type="%s" name="%s" checked="%d" opacity="%f">\n' % \
+                                    (' ' * self.indent, type, name.encode('utf8'), checked, opacity));
+                
+                self.indent += 4
+                # selected ?
+                if item in itemSelected:
+                    self.file.write('%s<selected />\n' % (' ' * self.indent))
+                # layer properties
+                self.file.write('%s<task name="%s">\n' % (' ' * self.indent, cmd[0]))
+                self.indent += 4
+                for key, val in cmd[1].iteritems():
+                    if key == 'flags':
+                        for f in val:
+                            self.file.write('%s<flag name="%s" />\n' %
+                                            (' ' * self.indent, f))
+                    elif val in (True, False):
+                        self.file.write('%s<flag name="%s" />\n' %
+                                        (' ' * self.indent, key))
+                    else: # parameter
+                        self.file.write('%s<parameter name="%s">\n' %
+                                        (' ' * self.indent, key))
+                        self.indent += 4
+                        self.file.write('%s<value>%s</value>\n' %
+                                        (' ' * self.indent, self.__filterValue(val)))
+                        self.indent -= 4
+                        self.file.write('%s</parameter>\n' % (' ' * self.indent));
+                self.indent -= 4
+                self.file.write('%s</task>\n' % (' ' * self.indent));
+                # vector digitizer
+                vdigit = mapTree.GetPyData(item)[0]['vdigit']
+                if vdigit:
+                    self.file.write('%s<vdigit>\n' % (' ' * self.indent))
+                    if 'geomAttr' in vdigit:
+                        self.indent += 4
+                        for type, val in vdigit['geomAttr'].iteritems():
+                            units = ''
+                            if val['units'] != 'mu':
+                                units = ' units="%s"' % val['units']
+                            self.file.write('%s<geometryAttribute type="%s" column="%s"%s />\n' % \
+                                                (' ' * self.indent, type, val['column'], units))
+                        self.indent -= 4
+                    self.file.write('%s</vdigit>\n' % (' ' * self.indent))
+                # nviz
+                nviz = mapTree.GetPyData(item)[0]['nviz']
+                if nviz:
+                    self.file.write('%s<nviz>\n' % (' ' * self.indent))
+                    if maplayer.type == 'raster':
+                        self.__writeNvizSurface(nviz['surface'])
+                    elif maplayer.type == 'vector':
+                        self.__writeNvizVector(nviz['vector'])
+                    self.file.write('%s</nviz>\n' % (' ' * self.indent))
+                self.indent -= 4
+                self.file.write('%s</layer>\n' % (' ' * self.indent))
+            item = mapTree.GetNextSibling(item)
+        self.indent -= 4
+        
+    def __writeNvizSurface(self, data):
+        """!Save Nviz raster layer properties to workspace
+
+        @param data Nviz layer properties
+        """
+        if 'object' not in data: # skip disabled
+            return
+        self.indent += 4
+        self.file.write('%s<surface>\n' % (' ' * self.indent))
+        self.indent += 4
+        for attrb in data.iterkeys():
+            if len(data[attrb]) < 1: # skip empty attributes
+                continue
+            if attrb == 'object':
+                continue
+            
+            for name in data[attrb].iterkeys():
+                # surface attribute
+                if attrb == 'attribute':
+                    self.file.write('%s<%s name="%s" map="%d">\n' % \
+                                   (' ' * self.indent, attrb, name, data[attrb][name]['map']))
+                    self.indent += 4
+                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
+                    self.indent -= 4
+                    # end tag
+                    self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
+
+            # draw mode
+            if attrb == 'draw':
+                self.file.write('%s<%s' %(' ' * self.indent, attrb))
+                if 'mode' in data[attrb]:
+                    for tag, value in data[attrb]['mode']['desc'].iteritems():
+                        self.file.write(' %s="%s"' % (tag, value))
+                self.file.write('>\n') # <draw ...>
+
+                if 'resolution' in data[attrb]:
+                    self.indent += 4
+                    for type in ('coarse', 'fine'):
+                        self.file.write('%s<resolution type="%s">\n' % (' ' * self.indent, type))
+                        self.indent += 4
+                        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent,
+                                                                   data[attrb]['resolution'][type]))
+                        self.indent -= 4
+                        self.file.write('%s</resolution>\n' % (' ' * self.indent))
+
+                if 'wire-color' in data[attrb]:
+                    self.file.write('%s<wire_color>\n' % (' ' * self.indent))
+                    self.indent += 4
+                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent,
+                                                               data[attrb]['wire-color']['value']))
+                    self.indent -= 4
+                    self.file.write('%s</wire_color>\n' % (' ' * self.indent))
+                self.indent -= 4
+            
+            # position
+            elif attrb == 'position':
+                self.file.write('%s<%s>\n' %(' ' * self.indent, attrb))
+                i = 0
+                for tag in ('x', 'y', 'z'):
+                    self.indent += 4
+                    self.file.write('%s<%s>%d</%s>\n' % (' ' * self.indent, tag,
+                                                        data[attrb][tag], tag))
+                    i += 1
+                    self.indent -= 4
+
+            if attrb != 'attribute':
+                # end tag
+                self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
+
+        self.indent -= 4
+        self.file.write('%s</surface>\n' % (' ' * self.indent))
+        self.indent -= 4
+
+    def __writeNvizVector(self, data):
+        """!Save Nviz vector layer properties (lines/points) to workspace
+
+        @param data Nviz layer properties
+        """
+        self.indent += 4
+        for attrb in data.iterkeys():
+            if len(data[attrb]) < 1: # skip empty attributes
+                continue
+
+            if 'object' not in data[attrb]: # skip disabled
+                continue
+            if attrb == 'lines':
+                self.file.write('%s<v%s>\n' % (' ' * self.indent, attrb))
+            elif attrb == 'points':
+                markerId = data[attrb]['marker']['value']
+                marker = UserSettings.Get(group = 'nviz', key = 'vector',
+                                          subkey = ['points', 'marker'], internal = True)[markerId]
+                self.file.write('%s<v%s marker="%s">\n' % (' ' * self.indent,
+                                                           attrb,
+                                                           marker))
+            self.indent += 4
+            for name in data[attrb].iterkeys():
+                if name in ('object', 'marker'):
+                    continue
+                if name == 'mode':
+                    self.file.write('%s<%s type="%s">\n' % (' ' * self.indent, name,
+                                                          data[attrb][name]['type']))
+                    if data[attrb][name]['type'] == 'surface':
+                        self.indent += 4
+                        for idx, surface in enumerate(data[attrb][name]['surface']['value']):
+                            checked = data[attrb][name]['surface']['show'][idx]
+                            self.file.write('%s<map>\n' % (' ' * self.indent))
+                            self.indent += 4
+                            self.file.write('%s<name>%s</name>\n' % (' ' * self.indent, surface))
+                            self.file.write('%s<checked>%s</checked>\n' % (' ' * self.indent, int(checked)))
+                            self.indent -= 4
+                            self.file.write('%s</map>\n' % (' ' * self.indent))
+                        self.indent -= 4
+                    self.file.write('%s</%s>\n' % ((' ' * self.indent, name)))
+                elif name == 'thematic':
+                    self.file.write('%s<%s ' % (' ' * self.indent, name))
+                    for key in data[attrb][name].iterkeys():
+                        if key.startswith('use'):
+                            self.file.write('%s="%s" ' % (key, int(data[attrb][name][key])))
+                    self.file.write('>\n')
+                    self.indent += 4
+                    for key, value in data[attrb][name].iteritems():
+                        if key.startswith('use'):
+                            continue
+                        if value is None:
+                            value = ''
+                        self.file.write('%s<%s>%s</%s>\n' % (' ' * self.indent, key, value, key))
+                    self.indent -= 4
+                    self.file.write('%s</%s>\n' % (' ' * self.indent, name))
+                else:
+                    self.file.write('%s<%s>\n' % (' ' * self.indent, name))
+                    self.indent += 4
+                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
+                    self.indent -= 4
+                    self.file.write('%s</%s>\n' % (' ' * self.indent, name))
+            self.indent -= 4
+            self.file.write('%s</v%s>\n' % (' ' * self.indent, attrb))
+
+        self.indent -= 4
+
+    def __writeNvizState(self, view, iview, light, constants):
+        """"!Save Nviz properties (view, light) to workspace
+
+        @param view Nviz view properties
+        @param iview Nviz internal view properties
+        @param light Nviz light properties
+        """
+        self.indent += 4
+        self.file.write('%s<nviz_state>\n' % (' ' * self.indent))
+        #
+        # view
+        #
+        self.indent += 4
+        self.file.write('%s<view>\n' % (' ' * self.indent))
+        self.indent += 4
+        # position
+        self.file.write('%s<v_position>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, view['position']['x']))
+        self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, view['position']['y']))
+        self.indent -= 4
+        self.file.write('%s</v_position>\n' % (' ' * self.indent))
+        # perspective
+        self.file.write('%s<persp>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['persp']['value']))
+        self.file.write('%s<step>%d</step>\n' % (' ' * self.indent, view['persp']['step']))
+        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['persp']['min']))
+        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['persp']['max']))
+        self.indent -= 4
+        self.file.write('%s</persp>\n' % (' ' * self.indent))
+        # height
+        self.file.write('%s<v_height>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, iview['height']['value']))
+        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['height']['min']))
+        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['height']['max']))
+        self.indent -= 4
+        self.file.write('%s</v_height>\n' % (' ' * self.indent))
+        # twist
+        self.file.write('%s<twist>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['twist']['value']))
+        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['twist']['min']))
+        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['twist']['max']))
+        self.indent -= 4
+        self.file.write('%s</twist>\n' % (' ' * self.indent))
+        # z-exag
+        self.file.write('%s<z-exag>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['z-exag']['value']))
+        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, view['z-exag']['min']))
+        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, view['z-exag']['max']))
+        self.file.write('%s<original>%d</original>\n' % (' ' * self.indent, iview['z-exag']['original']))
+        self.indent -= 4
+        self.file.write('%s</z-exag>\n' % (' ' * self.indent))
+        # focus (look here)
+        self.file.write('%s<focus>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<x>%d</x>\n' % (' ' * self.indent, iview['focus']['x']))
+        self.file.write('%s<y>%d</y>\n' % (' ' * self.indent, iview['focus']['y']))
+        self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, iview['focus']['z']))
+        self.indent -= 4
+        self.file.write('%s</focus>\n' % (' ' * self.indent))
+        # background
+        self.__writeTagWithValue('background_color', view['background']['color'][:3], format = 'd:%d:%d')
+        
+        self.indent -= 4
+        self.file.write('%s</view>\n' % (' ' * self.indent))
+        #
+        # light
+        #
+        self.file.write('%s<light>\n' % (' ' * self.indent))
+        self.indent += 4
+        # position
+        self.file.write('%s<l_position>\n' % (' ' * self.indent))
+        self.indent += 4
+        self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, light['position']['x']))
+        self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, light['position']['y']))
+        self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, light['position']['z']))
+        self.indent -= 4
+        self.file.write('%s</l_position>\n' % (' ' * self.indent))
+        # bright
+        self.__writeTagWithValue('bright', light['bright'])
+        # ambient
+        self.__writeTagWithValue('ambient', light['ambient'])
+        # color
+        self.__writeTagWithValue('color', light['color'][:3], format = 'd:%d:%d')
+        
+        self.indent -= 4
+        self.file.write('%s</light>\n' % (' ' * self.indent))
+        #
+        # constant planes
+        #
+        if constants:
+            self.file.write('%s<constant_planes>\n' % (' ' * self.indent))
+            self.indent += 4
+            for idx, plane in enumerate(constants):
+                self.file.write('%s<plane>\n' % (' ' * self.indent))
+                self.indent += 4
+                self.__writeTagWithValue('height', constants[idx]['constant']['value'])
+                self.__writeTagWithValue('fine_resolution', constants[idx]['constant']['resolution'])
+                self.__writeTagWithValue('color', constants[idx]['constant']['color'], format = 's')
+                self.indent -= 4
+                self.file.write('%s</plane>\n' % (' ' * self.indent))
+            self.indent -= 4
+            self.file.write('%s</constant_planes>\n' % (' ' * self.indent))
+        self.indent -= 4
+        
+        self.file.write('%s</nviz_state>\n' % (' ' * self.indent))
+        self.indent -= 4
+    
+    def __writeTagWithValue(self, tag, data, format = 'd'):
+        """!Helper function for writing pair tag
+        
+        @param tag written tag
+        @param data written data
+        @param format conversion type
+        """
+        self.file.write('%s<%s>\n' % (' ' * self.indent, tag))
+        self.indent += 4
+        self.file.write('%s' % (' ' * self.indent))
+        self.file.write(('<value>%' + format + '</value>\n') % data)
+        self.indent -= 4
+        self.file.write('%s</%s>\n' % (' ' * self.indent, tag))
+        
+class ProcessGrcFile(object):
+    def __init__(self, filename):
+        """!Process GRC file"""
+        self.filename = filename
+
+        # elements
+        self.inGroup = False
+        self.inRaster = False
+        self.inVector = False
+
+        # list of layers
+        self.layers = []
+
+        # error message
+        self.error = ''
+        self.num_error = 0
+
+    def read(self, parent):
+        """!Read GRC file
+
+        @param parent parent window
+
+        @return list of map layers
+        """
+        try:
+            file = open(self.filename, "r")
+        except IOError:
+            wx.MessageBox(parent=parent,
+                          message=_("Unable to open file <%s> for reading.") % self.filename,
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
+            return []
+
+        line_id = 1
+        for line in file.readlines():
+            self.process_line(line.rstrip('\n'), line_id)
+            line_id +=1
+
+        file.close()
+
+        if self.num_error > 0:
+            wx.MessageBox(parent=parent,
+                          message=_("Some lines were skipped when reading settings "
+                                    "from file <%(file)s>.\nSee 'Command output' window for details.\n\n"
+                                    "Number of skipped lines: %(line)d") % \
+                                        { 'file' : self.filename, 'line' : self.num_error },
+                          caption=_("Warning"), style=wx.OK | wx.ICON_EXCLAMATION)
+            parent.goutput.WriteLog('Map layers loaded from GRC file <%s>' % self.filename)
+            parent.goutput.WriteLog('Skipped lines:\n%s' % self.error)
+
+        return self.layers
+
+    def process_line(self, line, line_id):
+        """!Process line definition"""
+        element = self._get_element(line)
+        if element == 'Group':
+            self.groupName = self._get_value(line)
+            self.layers.append({
+                    "type"    : 'group',
+                    "name"    : self.groupName,
+                    "checked" : None,
+                    "opacity" : None,
+                    "cmd"     : None,
+                    "group"   : self.inGroup,
+                    "display" : 0 })
+            self.inGroup = True
+
+        elif element == '_check':
+            if int(self._get_value(line)) ==  1:
+                self.layers[-1]['checked'] = True
+            else:
+                self.layers[-1]['checked'] = False
+            
+        elif element == 'End':
+            if self.inRaster:
+                self.inRaster = False
+            elif self.inVector:
+                self.inVector = False
+            elif self.inGroup:
+                self.inGroup = False
+            elif self.inGridline:
+                self.inGridline = False
+        
+        elif element == 'opacity':
+            self.layers[-1]['opacity'] = float(self._get_value(line))
+
+        # raster
+        elif element == 'Raster':
+            self.inRaster = True
+            self.layers.append({
+                    "type"    : 'raster',
+                    "name"    : self._get_value(line),
+                    "checked" : None,
+                    "opacity" : None,
+                    "cmd"     : ['d.rast'],
+                    "group"   : self.inGroup,
+                    "display" : 0})
+
+        elif element == 'map' and self.inRaster:
+            self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
+            
+        elif element == 'overlay' and self.inRaster:
+            if int(self._get_value(line)) == 1:
+                self.layers[-1]['cmd'].append('-o')
+            
+        elif element == 'rastquery' and self.inRaster:
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('catlist=%s' % value)
+            
+        elif element == 'bkcolor' and self.inRaster:
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('bg=%s' % value)
+
+        # vector
+        elif element == 'Vector':
+            self.inVector = True
+            self.layers.append({
+                    "type"    : 'vector',
+                    "name"    : self._get_value(line),
+                    "checked" : None,
+                    "opacity" : None,
+                    "cmd"     : ['d.vect'],
+                    "group"   : self.inGroup,
+                    "display" : 0})
+
+        elif element == 'vect' and self.inVector:
+            self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
+                
+        elif element in ('display_shape',
+                         'display_cat',
+                         'display_topo',
+                         'display_dir',
+                         'display_attr',
+                         'type_point',
+                         'type_line',
+                         'type_boundary',
+                         'type_centroid',
+                         'type_area',
+                         'type_face') and self.inVector:
+            
+            if int(self._get_value(line)) == 1:
+                name = element.split('_')[0]
+                type = element.split('_')[1]
+                paramId = self._get_cmd_param_index(self.layers[-1]['cmd'], name)
+                if paramId == -1:
+                    self.layers[-1]['cmd'].append('%s=%s' % (name, type))
+                else:
+                    self.layers[-1]['cmd'][paramId] += ',%s' % type
+
+        elif element in ('color',
+                         'fcolor',
+                         'lcolor') and self.inVector:
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('%s=%s' % (element,
+                                                         self._color_name_to_rgb(value)))
+
+        elif element == 'rdmcolor' and self.inVector:
+            if int(self._get_value(line)) == 1:
+                self.layers[-1]['cmd'].append('-c')
+
+        elif element == 'sqlcolor' and self.inVector:
+            if int(self._get_value(line)) == 1:
+                self.layers[-1]['cmd'].append('-a')
+
+        elif element in ('icon',
+                         'size',
+                         'layer',
+                         'xref',
+                         'yref',
+                         'lsize',
+                         'where',
+                         'minreg',
+                         'maxreg') and self.inVector:
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('%s=%s' % (element,
+                                                         value))
+        
+        elif element == 'lwidth':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('width=%s' % value)
+
+        elif element == 'lfield':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('llayer=%s' % value)
+                                        
+        elif element == 'attribute':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('attrcol=%s' % value)
+
+        elif element == 'cat':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('cats=%s' % value)
+
+        # gridline
+        elif element == 'gridline':
+            self.inGridline = True
+            self.layers.append({
+                    "type"    : 'grid',
+                    "name"    : self._get_value(line),
+                    "checked" : None,
+                    "opacity" : None,
+                    "cmd"     : ['d.grid'],
+                    "group"   : self.inGroup,
+                    "display" : 0})
+
+        elif element == 'gridcolor':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('color=%s' % self._color_name_to_rgb(value))
+
+        elif element == 'gridborder':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('bordercolor=%s' % self._color_name_to_rgb(value))
+
+        elif element == 'textcolor':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('textcolor=%s' % self._color_name_to_rgb(value))
+
+        elif element in ('gridsize',
+                         'gridorigin'):
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('%s=%s' % (element[4:], value))
+
+        elif element in 'fontsize':
+            value = self._get_value(line)
+            if value != '':
+                self.layers[-1]['cmd'].append('%s=%s' % (element, value))
+        
+        elif element == 'griddraw':
+            value = self._get_value(line)
+            if value == '0':
+                self.layers[-1]['cmd'].append('-n')
+                
+        elif element == 'gridgeo':
+            value = self._get_value(line)
+            if value == '1':
+                self.layers[-1]['cmd'].append('-g')
+        
+        elif element == 'borderdraw':
+            value = self._get_value(line)
+            if value == '0':
+                self.layers[-1]['cmd'].append('-b')
+
+        elif element == 'textdraw':
+            value = self._get_value(line)
+            if value == '0':
+                self.layers[-1]['cmd'].append('-t')
+        
+        else:
+            self.error += _(' row %d:') % line_id + line + os.linesep
+            self.num_error += 1
+
+    def _get_value(self, line):
+        """!Get value of element"""
+        try:
+            return line.strip(' ').split(' ')[1].strip(' ')
+        except:
+            return ''
+
+    def _get_element(self, line):
+        """!Get element tag"""
+        return line.strip(' ').split(' ')[0].strip(' ')
+
+    def _get_cmd_param_index(self, cmd, name):
+        """!Get index of parameter in cmd list
+
+        @param cmd cmd list
+        @param name parameter name
+
+        @return index
+        @return -1 if not found
+        """
+        i = 0
+        for param in cmd:
+            if '=' not in param:
+                i += 1
+                continue
+            if param.split('=')[0] == name:
+                return i
+
+            i += 1
+
+        return -1
+
+    def _color_name_to_rgb(self, value):
+        """!Convert color name (#) to rgb values"""
+        col = wx.NamedColour(value)
+        return str(col.Red()) + ':' + \
+            str(col.Green()) + ':' + \
+            str(col.Blue())

Added: grass/trunk/gui/wxpython/create__init__.py
===================================================================
--- grass/trunk/gui/wxpython/create__init__.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/create__init__.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import glob
+
+def main(path):
+    if not os.path.exists(path) or not os.path.isdir(path):
+        print >> sys.stderr, "'%s' is not a directory" % path
+        return 1
+    
+    modules = []
+    for f in glob.glob(os.path.join(os.path.basename(path), '*.py')):
+        if f[-5:-3] == '__':
+            continue
+        modules.append(os.path.splitext(os.path.basename(f))[0])
+        
+    fd = open(os.path.join(path, '__init__.py'), 'w')
+    try:
+        fd.write('all = [%s' % os.linesep)
+        for m in modules:
+            fd.write("    '%s',%s" % (m, os.linesep))
+        fd.write('    ]%s' % os.linesep)
+    finally:
+        fd.close()
+    
+    return 0
+
+if __name__ == "__main__":
+    if len(sys.argv) < 2:
+        sys.exit("usage: %s path/to/gui_modules" % sys.argv[0])
+    
+    sys.exit(main(sys.argv[1]))


Property changes on: grass/trunk/gui/wxpython/create__init__.py
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/dbm/dialogs.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/dbm_dialogs.py)
===================================================================
--- grass/trunk/gui/wxpython/dbm/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/dbm/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,668 @@
+"""!
+ at package dbm.dialogs
+
+ at brief DBM-related dialogs
+
+List of classes:
+ - DisplayAttributesDialog
+ - ModifyTableRecord
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+from core import globalvar
+import wx
+import wx.lib.scrolledpanel as scrolled
+
+from core.gcmd     import RunCommand
+from core.debug    import Debug
+from core.settings import UserSettings
+from dbm.vinfo     import VectorDBInfo
+
+class DisplayAttributesDialog(wx.Dialog):
+    def __init__(self, parent, map,
+                 query = None, cats = None, line = None,
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+                 pos = wx.DefaultPosition,
+                 action = "add", ignoreError = False):
+        """!Standard dialog used to add/update/display attributes linked
+        to the vector map.
+        
+        Attribute data can be selected based on layer and category number
+        or coordinates.
+        
+        @param parent
+        @param map vector map
+        @param query query coordinates and distance (used for v.edit)
+        @param cats {layer: cats}
+        @param line feature id (requested for cats)
+        @param style
+        @param pos
+        @param action (add, update, display)
+        @param ignoreError True to ignore errors
+        """
+        self.parent = parent # mapdisplay.BufferedWindow
+        self.map    = map
+        self.action = action
+
+        # ids/cats of selected features
+        # fid : {layer : cats}
+        self.cats = {}
+        self.fid = -1 # feature id
+        
+        # get layer/table/column information
+        self.mapDBInfo = VectorDBInfo(self.map)
+        
+        layers = self.mapDBInfo.layers.keys() # get available layers
+
+        # check if db connection / layer exists
+        if len(layers) <= 0:
+            if not ignoreError:
+                dlg = wx.MessageDialog(parent = self.parent,
+                                       message = _("No attribute table found.\n\n"
+                                                   "Do you want to create a new attribute table "
+                                                   "and defined a link to vector map <%s>?") % self.map,
+                                       caption = _("Create table?"),
+                                       style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+                if dlg.ShowModal() == wx.ID_YES:
+                    lmgr = self.parent.lmgr
+                    lmgr.OnShowAttributeTable(event = None, selection = 'layers')
+                
+                dlg.Destroy()
+            
+            self.mapDBInfo = None
+        
+        wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY,
+                           title = "", style = style, pos = pos)
+
+        # dialog body
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+
+        # notebook
+        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+
+        self.closeDialog = wx.CheckBox(parent = self, id = wx.ID_ANY,
+                                       label = _("Close dialog on submit"))
+        self.closeDialog.SetValue(True)
+        if self.action == 'display':
+            self.closeDialog.Enable(False)
+        
+        # feature id (text/choice for duplicates)
+        self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
+                                  size = (150, -1))
+        self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
+        self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
+
+        self.noFoundMsg = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                        label = _("No attributes found"))
+        
+        self.UpdateDialog(query = query, cats = cats)
+
+        # set title
+        if self.action == "update":
+            self.SetTitle(_("Update attributes"))
+        elif self.action == "add":
+            self.SetTitle(_("Define attributes"))
+        else:
+            self.SetTitle(_("Display attributes"))
+
+        # buttons
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnReset  = wx.Button(self, wx.ID_UNDO, _("&Reload"))
+        btnSubmit = wx.Button(self, wx.ID_OK, _("&Submit"))
+        if self.action == 'display':
+            btnSubmit.Enable(False)
+        
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        btnSizer.AddButton(btnReset)
+        btnSizer.SetNegativeButton(btnReset)
+        btnSubmit.SetDefault()
+        btnSizer.AddButton(btnSubmit)
+        btnSizer.Realize()
+
+        mainSizer.Add(item = self.noFoundMsg, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = self.notebook, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        fidSizer = wx.BoxSizer(wx.HORIZONTAL)
+        fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                        label = _("Feature id:")),
+                     proportion = 0, border = 5,
+                     flag = wx.ALIGN_CENTER_VERTICAL)
+        fidSizer.Add(item = self.fidMulti, proportion = 0,
+                     flag = wx.EXPAND | wx.ALL,  border = 5)
+        fidSizer.Add(item = self.fidText, proportion = 0,
+                     flag = wx.EXPAND | wx.ALL,  border = 5)
+        mainSizer.Add(item = fidSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+        mainSizer.Add(item = self.closeDialog, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
+                      border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        # bindigs
+        btnReset.Bind(wx.EVT_BUTTON, self.OnReset)
+        btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit)
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+        # set min size for dialog
+        w, h = self.GetBestSize()
+        if h < 200:
+            self.SetMinSize((w, 200))
+        else:
+            self.SetMinSize(self.GetBestSize())
+
+        if self.notebook.GetPageCount() == 0:
+            Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
+            ### self.mapDBInfo = None
+        
+    def OnSQLStatement(self, event):
+        """!Update SQL statement"""
+        pass
+
+    def IsFound(self):
+        """!Check for status
+
+        @return True on attributes found
+        @return False attributes not found
+        """
+        return bool(self.mapDBInfo and self.notebook.GetPageCount() > 0)
+    
+    def GetSQLString(self, updateValues = False):
+        """!Create SQL statement string based on self.sqlStatement
+
+        If updateValues is True, update dataFrame according to values
+        in textfields.
+        """
+        sqlCommands = []
+        # find updated values for each layer/category
+        for layer in self.mapDBInfo.layers.keys(): # for each layer
+            table = self.mapDBInfo.GetTable(layer)
+            key = self.mapDBInfo.GetKeyColumn(layer)
+            columns = self.mapDBInfo.GetTableDesc(table)
+            for idx in range(len(columns[key]['values'])): # for each category
+                updatedColumns = []
+                updatedValues = []
+                for name in columns.keys():
+                    if name == key:
+                        cat = columns[name]['values'][idx]
+                        continue
+                    type  = columns[name]['type']
+                    value = columns[name]['values'][idx]
+                    id    = columns[name]['ids'][idx]
+                    try:
+                        newvalue = self.FindWindowById(id).GetValue()
+                    except:
+                        newvalue = self.FindWindowById(id).GetLabel()
+
+                    if newvalue == '':
+                        newvalue = None
+                    
+                    if newvalue != value:
+                        updatedColumns.append(name)
+                        if newvalue is None:
+                            updatedValues.append('NULL')
+                        else:
+                            if type != 'character':
+                                updatedValues.append(newvalue)
+                            else:
+                                updatedValues.append("'" + newvalue + "'")
+                        columns[name]['values'][idx] = newvalue
+
+                if self.action != "add" and len(updatedValues) == 0:
+                    continue
+
+                if self.action == "add":
+                    sqlString = "INSERT INTO %s (%s," % (table, key)
+                else:
+                    sqlString = "UPDATE %s SET " % table
+
+                for idx in range(len(updatedColumns)):
+                    name = updatedColumns[idx]
+                    if self.action == "add":
+                        sqlString += name + ","
+                    else:
+                        sqlString += name + "=" + updatedValues[idx] + ","
+
+                sqlString = sqlString[:-1] # remove last comma
+
+                if self.action == "add":
+                    sqlString += ") VALUES (%s," % cat
+                    for value in updatedValues:
+                        sqlString += str(value) + ","
+                    sqlString = sqlString[:-1] # remove last comma
+                    sqlString += ")"
+                else:
+                    sqlString += " WHERE %s=%s" % (key, cat)
+                sqlCommands.append(sqlString)
+            # for each category
+        # for each layer END
+
+        Debug.msg(3, "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
+
+        return sqlCommands
+
+    def OnReset(self, event = None):
+        """!Reset form"""
+        for layer in self.mapDBInfo.layers.keys():
+            table = self.mapDBInfo.layers[layer]["table"]
+            key = self.mapDBInfo.layers[layer]["key"]
+            columns = self.mapDBInfo.tables[table]
+            for idx in range(len(columns[key]['values'])):
+                for name in columns.keys():
+                    type  = columns[name]['type']
+                    value = columns[name]['values'][idx]
+                    if value is None:
+                        value = ''
+                    try:
+                        id = columns[name]['ids'][idx]
+                    except IndexError:
+                        id = wx.NOT_FOUND
+                    
+                    if name != key and id != wx.NOT_FOUND:
+                        self.FindWindowById(id).SetValue(str(value))
+
+    def OnCancel(self, event):
+        """!Cancel button pressed
+        """
+        self.parent.parent.dialogs['attributes'] = None
+        
+        if hasattr(self, "digit"):
+            self.parent.digit.GetDisplay().SetSelected([])
+            self.parent.UpdateMap(render = False)
+        else:
+            self.parent.parent.OnRender(None)
+        
+        self.Close()
+
+    def OnSubmit(self, event):
+        """!Submit records"""
+        layer = 1
+        for sql in self.GetSQLString(updateValues = True):
+            enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
+            if not enc and 'GRASS_DB_ENCODING' in os.environ:
+                enc = os.environ['GRASS_DB_ENCODING']
+            if enc:
+                sql = sql.encode(enc)
+
+            driver, database = self.mapDBInfo.GetDbSettings(layer)
+            Debug.msg(1, "SQL: %s" % sql)
+            RunCommand('db.execute',
+                       parent = self,
+                       quiet = True,
+                       input = '-',
+                       stdin = sql,
+                       driver = driver,
+                       database = database)
+            
+            layer += 1
+        
+        if self.closeDialog.IsChecked():
+            self.OnCancel(event)
+
+    def OnFeature(self, event):
+        self.fid = int(event.GetString())
+        self.UpdateDialog(cats = self.cats, fid = self.fid)
+        
+    def GetCats(self):
+        """!Get id of selected vector object or 'None' if nothing selected
+
+        @param id if true return ids otherwise cats
+        """
+        if self.fid < 0:
+            return None
+        
+        return self.cats[self.fid]
+
+    def GetFid(self):
+        """!Get selected feature id"""
+        return self.fid
+    
+    def UpdateDialog(self, map = None, query = None, cats = None, fid = -1,
+                     action = None):
+        """!Update dialog
+        
+        @param map name of vector map
+        @param query
+        @param cats
+        @param fid feature id
+        @param action add, update, display or None
+        
+        @return True if updated
+        @return False
+        """
+        if action:
+            self.action = action
+            if action == 'display':
+                enabled = False
+            else:
+                enabled = True
+            self.closeDialog.Enable(enabled)
+            self.FindWindowById(wx.ID_OK).Enable(enabled)
+        
+        if map:
+            self.map = map
+            # get layer/table/column information
+            self.mapDBInfo = VectorDBInfo(self.map)
+        
+        if not self.mapDBInfo:
+            return False
+        
+        self.mapDBInfo.Reset()
+        
+        layers = self.mapDBInfo.layers.keys() # get available layers
+        
+        # id of selected line
+        if query: # select by position
+            data = self.mapDBInfo.SelectByPoint(query[0],
+                                                query[1])
+            self.cats = {}
+            if data and 'Layer' in data:
+                idx = 0
+                for layer in data['Layer']:
+                    layer = int(layer)
+                    if 'Id' in data:
+                        tfid = int(data['Id'][idx])
+                    else:
+                        tfid = 0 # Area / Volume
+                    if not tfid in self.cats:
+                        self.cats[tfid] = {}
+                    if not layer in self.cats[tfid]:
+                        self.cats[tfid][layer] = []
+                    cat = int(data['Category'][idx])
+                    self.cats[tfid][layer].append(cat)
+                    idx += 1
+        else:
+            self.cats = cats
+        
+        if fid > 0:
+            self.fid = fid
+        elif len(self.cats.keys()) > 0:
+            self.fid = self.cats.keys()[0]
+        else:
+            self.fid = -1
+        
+        if len(self.cats.keys()) == 1:
+            self.fidMulti.Show(False)
+            self.fidText.Show(True)
+            if self.fid > 0:
+                self.fidText.SetLabel("%d" % self.fid)
+            else:
+                self.fidText.SetLabel(_("Unknown"))
+        else:
+            self.fidMulti.Show(True)
+            self.fidText.Show(False)
+            choices = []
+            for tfid in self.cats.keys():
+                choices.append(str(tfid))
+            self.fidMulti.SetItems(choices)
+            self.fidMulti.SetStringSelection(str(self.fid))
+        
+        # reset notebook
+        self.notebook.DeleteAllPages()
+        
+        for layer in layers: # for each layer
+            if not query: # select by layer/cat
+                if self.fid > 0 and layer in self.cats[self.fid]:
+                    for cat in self.cats[self.fid][layer]:
+                        nselected = self.mapDBInfo.SelectFromTable(layer,
+                                                                   where = "%s=%d" % \
+                                                                   (self.mapDBInfo.layers[layer]['key'],
+                                                                    cat))
+                else:
+                    nselected = 0
+            
+            # if nselected <= 0 and self.action != "add":
+            #    continue # nothing selected ...
+            
+            if self.action == "add":
+                if nselected <= 0:
+                    if layer in self.cats[self.fid]:
+                        table = self.mapDBInfo.layers[layer]["table"]
+                        key = self.mapDBInfo.layers[layer]["key"]
+                        columns = self.mapDBInfo.tables[table]
+                        for name in columns.keys():
+                            if name == key:
+                                for cat in self.cats[self.fid][layer]:
+                                    self.mapDBInfo.tables[table][name]['values'].append(cat)
+                            else:
+                                self.mapDBInfo.tables[table][name]['values'].append(None)
+                else: # change status 'add' -> 'update'
+                    self.action = "update"
+            
+            table   = self.mapDBInfo.layers[layer]["table"]
+            key   = self.mapDBInfo.layers[layer]["key"]
+            columns = self.mapDBInfo.tables[table]
+            
+            for idx in range(len(columns[key]['values'])):
+                for name in columns.keys():
+                    if name == key:
+                        cat = int(columns[name]['values'][idx])
+                        break
+
+                # use scrolled panel instead (and fix initial max height of the window to 480px)
+                panel = scrolled.ScrolledPanel(parent = self.notebook, id = wx.ID_ANY,
+                                               size = (-1, 150))
+                panel.SetupScrolling(scroll_x = False)
+                
+                self.notebook.AddPage(page = panel, text = " %s %d / %s %d" % (_("Layer"), layer,
+                                                                           _("Category"), cat))
+                
+                # notebook body
+                border = wx.BoxSizer(wx.VERTICAL)
+                
+                flexSizer = wx.FlexGridSizer (cols = 4, hgap = 3, vgap = 3)
+                flexSizer.AddGrowableCol(3)
+                # columns (sorted by index)
+                names = [''] * len(columns.keys())
+                for name in columns.keys():
+                    names[columns[name]['index']] = name
+                
+                for name in names:
+                    if name == key: # skip key column (category)
+                        continue
+                    
+                    vtype  = columns[name]['type']
+                    
+                    if columns[name]['values'][idx] is not None:
+                        if columns[name]['ctype'] != type(''):
+                            value = str(columns[name]['values'][idx])
+                        else:
+                            value = columns[name]['values'][idx]
+                    else:
+                        value = ''
+                    
+                    colName = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                            label = name)
+                    colType = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                            label = "[" + vtype.lower() + "]")
+                    delimiter = wx.StaticText(parent = panel, id = wx.ID_ANY, label = ":")
+                    
+                    colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
+                    colValue.SetName(name)
+                    self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
+                    if self.action == 'display':
+                        colValue.SetWindowStyle(wx.TE_READONLY)
+                    
+                    flexSizer.Add(colName, proportion = 0,
+                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+                    flexSizer.Add(colType, proportion = 0,
+                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+                    flexSizer.Add(delimiter, proportion = 0,
+                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+                    flexSizer.Add(colValue, proportion = 1,
+                                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+                    # add widget reference to self.columns
+                    columns[name]['ids'].append(colValue.GetId()) # name, type, values, id
+                # for each attribute (including category) END
+                border.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+                panel.SetSizer(border)
+            # for each category END
+        # for each layer END
+        
+        if self.notebook.GetPageCount() == 0:
+            self.noFoundMsg.Show(True)
+        else:
+            self.noFoundMsg.Show(False)
+        
+        self.Layout()
+        
+        return True
+
+    def SetColumnValue(self, layer, column, value):
+        """!Set attrbute value
+
+        @param column column name
+        @param value value
+        """
+        table = self.mapDBInfo.GetTable(layer)
+        columns = self.mapDBInfo.GetTableDesc(table)
+        
+        for key, col in columns.iteritems():
+            if key == column:
+                col['values'] = [col['ctype'](value),]
+                break
+        
+class ModifyTableRecord(wx.Dialog):
+    def __init__(self, parent, title, data, keyEditable = (-1, True),
+                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        """!Dialog for inserting/updating table record
+        
+        @param data a list: [(column, value)]
+        @param KeyEditable (id, editable?) indicates if textarea for key column
+        is editable(True) or not
+        """
+        # parent -> VDigitWindow
+        wx.Dialog.__init__(self, parent, id, title, style = style)
+        
+        self.CenterOnParent()
+        
+        self.keyId = keyEditable[0]
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY)
+        box.Hide()
+        self.dataPanel = scrolled.ScrolledPanel(parent = self.panel, id = wx.ID_ANY,
+                                                style = wx.TAB_TRAVERSAL)
+        self.dataPanel.SetupScrolling(scroll_x = False)
+        
+        # buttons
+        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
+        self.btnSubmit = wx.Button(self.panel, wx.ID_OK, _("&Submit"))
+        self.btnSubmit.SetDefault()
+        
+        # data area
+        self.widgets = []
+        cId = 0
+        self.usebox = False
+        self.cat = None
+        winFocus = False
+        for column, value in data:
+            if self.keyId == cId:
+                self.cat = int(value)
+                if not keyEditable[1]:
+                    self.usebox = True
+                    box.SetLabel(" %s %d " % (_("Category"), self.cat))
+                    box.Show()
+                    self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+                    cId += 1
+                    continue
+                else:
+                    valueWin = wx.SpinCtrl(parent = self.dataPanel, id = wx.ID_ANY,
+                                           value = value, min = -1e9, max = 1e9, size = (250, -1))
+            else:
+                valueWin = wx.TextCtrl(parent = self.dataPanel, id = wx.ID_ANY,
+                                       value = value, size = (250, -1))
+                if not winFocus:
+                    wx.CallAfter(valueWin.SetFocus)
+                    winFocus = True
+            
+            label = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
+                                  label = column + ":")
+            
+            self.widgets.append((label.GetId(), valueWin.GetId()))
+            
+            cId += 1
+        
+        self._layout()
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # data area
+        dataSizer = wx.FlexGridSizer (cols = 2, hgap = 3, vgap = 3)
+        dataSizer.AddGrowableCol(1)
+        
+        for labelId, valueId in self.widgets:
+            label = self.FindWindowById(labelId)
+            value = self.FindWindowById(valueId)
+            
+            dataSizer.Add(label, proportion = 0,
+                          flag = wx.ALIGN_CENTER_VERTICAL)
+            dataSizer.Add(value, proportion = 0,
+                          flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+        
+        self.dataPanel.SetAutoLayout(True)
+        self.dataPanel.SetSizer(dataSizer)
+        dataSizer.Fit(self.dataPanel)
+        
+        if self.usebox:
+            self.boxSizer.Add(item = self.dataPanel, proportion = 1,
+                              flag = wx.EXPAND | wx.ALL, border = 5)
+            
+        # buttons
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnSubmit)
+        btnSizer.Realize()
+        
+        if not self.usebox:
+            sizer.Add(item = self.dataPanel, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        else:
+            sizer.Add(item = self.boxSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALL, border = 5)
+        
+        framewidth = self.GetSize()[0]
+        self.SetMinSize((framewidth,150))
+        self.SetMaxSize((framewidth,300))
+        
+        # sizer.SetSizeHints(self.panel)
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        
+        self.Layout()
+        
+    def GetValues(self, columns = None):
+        """!Return list of values (casted to string).
+        
+        If columns is given (list), return only values of given columns.
+        """
+        valueList = []
+        for labelId, valueId in self.widgets:
+            column = self.FindWindowById(labelId).GetLabel().replace(':', '')
+            if columns is None or column in columns:
+                value = str(self.FindWindowById(valueId).GetValue())
+                valueList.append(value)
+        
+        # add key value
+        if self.usebox:
+            valueList.insert(self.keyId, str(self.cat))
+                             
+        return valueList

Copied: grass/trunk/gui/wxpython/dbm/manager.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/dbm.py)
===================================================================
--- grass/trunk/gui/wxpython/dbm/manager.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/dbm/manager.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,3092 @@
+"""!
+ at package dbm.manager
+
+ at brief GRASS Attribute Table Manager
+
+This program is based on FileHunter, published in 'The wxPython Linux
+Tutorial' on wxPython WIKI pages.
+
+It also uses some functions at
+http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407
+
+ at code
+python dbm.py vector at mapset
+ at endcode
+
+List of classes:
+ - Log
+ - VirtualAttributeList
+ - AttributeManager
+ - TableListCtrl
+ - LayerListCtrl
+ - LayerBook
+
+(C) 2007-2009, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Jachym Cepicky <jachym.cepicky gmail.com>
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import sys
+import os
+import locale
+import tempfile
+import copy
+import types
+
+from core import globalvar
+import wx
+import wx.lib.mixins.listctrl as listmix
+import wx.lib.flatnotebook    as FN
+
+import grass.script as grass
+
+from dbm.sqlbuilder   import SQLFrame
+from core.gcmd        import RunCommand, GException, GError
+from core.utils       import ListOfCatsToRange
+from gui_core.dialogs import CreateNewVector
+from dbm.vinfo        import VectorDBInfo, unicodeValue, createDbInfoDesc
+from core.debug       import Debug
+from dbm.dialogs      import ModifyTableRecord
+from core.settings    import UserSettings
+from gui_core.widgets import GNotebook
+
+class Log:
+    """
+    The log output is redirected to the status bar of the containing frame.
+    """
+    def __init__(self, parent):
+        self.parent = parent
+
+    def write(self, text_string):
+        """!Update status bar"""
+        self.parent.SetStatusText(text_string.strip())
+
+
+class VirtualAttributeList(wx.ListCtrl,
+                           listmix.ListCtrlAutoWidthMixin,
+                           listmix.ColumnSorterMixin):
+    """
+    Support virtual list class
+    """
+    def __init__(self, parent, log, mapDBInfo, layer):
+        #
+        # initialize variables
+        #
+        self.parent  = parent
+        self.log     = log
+        self.mapDBInfo = mapDBInfo
+        self.layer   = layer
+        
+        self.columns = {} # <- LoadData()
+
+        wx.ListCtrl.__init__(self, parent=parent, id=wx.ID_ANY,
+                             style=wx.LC_REPORT | wx.LC_HRULES |
+                             wx.LC_VRULES | wx.LC_VIRTUAL | wx.LC_SORT_ASCENDING)
+        
+        try:
+            keyColumn = self.LoadData(layer)
+        except GException, e:
+            GError(parent = self,
+                   message = e.value)
+            return
+        
+        #
+        # add some attributes (colourful background for each item rows)
+        #
+        self.attr1 = wx.ListItemAttr()
+        self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
+        self.attr2 = wx.ListItemAttr()
+        self.attr2.SetBackgroundColour("white")
+        self.il = wx.ImageList(16, 16)
+        self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
+                                                          (16,16)))
+        self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
+                                                          (16,16)))
+        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
+        
+        # setup mixins
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.ColumnSorterMixin.__init__(self, len(self.columns))
+
+        # sort item by category (id)
+        if keyColumn > -1:
+            self.SortListItems(col=keyColumn, ascending=True) 
+        else:
+            self.SortListItems(col=0, ascending=True) 
+        
+        # events
+        self.Bind(wx.EVT_LIST_ITEM_SELECTED,   self.OnItemSelected)
+        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected)
+        self.Bind(wx.EVT_LIST_COL_CLICK,       self.OnColumnSort)     
+        self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColumnMenu)     
+        
+    def Update(self, mapDBInfo):
+        """!Update list according new mapDBInfo description"""
+        self.mapDBInfo = mapDBInfo
+        self.LoadData(self.layer)
+
+    def LoadData(self, layer, columns=None, where=None, sql=None):
+        """!Load data into list
+
+        @param layer layer number
+        @param columns list of columns for output (-> v.db.select)
+        @param where where statement (-> v.db.select)
+        @param sql full sql statement (-> db.select)
+        
+        @return id of key column 
+        @return -1 if key column is not displayed
+        """
+        self.log.write(_("Loading data..."))
+        
+        tableName    = self.mapDBInfo.layers[layer]['table']
+        keyColumn    = self.mapDBInfo.layers[layer]['key']
+        try:
+            self.columns = self.mapDBInfo.tables[tableName]
+        except KeyError:
+            raise GException(_("Attribute table <%s> not found. "
+                                    "For creating the table switch to "
+                                    "'Manage layers' tab.") % tableName)
+        
+        if not columns:
+            columns = self.mapDBInfo.GetColumns(tableName)
+        else:
+            all = self.mapDBInfo.GetColumns(tableName)
+            for col in columns:
+                if col not in all:
+                    wx.MessageBox(parent=self,
+                                  message=_("Column <%(column)s> not found in "
+                                            "in the table <%(table)s>.") % \
+                                      { 'column' : col, 'table' : tableName },
+                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                    return
+        
+        try:
+            # for maps connected via v.external
+            keyId = columns.index(keyColumn)
+        except:
+            keyId = -1
+        
+        #
+        # read data
+        #
+        # FIXME: Max. number of rows, while the GUI is still usable
+
+        # stdout can be very large, do not use PIPE, redirect to temp file
+        # TODO: more effective way should be implemented...
+        outFile = tempfile.NamedTemporaryFile(mode='w+b')
+        
+        if sql:
+            ret = RunCommand('db.select',
+                             quiet = True,
+                             parent = self,
+                             flags = 'c',
+                             sql = sql,
+                             output = outFile.name)
+        else:
+            if columns:
+                ret = RunCommand('v.db.select',
+                                 quiet = True,
+                                 parent = self,
+                                 flags = 'c',
+                                 map = self.mapDBInfo.map,
+                                 layer = layer,
+                                 columns = ','.join(columns),
+                                 where = where,
+                                 stdout = outFile)
+            else:
+                ret = RunCommand('v.db.select',
+                                 quiet = True,
+                                 parent = self,
+                                 flags = 'c',
+                                 map = self.mapDBInfo.map,
+                                 layer = layer,
+                                 where = where,
+                                 stdout = outFile) 
+        
+        # These two should probably be passed to init more cleanly
+        # setting the numbers of items = number of elements in the dictionary
+        self.itemDataMap  = {}
+        self.itemIndexMap = []
+        self.itemCatsMap  = {}
+        
+        self.DeleteAllItems()
+        
+        # self.ClearAll()
+        for i in range(self.GetColumnCount()):
+            self.DeleteColumn(0)
+        
+        i = 0
+        info = wx.ListItem()
+        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
+        info.m_image = -1
+        info.m_format = 0
+        for column in columns:
+            info.m_text = column
+            self.InsertColumnInfo(i, info)
+            i += 1
+            
+            if i >= 256:
+                self.log.write(_("Can display only 256 columns."))
+        
+        i = 0
+        outFile.seek(0)
+        
+        while True:
+            # os.linesep doesn't work here (MSYS)
+            record = outFile.readline().replace('\n', '')
+            
+            if not record:
+                break
+           
+            self.AddDataRow(i, record, columns, keyId)
+
+            i += 1
+            if i >= 100000:
+                self.log.write(_("Limit 100000 records."))
+                break
+        
+        self.SetItemCount(i)
+        
+        i = 0
+        for col in columns:
+            width = self.columns[col]['length'] * 6 # FIXME
+            if width < 60:
+                width = 60
+            if width > 300:
+                width = 300
+            self.SetColumnWidth(col=i, width=width)
+            i += 1
+        
+        self.SendSizeEvent()
+        
+        self.log.write(_("Number of loaded records: %d") % \
+                           self.GetItemCount())
+        
+        return keyId
+    
+    def AddDataRow(self, i, record, columns, keyId):
+        """!Add row to the data list"""
+        self.itemDataMap[i] = []
+        keyColumn = self.mapDBInfo.layers[self.layer]['key']
+        j = 0
+        cat = None
+        
+        if keyColumn == 'OGC_FID':
+            self.itemDataMap[i].append(i+1)
+            j += 1
+            cat = i + 1
+        
+        for value in record.split('|'):
+            if self.columns[columns[j]]['ctype'] != types.StringType:
+                try:
+                    ### casting disabled (2009/03)
+                    ### self.itemDataMap[i].append(self.columns[columns[j]]['ctype'](value))
+                    self.itemDataMap[i].append(value)
+                except ValueError:
+                    self.itemDataMap[i].append(_('Unknown value'))
+            else:
+                # encode string values
+                try:
+                    self.itemDataMap[i].append(unicodeValue(value))
+                except UnicodeDecodeError:
+                    self.itemDataMap[i].append(_("Unable to decode value. "
+                                                 "Set encoding in GUI preferences ('Attributes')."))
+                
+            if not cat and keyId > -1 and keyId == j:
+                try:
+                    cat = self.columns[columns[j]]['ctype'] (value)
+                except ValueError, e:
+                    cat = -1
+                    gGError(parent = self,
+                            message=_("Error loading attribute data. "
+                                      "Record number: %(rec)d. Unable to convert value '%(val)s' in "
+                                      "key column (%(key)s) to integer.\n\n"
+                                      "Details: %(detail)s") % \
+                                { 'rec' : i + 1, 'val' : value,
+                                  'key' : keyColumn, 'detail' : e})
+            j += 1
+        
+        self.itemIndexMap.append(i)
+        if keyId > -1: # load cats only when LoadData() is called first time
+            self.itemCatsMap[i] = cat
+        
+    def OnItemSelected(self, event):
+        """!Item selected. Add item to selected cats..."""
+        #         cat = int(self.GetItemText(event.m_itemIndex))
+        #         if cat not in self.selectedCats:
+        #             self.selectedCats.append(cat)
+        #             self.selectedCats.sort()
+        
+        event.Skip()
+
+    def OnItemDeselected(self, event):
+        """!Item deselected. Remove item from selected cats..."""
+        #         cat = int(self.GetItemText(event.m_itemIndex))
+        #         if cat in self.selectedCats:
+        #             self.selectedCats.remove(cat)
+        #             self.selectedCats.sort()
+
+        event.Skip()
+
+    def GetSelectedItems(self):
+        """!Return list of selected items (category numbers)"""
+        cats = []
+        item = self.GetFirstSelected()
+        while item != -1:
+            cats.append(self.GetItemText(item))
+            item = self.GetNextSelected(item)
+
+        return cats
+
+    def GetColumnText(self, index, col):
+        """!Return column text"""
+        item = self.GetItem(index, col)
+        return item.GetText()
+
+    def GetListCtrl(self):
+        """!Returt list"""
+        return self
+
+    def OnGetItemText(self, item, col):
+        """!Get item text"""
+        index = self.itemIndexMap[item]
+        s = self.itemDataMap[index][col]
+        return s
+
+    def OnGetItemAttr(self, item):
+        """!Get item attributes"""
+        if ( item % 2) == 0:
+            return self.attr2
+        else:
+            return self.attr1
+
+    def OnColumnMenu(self, event):
+        """!Column heading right mouse button -> pop-up menu"""
+        self._col = event.GetColumn()
+        
+        popupMenu = wx.Menu()
+
+        if not hasattr (self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.popupID3 = wx.NewId()
+            self.popupID4 = wx.NewId()
+            self.popupID5 = wx.NewId()
+            self.popupID6 = wx.NewId()
+            self.popupID7 = wx.NewId()
+            self.popupID8 = wx.NewId()
+            self.popupID9 = wx.NewId()
+            self.popupID10 = wx.NewId()
+            self.popupID11 = wx.NewId()
+            self.popupID12 = wx.NewId()
+        
+        popupMenu.Append(self.popupID1, text=_("Sort ascending"))
+        popupMenu.Append(self.popupID2, text=_("Sort descending"))
+        popupMenu.AppendSeparator()
+        subMenu = wx.Menu()
+        popupMenu.AppendMenu(self.popupID3, _("Calculate (only numeric columns)"),
+                             subMenu)
+        if not self.log.parent.editable or \
+                self.columns[self.GetColumn(self._col).GetText()]['ctype'] not in (types.IntType, types.FloatType):
+            popupMenu.Enable(self.popupID3, False)
+        
+        subMenu.Append(self.popupID4,  text=_("Area size"))
+        subMenu.Append(self.popupID5,  text=_("Line length"))
+        subMenu.Append(self.popupID6,  text=_("Compactness of an area"))
+        subMenu.Append(self.popupID7,  text=_("Fractal dimension of boundary defining a polygon"))
+        subMenu.Append(self.popupID8,  text=_("Perimeter length of an area"))
+        subMenu.Append(self.popupID9,  text=_("Number of features for each category"))
+        subMenu.Append(self.popupID10, text=_("Slope steepness of 3D line"))
+        subMenu.Append(self.popupID11, text=_("Line sinuousity"))
+        subMenu.Append(self.popupID12, text=_("Line azimuth"))
+        
+        self.Bind (wx.EVT_MENU, self.OnColumnSortAsc,  id=self.popupID1)
+        self.Bind (wx.EVT_MENU, self.OnColumnSortDesc, id=self.popupID2)
+        for id in (self.popupID4, self.popupID5, self.popupID6,
+                   self.popupID7, self.popupID8, self.popupID9,
+                   self.popupID10, self.popupID11, self.popupID12):
+            self.Bind(wx.EVT_MENU, self.OnColumnCompute, id = id)
+        
+        self.PopupMenu(popupMenu)
+        popupMenu.Destroy()
+
+    def OnColumnSort(self, event):
+        """!Column heading left mouse button -> sorting"""
+        self._col = event.GetColumn()
+        
+        self.ColumnSort()
+        
+        event.Skip()
+
+    def OnColumnSortAsc(self, event):
+        """!Sort values of selected column (ascending)"""
+        self.SortListItems(col = self._col, ascending = True)
+        event.Skip()
+
+    def OnColumnSortDesc(self, event):
+        """!Sort values of selected column (descending)"""
+        self.SortListItems(col = self._col, ascending = False)
+        event.Skip()
+        
+    def OnColumnCompute(self, event):
+        """!Compute values of selected column"""
+        id = event.GetId()
+        
+        option = None
+        if id == self.popupID4:
+            option = 'area'
+        elif id == self.popupID5:
+            option = 'length'
+        elif id == self.popupID6:
+            option = 'compact'
+        elif id == self.popupID7:
+            option = 'fd'
+        elif id == self.popupID8:
+            option = 'perimeter'
+        elif id == self.popupID9:
+            option = 'count'
+        elif id == self.popupID10:
+            option = 'slope'
+        elif id == self.popupID11:
+            option = 'sinuous'
+        elif id == self.popupID12:
+            option = 'azimuth'
+        
+        if not option:
+            return
+        
+        RunCommand('v.to.db',
+                   parent = self.parent,
+                   map = self.mapDBInfo.map,
+                   layer = self.layer, 
+                   option = option,
+                   columns = self.GetColumn(self._col).GetText())
+        
+        self.LoadData(self.layer)
+        
+    def ColumnSort(self):
+        """!Sort values of selected column (self._col)"""
+        # remove duplicated arrow symbol from column header
+        # FIXME: should be done automatically
+        info = wx.ListItem()
+        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
+        info.m_image = -1
+        for column in range(self.GetColumnCount()):
+            info.m_text = self.GetColumn(column).GetText()
+            self.SetColumn(column, info)
+        
+    def SortItems(self, sorter=cmp):
+        """!Sort items"""
+        items = list(self.itemDataMap.keys())
+        items.sort(self.Sorter)
+        self.itemIndexMap = items
+
+        # redraw the list
+        self.Refresh()
+        
+    def Sorter(self, key1, key2):
+        colName = self.GetColumn(self._col).GetText()
+        ascending = self._colSortFlag[self._col]
+        try:
+            item1 = self.columns[colName]["ctype"](self.itemDataMap[key1][self._col])
+            item2 = self.columns[colName]["ctype"](self.itemDataMap[key2][self._col])
+        except ValueError:
+            item1 = self.itemDataMap[key1][self._col]
+            item2 = self.itemDataMap[key2][self._col]
+
+        if type(item1) == type('') or type(item2) == type(''):
+            cmpVal = locale.strcoll(str(item1), str(item2))
+        else:
+            cmpVal = cmp(item1, item2)
+
+
+        # If the items are equal then pick something else to make the sort value unique
+        if cmpVal == 0:
+            cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
+        
+        if ascending:
+            return cmpVal
+        else:
+            return -cmpVal
+
+    def GetSortImages(self):
+        """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
+        return (self.sm_dn, self.sm_up)
+
+    def IsEmpty(self):
+        """!Check if list if empty"""
+        if self.columns:
+            return False
+        
+        return True
+    
+class AttributeManager(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = None, vectorName = None, item = None, log = None,
+                 selection = None, **kwargs):
+        """!GRASS Attribute Table Manager window
+
+        @param parent parent window
+        @parem id window id
+        @param title window title or None for default title
+        @param vetorName name of vector map
+        @param item item from Layer Tree
+        @param log log window
+        @param selection name of page to be selected
+        @param kwagrs other wx.Frame's arguments
+        """
+        self.vectorName = vectorName
+        self.parent     = parent # GMFrame
+        self.treeItem   = item   # item in layer tree
+        if self.parent and self.parent.GetName() == "LayerManager" and \
+                self.treeItem and not self.vectorName:
+            maptree = self.parent.curr_page.maptree
+            name = maptree.GetPyData(self.treeItem)[0]['maplayer'].GetName()
+            self.vectorName = name
+        
+        # vector attributes can be changed only if vector map is in
+        # the current mapset
+        if grass.find_file(name = self.vectorName, element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
+            self.editable = True
+        else:
+            self.editable = False
+        
+        self.cmdLog = log    # self.parent.goutput
+        
+        wx.Frame.__init__(self, parent, id, *kwargs)
+
+        # title
+        if not title:
+            self.SetTitle("%s - <%s>" % (_("GRASS GIS Attribute Table Manager"),
+                                         self.vectorName))
+        else:
+            self.SetTitle(title)
+        
+        # icon
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
+
+        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
+
+        try:
+            self.map        = self.parent.curr_page.maptree.Map
+            self.mapdisplay = self.parent.curr_page.maptree.mapdisplay
+        except:
+            self.map = self.mapdisplay = None
+        
+        # status bar log class
+        self.log = Log(self) # -> statusbar
+
+        # query map layer (if parent (GMFrame) is given)
+        self.qlayer = None
+
+        # -> layers / tables description
+        self.mapDBInfo = VectorDBInfo(self.vectorName)
+
+        # sqlbuilder
+        self.builder = None
+        
+        if len(self.mapDBInfo.layers.keys()) == 0:
+            wx.MessageBox(parent=self.parent,
+                          message=_("Database connection for vector map <%s> "
+                                    "is not defined in DB file. "
+                                    "You can define new connection in "
+                                    "'Manage layers' tab.") % self.vectorName,
+                          caption=_("Attribute Table Manager"),
+                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+
+        #
+        # list of command/SQL statements to be performed
+        #
+        self.listOfCommands      = []
+        self.listOfSQLStatements = []
+
+        self.CreateStatusBar(number=1)
+
+        # set up virtual lists (each layer)
+        ### {layer: list, widgets...}
+        self.layerPage = {}
+
+        self.notebook = GNotebook(self.panel, style = globalvar.FNPageDStyle)
+        
+        if globalvar.hasAgw:
+            dbmStyle = { 'agwStyle' : globalvar.FNPageStyle }
+        else:
+            dbmStyle = { 'style' : globalvar.FNPageStyle }
+        
+        self.browsePage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
+                                          **dbmStyle)
+        self.notebook.AddPage(page = self.browsePage, text = _("Browse data"),
+                              name = 'browse')
+        self.browsePage.SetTabAreaColour(globalvar.FNPageColor)
+
+        self.manageTablePage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
+                                               **dbmStyle)
+        self.notebook.AddPage(page = self.manageTablePage, text = _("Manage tables"),
+                              name = 'table')
+        if not self.editable:
+            self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(False)
+        self.manageTablePage.SetTabAreaColour(globalvar.FNPageColor)
+
+        self.manageLayerPage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
+                                               **dbmStyle)
+        self.notebook.AddPage(page = self.manageLayerPage, text = _("Manage layers"),
+                              name = 'layers')
+        self.manageLayerPage.SetTabAreaColour(globalvar.FNPageColor)
+        if not self.editable:
+            self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(False)
+        
+        self._createBrowsePage()
+        self._createManageTablePage()
+        self._createManageLayerPage()
+
+        if selection:
+            wx.CallAfter(self.notebook.SetSelectionByName, selection) # select browse tab
+
+        # buttons
+        self.btnQuit   = wx.Button(parent=self.panel, id=wx.ID_EXIT)
+        self.btnQuit.SetToolTipString(_("Close Attribute Table Manager"))
+        self.btnReload = wx.Button(parent=self.panel, id=wx.ID_REFRESH)
+        self.btnReload.SetToolTipString(_("Reload attribute data (selected layer only)"))
+
+        # events
+        self.btnQuit.Bind(wx.EVT_BUTTON,   self.OnCloseWindow)
+        self.btnReload.Bind(wx.EVT_BUTTON, self.OnDataReload)
+        self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.browsePage)
+        self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.manageTablePage)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        # do layout
+        self._layout()
+
+        # self.SetMinSize(self.GetBestSize())
+        self.SetSize((680, 550)) # FIXME hard-coded size
+        self.SetMinSize(self.GetSize())
+
+    def _createBrowsePage(self, onlyLayer=-1):
+        """!Create browse tab page"""
+        for layer in self.mapDBInfo.layers.keys():
+            if onlyLayer > 0 and layer != onlyLayer:
+                continue
+
+            panel = wx.Panel(parent=self.browsePage, id=wx.ID_ANY)
+            
+            #IMPORTANT NOTE: wx.StaticBox MUST be defined BEFORE any of the 
+            #   controls that are placed IN the wx.StaticBox, or it will freeze
+            #   on the Mac
+            
+            listBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                       label=" %s " % _("Attribute data - right-click to edit/manage records"))
+            listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL)
+            
+            win = VirtualAttributeList(panel, self.log,
+                                       self.mapDBInfo, layer)
+            if win.IsEmpty():
+                del panel
+                continue
+            
+            win.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnDataItemActivated)
+
+            self.layerPage[layer] = {'browsePage': panel.GetId()}
+            
+            label = _("Table")
+            if not self.editable:
+                label += _(" (readonly)")
+            self.browsePage.AddPage(page=panel, text=" %d / %s %s" % \
+                                        (layer, label, self.mapDBInfo.layers[layer]['table']))
+
+            pageSizer = wx.BoxSizer(wx.VERTICAL)
+
+            # attribute data            
+            sqlBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                                  label=" %s " % _("SQL Query"))
+
+            sqlSizer = wx.StaticBoxSizer(sqlBox, wx.VERTICAL)
+
+            win.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnDataRightUp) #wxMSW
+            win.Bind(wx.EVT_RIGHT_UP,            self.OnDataRightUp) #wxGTK
+            if UserSettings.Get(group='atm', key='leftDbClick', subkey='selection') == 0:
+                win.Bind(wx.EVT_LEFT_DCLICK, self.OnDataItemEdit)
+                win.Bind(wx.EVT_COMMAND_LEFT_DCLICK, self.OnDataItemEdit)
+            else:
+                win.Bind(wx.EVT_LEFT_DCLICK, self.OnDataDrawSelected)
+                win.Bind(wx.EVT_COMMAND_LEFT_DCLICK, self.OnDataDrawSelected)
+                
+            
+            listSizer.Add(item=win, proportion=1,
+                          flag=wx.EXPAND | wx.ALL,
+                          border=3)
+
+            # sql statement box
+            btnApply = wx.Button(parent=panel, id=wx.ID_APPLY)
+            btnApply.SetToolTipString(_("Apply SELECT statement and reload data records"))
+            btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement)
+            btnSqlBuilder = wx.Button(parent=panel, id=wx.ID_ANY, label=_("SQL Builder"))
+            btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder)
+
+            sqlSimple = wx.RadioButton(parent=panel, id=wx.ID_ANY,
+                                       label=_("Simple"))
+            sqlSimple.SetValue(True)
+            sqlAdvanced = wx.RadioButton(parent=panel, id=wx.ID_ANY,
+                                         label=_("Advanced"))
+            sqlSimple.Bind(wx.EVT_RADIOBUTTON,   self.OnChangeSql)
+            sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql)
+
+            sqlWhereColumn = wx.Choice(parent=panel, id=wx.ID_ANY,
+                                       size=(100,-1),
+                                       choices=self.mapDBInfo.GetColumns(self.mapDBInfo.layers[layer]['table']))
+            sqlWhereValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="",
+                                        style=wx.TE_PROCESS_ENTER)
+            sqlWhereValue.SetToolTipString(_("Example: %s") % "MULTILANE = 'no' AND OBJECTID < 10")
+
+            sqlStatement = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
+                                       value="SELECT * FROM %s" % \
+                                           self.mapDBInfo.layers[layer]['table'],
+                                       style=wx.TE_PROCESS_ENTER)
+            sqlStatement.SetToolTipString(_("Example: %s") % "SELECT * FROM roadsmajor WHERE MULTILANE = 'no' AND OBJECTID < 10")
+            sqlWhereValue.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement)
+            sqlStatement.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement)
+
+            sqlLabel = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                     label="SELECT * FROM %s WHERE " % \
+                                         self.mapDBInfo.layers[layer]['table'])
+            label_query = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                        label="")
+
+            sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
+            sqlFlexSizer.AddGrowableCol(1)
+
+            sqlFlexSizer.Add(item=sqlSimple,
+                             flag=wx.ALIGN_CENTER_VERTICAL)
+            sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL)
+            sqlSimpleSizer.Add(item=sqlLabel,
+                               flag=wx.ALIGN_CENTER_VERTICAL)
+            sqlSimpleSizer.Add(item=sqlWhereColumn,
+                               flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+            sqlSimpleSizer.Add(item=sqlWhereValue, proportion=1,
+                               flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+            sqlFlexSizer.Add(item=sqlSimpleSizer,
+                             flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+            sqlFlexSizer.Add(item=btnApply,
+                             flag=wx.ALIGN_RIGHT)
+            sqlFlexSizer.Add(item=sqlAdvanced,
+                             flag=wx.ALIGN_CENTER_VERTICAL)
+            sqlFlexSizer.Add(item=sqlStatement,
+                             flag=wx.EXPAND)
+            sqlFlexSizer.Add(item=btnSqlBuilder,
+                             flag=wx.ALIGN_RIGHT)
+
+            sqlSizer.Add(item=sqlFlexSizer,
+                         flag=wx.ALL | wx.EXPAND,
+                         border=3)
+
+            pageSizer.Add(item=listSizer,
+                          proportion=1,
+                          flag=wx.ALL | wx.EXPAND,
+                          border=5)
+
+            pageSizer.Add(item=sqlSizer,
+                          proportion=0,
+                          flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.EXPAND,
+                          border=5)
+
+            panel.SetSizer(pageSizer)
+
+            self.layerPage[layer]['data']      = win.GetId()
+            self.layerPage[layer]['simple']    = sqlSimple.GetId()
+            self.layerPage[layer]['advanced']  = sqlAdvanced.GetId()
+            self.layerPage[layer]['whereColumn'] = sqlWhereColumn.GetId()
+            self.layerPage[layer]['where']     = sqlWhereValue.GetId()
+            self.layerPage[layer]['builder']   = btnSqlBuilder.GetId()
+            self.layerPage[layer]['statement'] = sqlStatement.GetId()
+
+
+        self.browsePage.SetSelection(0) # select first layer
+        try:
+            self.layer = self.mapDBInfo.layers.keys()[0]
+            self.OnChangeSql(None)
+            self.log.write(_("Number of loaded records: %d") % \
+                           self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount())
+        except (IndexError, KeyError):
+            self.layer = None
+        
+    def _createManageTablePage(self, onlyLayer=-1):
+        """!Create manage page (create/link and alter tables)"""
+        for layer in self.mapDBInfo.layers.keys():
+            if onlyLayer > 0 and layer != onlyLayer:
+                continue
+            
+            if not layer in self.layerPage:
+                continue
+            
+            panel = wx.Panel(parent=self.manageTablePage, id=wx.ID_ANY)
+            self.layerPage[layer]['tablePage'] = panel.GetId()
+            label = _("Table")
+            if not self.editable:
+                label += _(" (readonly)")
+            self.manageTablePage.AddPage(page=panel,
+                                         text=" %d / %s %s" % (layer, label,
+                                                               self.mapDBInfo.layers[layer]['table']))
+            
+            pageSizer = wx.BoxSizer(wx.VERTICAL)
+            
+            #
+            # dbInfo
+            #
+            dbBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                                          label=" %s " % _("Database connection"))
+            dbSizer = wx.StaticBoxSizer(dbBox, wx.VERTICAL)
+            dbSizer.Add(item=createDbInfoDesc(panel, self.mapDBInfo, layer),
+                        proportion=1,
+                        flag=wx.EXPAND | wx.ALL,
+                        border=3)
+            
+            #
+            # table description
+            #
+            table = self.mapDBInfo.layers[layer]['table']
+            tableBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                                    label=" %s " % _("Table <%s> - right-click to delete column(s)") % table)
+            
+            tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
+            
+            list = self._createTableDesc(panel, table)
+            list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnTableRightUp) #wxMSW
+            list.Bind(wx.EVT_RIGHT_UP,            self.OnTableRightUp) #wxGTK
+            self.layerPage[layer]['tableData'] = list.GetId()
+            
+            #
+            # add column
+            #
+            columnBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+                                     label=" %s " % _("Manage columns"))
+            
+            columnSizer = wx.StaticBoxSizer(columnBox, wx.VERTICAL)
+            
+            addSizer = wx.FlexGridSizer (cols=5, hgap=3, vgap=3)
+            addSizer.AddGrowableCol(3)
+            
+            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Column name"))
+            column = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value='',
+                                 size=(150, -1), style=wx.TE_PROCESS_ENTER)
+            column.Bind(wx.EVT_TEXT,       self.OnTableAddColumnName)
+            column.Bind(wx.EVT_TEXT_ENTER, self.OnTableItemAdd)
+            self.layerPage[layer]['addColName'] = column.GetId()
+            addSizer.Add(item=label,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            addSizer.Add(item=column,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            # data type
+            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Data type"))
+            addSizer.Add(item=label,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            
+            subSizer = wx.BoxSizer(wx.HORIZONTAL)
+            type = wx.Choice (parent=panel, id=wx.ID_ANY,
+                              choices = ["integer",
+                                         "double",
+                                         "varchar",
+                                         "date"]) # FIXME
+            type.SetSelection(0)
+            type.Bind(wx.EVT_CHOICE, self.OnTableChangeType)
+            self.layerPage[layer]['addColType'] = type.GetId()
+            subSizer.Add(item=type,
+                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+                         border=3)
+            # length
+            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Data length"))
+            length = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(65, -1),
+                                 initial=250,
+                                 min=1, max=1e6)
+            length.Enable(False)
+            self.layerPage[layer]['addColLength'] = length.GetId()
+            subSizer.Add(item=label,
+                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+                         border=3)
+            subSizer.Add(item=length,
+                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+                         border=3)
+            
+            addSizer.Add(item=subSizer,
+                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+                         border=3)
+            
+            btnAddCol = wx.Button(parent=panel, id=wx.ID_ANY, label=_("Add"))
+            btnAddCol.Bind(wx.EVT_BUTTON, self.OnTableItemAdd)
+            btnAddCol.Enable(False)
+            self.layerPage[layer]['addColButton'] = btnAddCol.GetId()
+            addSizer.Add(item=btnAddCol,
+                         proportion=0,
+                         flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE |
+                         wx.ALIGN_CENTER_VERTICAL )
+            
+            # rename col
+            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Rename column"))
+            column = wx.ComboBox(parent=panel, id=wx.ID_ANY, size=(150, -1),
+                                 style=wx.CB_SIMPLE | wx.CB_READONLY,
+                                 choices=self.mapDBInfo.GetColumns(table))
+            column.SetSelection(0)
+            self.layerPage[layer]['renameCol'] = column.GetId()
+            addSizer.Add(item=label,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            addSizer.Add(item=column,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("To"))
+            columnTo = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value='',
+                                   size=(150, -1), style=wx.TE_PROCESS_ENTER)
+            columnTo.Bind(wx.EVT_TEXT,       self.OnTableRenameColumnName)
+            columnTo.Bind(wx.EVT_TEXT_ENTER, self.OnTableItemChange)
+            self.layerPage[layer]['renameColTo'] = columnTo.GetId()
+            addSizer.Add(item=label,
+                         flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
+            addSizer.Add(item=columnTo,
+                         flag=wx.ALIGN_CENTER_VERTICAL)
+            btnRenameCol = wx.Button(parent=panel, id=wx.ID_ANY, label=_("&Rename"))
+            btnRenameCol.Bind(wx.EVT_BUTTON, self.OnTableItemChange)
+            btnRenameCol.Enable(False)
+            self.layerPage[layer]['renameColButton'] = btnRenameCol.GetId()
+            
+            addSizer.Add(item=btnRenameCol,
+                         proportion=0,
+                         flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE |
+                         wx.ALIGN_CENTER_VERTICAL)
+
+            columnSizer.Add(item=addSizer, proportion=1,
+                            flag=wx.ALL | wx.EXPAND, border=3)
+            
+            tableSizer.Add(item=list,
+                           flag=wx.ALL | wx.EXPAND,
+                           proportion=1,
+                           border=3)
+            
+            pageSizer.Add(item=dbSizer,
+                          flag=wx.ALL | wx.EXPAND,
+                          proportion=0,
+                          border=3)
+            
+            pageSizer.Add(item=tableSizer,
+                          flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                          proportion=1,
+                          border=3)
+ 
+            pageSizer.Add(item=columnSizer,
+                          flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                          proportion=0,
+                          border=3)
+            
+            panel.SetSizer(pageSizer)
+        
+        self.manageTablePage.SetSelection(0) # select first layer
+        try:
+            self.layer = self.mapDBInfo.layers.keys()[0]
+        except IndexError:
+            self.layer = None
+        
+    def _createTableDesc(self, parent, table):
+        """!Create list with table description"""
+        list = TableListCtrl(parent=parent, id=wx.ID_ANY,
+                             table=self.mapDBInfo.tables[table],
+                             columns=self.mapDBInfo.GetColumns(table))
+        list.Populate()
+        # sorter
+        # itemDataMap = list.Populate()
+        # listmix.ColumnSorterMixin.__init__(self, 2)
+
+        return list
+
+    def _createManageLayerPage(self):
+        """!Create manage page"""
+        splitterWin = wx.SplitterWindow(parent=self.manageLayerPage, id=wx.ID_ANY)
+        splitterWin.SetMinimumPaneSize(100)
+        
+        label = _("Layers of vector map")
+        if not self.editable:
+            label += _(" (readonly)")
+        self.manageLayerPage.AddPage(page=splitterWin,
+                                     text=label) # dummy page
+        
+        #
+        # list of layers
+        #
+        panelList = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
+
+        panelListSizer  = wx.BoxSizer(wx.VERTICAL)
+        layerBox = wx.StaticBox(parent=panelList, id=wx.ID_ANY,
+                                label=" %s " % _("List of layers"))
+        layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
+
+        self.layerList = self._createLayerDesc(panelList)
+        self.layerList.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnLayerRightUp) #wxMSW
+        self.layerList.Bind(wx.EVT_RIGHT_UP,            self.OnLayerRightUp) #wxGTK
+        
+        layerSizer.Add(item=self.layerList,
+                       flag=wx.ALL | wx.EXPAND,
+                       proportion=1,
+                       border=3)
+
+        panelListSizer.Add(item=layerSizer,
+                           flag=wx.ALL | wx.EXPAND,
+                           proportion=1,
+                           border=3)
+
+        panelList.SetSizer(panelListSizer)
+
+        #
+        # manage part
+        #
+        panelManage = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
+         
+        manageSizer = wx.BoxSizer(wx.VERTICAL)
+
+        self.manageLayerBook = LayerBook(parent=panelManage, id=wx.ID_ANY,
+                                         parentDialog=self)
+
+        manageSizer.Add(item=self.manageLayerBook,
+                        proportion=1,
+                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                        border=5)
+
+        panelManage.SetSizer(manageSizer)
+        splitterWin.SplitHorizontally(panelList, panelManage, 100) 
+        splitterWin.Fit()
+
+    def _createLayerDesc(self, parent):
+        """!Create list of linked layers"""
+        list = LayerListCtrl(parent=parent, id=wx.ID_ANY,
+                             layers=self.mapDBInfo.layers)
+        
+        list.Populate()
+        # sorter
+        # itemDataMap = list.Populate()
+        # listmix.ColumnSorterMixin.__init__(self, 2)
+
+        return list
+
+    def _layout(self):
+        """!Do layout"""
+        # frame body
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+
+        # buttons
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item=self.btnReload, proportion=1,
+                     flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
+        btnSizer.Add(item=self.btnQuit, proportion=1,
+                     flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
+
+        mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND)
+        mainSizer.Add(item=btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
+
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(mainSizer)
+        mainSizer.Fit(self.panel)
+        self.Layout()
+        
+    def OnDataRightUp(self, event):
+        """!Table description area, context menu"""
+        if not hasattr(self, "popupDataID1"):
+            self.popupDataID1 = wx.NewId()
+            self.popupDataID2 = wx.NewId()
+            self.popupDataID3 = wx.NewId()
+            self.popupDataID4 = wx.NewId()
+            self.popupDataID5 = wx.NewId()
+            self.popupDataID6 = wx.NewId()
+            self.popupDataID7 = wx.NewId()
+            self.popupDataID8 = wx.NewId()
+            self.popupDataID9 = wx.NewId()
+            self.popupDataID10 = wx.NewId()
+            self.popupDataID11 = wx.NewId()
+
+            self.Bind(wx.EVT_MENU, self.OnDataItemEdit,       id=self.popupDataID1)
+            self.Bind(wx.EVT_MENU, self.OnDataItemAdd,        id=self.popupDataID2)
+            self.Bind(wx.EVT_MENU, self.OnDataItemDelete,     id=self.popupDataID3)
+            self.Bind(wx.EVT_MENU, self.OnDataItemDeleteAll,  id=self.popupDataID4)
+            self.Bind(wx.EVT_MENU, self.OnDataSelectAll,      id=self.popupDataID5)
+            self.Bind(wx.EVT_MENU, self.OnDataSelectNone,     id=self.popupDataID6)
+            self.Bind(wx.EVT_MENU, self.OnDataDrawSelected,   id=self.popupDataID7)
+            self.Bind(wx.EVT_MENU, self.OnDataDrawSelectedZoom, id=self.popupDataID8)
+            self.Bind(wx.EVT_MENU, self.OnExtractSelected,    id=self.popupDataID9)
+            self.Bind(wx.EVT_MENU, self.OnDeleteSelected,     id=self.popupDataID11)
+            self.Bind(wx.EVT_MENU, self.OnDataReload,         id=self.popupDataID10)
+
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupDataID1, _("Edit selected record"))
+        selected = list.GetFirstSelected()
+        if not self.editable or selected == -1 or list.GetNextSelected(selected) != -1:
+            menu.Enable(self.popupDataID1, False)
+        menu.Append(self.popupDataID2, _("Insert new record"))
+        menu.Append(self.popupDataID3, _("Delete selected record(s)"))
+        menu.Append(self.popupDataID4, _("Delete all records"))
+        if not self.editable:
+            menu.Enable(self.popupDataID2, False)
+            menu.Enable(self.popupDataID3, False)
+            menu.Enable(self.popupDataID4, False)
+        menu.AppendSeparator()
+        menu.Append(self.popupDataID5, _("Select all"))
+        menu.Append(self.popupDataID6, _("Deselect all"))
+        menu.AppendSeparator()
+        menu.Append(self.popupDataID7, _("Highlight selected features"))
+        menu.Append(self.popupDataID8, _("Highlight selected features and zoom"))
+        if not self.map or len(list.GetSelectedItems()) == 0:
+            menu.Enable(self.popupDataID7, False)
+            menu.Enable(self.popupDataID8, False)
+        menu.Append(self.popupDataID9, _("Extract selected features"))
+        menu.Append(self.popupDataID11, _("Delete selected features"))
+        if not self.editable:
+            menu.Enable(self.popupDataID11, False)
+        if list.GetFirstSelected() == -1:
+            menu.Enable(self.popupDataID3, False)
+            menu.Enable(self.popupDataID9, False)
+            menu.Enable(self.popupDataID11, False)
+        menu.AppendSeparator()
+        menu.Append(self.popupDataID10, _("Reload"))
+
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+        # update statusbar
+        self.log.write(_("Number of loaded records: %d") % \
+                           list.GetItemCount())
+
+    def OnDataItemDelete(self, event):
+        """!Delete selected item(s) from the list (layer/category pair)"""
+        dlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+        item = dlist.GetFirstSelected()
+        
+        table    = self.mapDBInfo.layers[self.layer]["table"]
+        key      = self.mapDBInfo.layers[self.layer]["key"]
+        
+        indeces = []
+        # collect SQL statements
+        while item != -1:
+            index = dlist.itemIndexMap[item]
+            indeces.append(index)
+            
+            cat = dlist.itemCatsMap[index]
+            
+            self.listOfSQLStatements.append('DELETE FROM %s WHERE %s=%d' % \
+                                                (table, key, cat))
+            
+            item = dlist.GetNextSelected(item)
+        
+        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
+            deleteDialog = wx.MessageBox(parent=self,
+                                         message=_("Selected data records (%d) will permanently deleted "
+                                                   "from table. Do you want to delete them?") % \
+                                             (len(self.listOfSQLStatements)),
+                                         caption=_("Delete records"),
+                                         style=wx.YES_NO | wx.CENTRE)
+            if deleteDialog != wx.YES:
+                self.listOfSQLStatements = []
+                return False
+        
+        # restore maps
+        i = 0
+        indexTemp = copy.copy(dlist.itemIndexMap)
+        dlist.itemIndexMap = []
+        dataTemp = copy.deepcopy(dlist.itemDataMap)
+        dlist.itemDataMap = {}
+        catsTemp = copy.deepcopy(dlist.itemCatsMap)
+        dlist.itemCatsMap = {}
+        
+        i = 0
+        for index in indexTemp:
+            if index in indeces:
+                continue
+            dlist.itemIndexMap.append(i)
+            dlist.itemDataMap[i] = dataTemp[index]
+            dlist.itemCatsMap[i] = catsTemp[index]
+            
+            i += 1
+            
+        dlist.SetItemCount(len(dlist.itemIndexMap))
+        
+        # deselect items
+        item = dlist.GetFirstSelected()
+        while item != -1:
+            dlist.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
+            item = dlist.GetNextSelected(item)
+        
+        # submit SQL statements
+        self.ApplyCommands()
+        
+        return True
+
+    def OnDataItemDeleteAll(self, event):
+        """!Delete all items from the list"""
+        dlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
+            deleteDialog = wx.MessageBox(parent=self,
+                                         message=_("All data records (%d) will permanently deleted "
+                                                   "from table. Do you want to delete them?") % \
+                                             (len(dlist.itemIndexMap)),
+                                         caption=_("Delete records"),
+                                         style=wx.YES_NO | wx.CENTRE)
+            if deleteDialog != wx.YES:
+                return
+
+        dlist.DeleteAllItems()
+        dlist.itemDataMap  = {}
+        dlist.itemIndexMap = []
+        dlist.SetItemCount(0)
+
+        table = self.mapDBInfo.layers[self.layer]["table"]
+        self.listOfSQLStatements.append('DELETE FROM %s' % table)
+
+        self.ApplyCommands()
+        
+        event.Skip()
+
+    def _drawSelected(self, zoom):
+        """!Highlight selected features"""
+        if not self.map or not self.mapdisplay:
+            return
+        
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        cats = map(int, list.GetSelectedItems())
+
+        digitToolbar = None
+        if 'vdigit' in self.mapdisplay.toolbars:
+            digitToolbar = self.mapdisplay.toolbars['vdigit']
+        if digitToolbar and digitToolbar.GetLayer() and \
+                digitToolbar.GetLayer().GetName() == self.vectorName:
+
+            self.mapdisplay.digit.driver.SetSelected(cats, field=self.layer)
+            if zoom:
+                n, s, w, e = self.mapdisplay.digit.driver.GetRegionSelected()
+                self.mapdisplay.Map.GetRegion(n=n, s=s, w=w, e=e,
+                                              update=True)
+        else:
+            # add map layer with higlighted vector features
+            self.AddQueryMapLayer() # -> self.qlayer
+
+            # set opacity based on queried layer
+            if self.parent and self.parent.GetName() == "LayerManager" and \
+                    self.treeItem:
+                maptree = self.parent.curr_page.maptree
+                opacity = maptree.GetPyData(self.treeItem)[0]['maplayer'].GetOpacity(float=True)
+                self.qlayer.SetOpacity(opacity)
+            if zoom:
+                keyColumn = self.mapDBInfo.layers[self.layer]['key']
+                where = ''
+                for range in ListOfCatsToRange(cats).split(','):
+                    if '-' in range:
+                        min, max = range.split('-')
+                        where += '%s >= %d and %s <= %d or ' % \
+                            (keyColumn, int(min),
+                             keyColumn, int(max))
+                    else:
+                        where += '%s = %d or ' % (keyColumn, int(range))
+                where = where.rstrip('or ')
+                
+                select = RunCommand('v.db.select',
+                                    parent = self,
+                                    read = True,
+                                    quiet = True,
+                                    flags = 'r',
+                                    map = self.mapDBInfo.map,
+                                    layer = int(self.layer),
+                                    where = where)
+                
+                region = {}
+                for line in select.splitlines():
+                    key, value = line.split('=')
+                    region[key.strip()] = float(value.strip())
+                
+                self.mapdisplay.Map.GetRegion(n=region['n'], s=region['s'],
+                                              w=region['w'], e=region['e'],
+                                              update=True)
+        
+        if zoom:
+            self.mapdisplay.Map.AdjustRegion() # adjust resolution
+            self.mapdisplay.Map.AlignExtentFromDisplay() # adjust extent
+            self.mapdisplay.MapWindow.UpdateMap(render=True, renderVector=True)
+        else:
+            self.mapdisplay.MapWindow.UpdateMap(render=False, renderVector=True)
+        
+    def OnDataDrawSelected(self, event):
+        """!Reload table description"""
+        self._drawSelected(zoom=False)
+        event.Skip()
+
+    def OnDataDrawSelectedZoom(self, event):
+        self._drawSelected(zoom=True)
+        event.Skip()
+        
+    def OnDataItemAdd(self, event):
+        """!Add new record to the attribute table"""
+        list      = self.FindWindowById(self.layerPage[self.layer]['data'])
+        table     = self.mapDBInfo.layers[self.layer]['table']
+        keyColumn = self.mapDBInfo.layers[self.layer]['key']
+        
+        # (column name, value)
+        data = []
+
+        # collect names of all visible columns
+        columnName = []
+        for i in range(list.GetColumnCount()): 
+            columnName.append(list.GetColumn(i).GetText())
+
+        # maximal category number
+        if len(list.itemCatsMap.values()) > 0:
+            maxCat = max(list.itemCatsMap.values())
+        else:
+            maxCat = 0 # starting category '1'
+        
+        # key column must be always presented
+        if keyColumn not in columnName:
+            columnName.insert(0, keyColumn) # insert key column on first position
+            data.append((keyColumn, str(maxCat + 1)))
+            missingKey = True
+        else:
+            missingKey = False
+            
+        # add other visible columns
+        colIdx = 0
+        keyId = -1
+        for col in columnName:
+            if col == keyColumn: # key 
+                if missingKey is False: 
+                    data.append((col, str(maxCat + 1)))
+                    keyId = colIdx
+            else:
+                data.append((col, ''))
+            colIdx += 1
+                
+        dlg = ModifyTableRecord(parent = self,
+                                title = _("Insert new record"),
+                                data = data, keyEditable = (keyId, True))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            try: # get category number
+                cat = int(dlg.GetValues(columns=[keyColumn])[0])
+            except:
+                cat = -1
+
+            try:
+                if cat in list.itemCatsMap.values():
+                    raise ValueError(_("Record with category number %d "
+                                       "already exists in the table.") % cat)
+
+                values = dlg.GetValues() # values (need to be casted)
+                columnsString = ''
+                valuesString   = ''
+                
+                for i in range(len(values)):
+                    if len(values[i]) == 0: # NULL
+                        if columnName[i] == keyColumn:
+                            raise ValueError(_("Category number (column %s)"
+                                               " is missing.") % keyColumn)
+                        else:
+                            continue
+
+                    try:
+                        if list.columns[columnName[i]]['ctype'] == int:
+                            # values[i] is stored as text. 
+                            value = float(values[i])
+                        else:
+                            value = values[i]
+                        values[i] = list.columns[columnName[i]]['ctype'] (value)
+
+                    except:
+                        raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") % 
+                                         {'value' : str(values[i]),
+                                          'type' : list.columns[columnName[i]]['type']})
+                    columnsString += '%s,' % columnName[i]
+                    if list.columns[columnName[i]]['ctype'] == str:
+                        valuesString += "'%s'," % values[i]
+                    else:
+                        valuesString += "%s," % values[i]
+
+            except ValueError, err:
+                wx.MessageBox(parent=self,
+                              message="%s%s%s" % (_("Unable to insert new record."),
+                                                    os.linesep, err),
+                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                return
+
+            # remove category if need 
+            if missingKey is True:
+                del values[0]
+                
+            # add new item to the list
+            if len(list.itemIndexMap) > 0:
+                index = max(list.itemIndexMap) + 1
+            else:
+                index = 0
+            
+            list.itemIndexMap.append(index)
+            list.itemDataMap[index] = values
+            list.itemCatsMap[index] = cat
+            list.SetItemCount(list.GetItemCount() + 1)
+
+            self.listOfSQLStatements.append('INSERT INTO %s (%s) VALUES(%s)' % \
+                                                (table,
+                                                 columnsString.strip(','),
+                                                 valuesString.strip(',')))
+            self.ApplyCommands()
+            
+    def OnDataItemEdit(self, event):
+        """!Edit selected record of the attribute table"""
+        list      = self.FindWindowById(self.layerPage[self.layer]['data'])
+        item      = list.GetFirstSelected()
+        if item == -1:
+            return
+
+        table     = self.mapDBInfo.layers[self.layer]['table']
+        keyColumn = self.mapDBInfo.layers[self.layer]['key']
+        cat       = list.itemCatsMap[list.itemIndexMap[item]]
+
+        # (column name, value)
+        data = []
+
+        # collect names of all visible columns
+        columnName = []
+        for i in range(list.GetColumnCount()): 
+            columnName.append(list.GetColumn(i).GetText())
+
+
+        # key column must be always presented
+        if keyColumn not in columnName:
+            columnName.insert(0, keyColumn) # insert key column on first position
+            data.append((keyColumn, str(cat)))
+            keyId = 0
+            missingKey = True
+        else:
+            missingKey = False
+            
+        # add other visible columns
+        for i in range(len(columnName)):
+            if columnName[i] == keyColumn: # key 
+                if missingKey is False: 
+                    data.append((columnName[i], str(cat)))
+                    keyId = i
+            else:
+                if missingKey is True:
+                    value = list.GetItem(item, i-1).GetText()
+                else:
+                    value = list.GetItem(item, i).GetText()
+                data.append((columnName[i], value))
+
+        dlg = ModifyTableRecord(parent = self, 
+                                title = _("Update existing record"),
+                                data = data, keyEditable = (keyId, False))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            values = dlg.GetValues() # string
+            updateString = ''
+            try:
+                for i in range(len(values)): 
+                    if i == keyId: # skip key column
+                        continue
+                    if list.GetItem(item, i).GetText() != values[i]:
+                        if len(values[i]) > 0:
+                            try:
+                                if missingKey is True:
+                                    idx = i - 1
+                                else:
+                                    idx = i
+                                if list.columns[columnName[i]]['ctype'] != type(''):
+                                    if list.columns[columnName[i]]['ctype'] == int:
+                                        value = float(values[i])
+                                    else:
+                                        value = values[i]
+                                    list.itemDataMap[item][idx] = \
+                                        list.columns[columnName[i]]['ctype'] (value)
+                                else:
+                                    list.itemDataMap[item][idx] = values[i]
+                            except:
+                                raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") % \
+                                                     {'value' : str(values[i]),
+                                                      'type' : list.columns[columnName[i]]['type']})
+
+                            if list.columns[columnName[i]]['ctype'] == str:
+                                updateString += "%s='%s'," % (columnName[i], values[i])
+                            else:
+                                updateString += "%s=%s," % (columnName[i], values[i])
+                        else: # NULL
+                            updateString += "%s=NULL," % (columnName[i])
+                            
+            except ValueError, err:
+                wx.MessageBox(parent=self,
+                              message="%s%s%s" % (_("Unable to update existing record."),
+                                                  os.linesep, err),
+                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                return
+            
+            if len(updateString) > 0:
+                self.listOfSQLStatements.append('UPDATE %s SET %s WHERE %s=%d' % \
+                                                    (table, updateString.strip(','),
+                                                     keyColumn, cat))
+                self.ApplyCommands()
+
+            list.Update(self.mapDBInfo)
+                        
+    def OnDataReload(self, event):
+        """!Reload list of records"""
+        self.OnApplySqlStatement(None)
+        self.listOfSQLStatements = []
+
+    def OnDataSelectAll(self, event):
+        """!Select all items"""
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        item = -1
+
+        while True:
+            item = list.GetNextItem(item)
+            if item == -1:
+                break
+            list.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
+
+        event.Skip()
+
+    def OnDataSelectNone(self, event):
+        """!Deselect items"""
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        item = -1
+
+        while True:
+            item = list.GetNextItem(item, wx.LIST_STATE_SELECTED)
+            if item == -1:
+                break
+            list.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
+
+        event.Skip()
+
+
+    def OnTableChangeType(self, event):
+        """!Data type for new column changed. Enable or disable
+        data length widget"""
+        win = self.FindWindowById(self.layerPage[self.layer]['addColLength'])
+        if event.GetString() == "varchar":
+            win.Enable(True)
+        else:
+            win.Enable(False)
+
+    def OnTableRenameColumnName(self, event):
+        """!Editing column name to be added to the table"""
+        btn  = self.FindWindowById(self.layerPage[self.layer]['renameColButton'])
+        col  = self.FindWindowById(self.layerPage[self.layer]['renameCol'])
+        colTo = self.FindWindowById(self.layerPage[self.layer]['renameColTo'])
+        if len(col.GetValue()) > 0 and len(colTo.GetValue()) > 0:
+            btn.Enable(True)
+        else:
+            btn.Enable(False)
+
+        event.Skip()
+
+    def OnTableAddColumnName(self, event):
+        """!Editing column name to be added to the table"""
+        btn = self.FindWindowById(self.layerPage[self.layer]['addColButton'])
+        if len(event.GetString()) > 0:
+            btn.Enable(True)
+        else:
+            btn.Enable(False)
+
+        event.Skip()
+
+    def OnTableItemChange(self, event):
+        """!Rename column in the table"""
+        list   = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+        name   = self.FindWindowById(self.layerPage[self.layer]['renameCol']).GetValue()
+        nameTo = self.FindWindowById(self.layerPage[self.layer]['renameColTo']).GetValue()
+
+        table = self.mapDBInfo.layers[self.layer]["table"]
+
+        if not name or not nameTo:
+            wx.MessageBox(self=self,
+                          message=_("Unable to rename column. "
+                                    "No column name defined."),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+        else:
+            item = list.FindItem(start=-1, str=name)
+            if item > -1:
+                if list.FindItem(start=-1, str=nameTo) > -1:
+                    wx.MessageBox(parent=self,
+                                  message=_("Unable to rename column <%(column)s> to "
+                                            "<%(columnTo)s>. Column already exists "
+                                            "in the table <%(table)s>.") % \
+                                      {'column' : name, 'columnTo' : nameTo,
+                                       'table' : table},
+                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                    return
+                else:
+                    list.SetItemText(item, nameTo)
+
+                    self.listOfCommands.append(('v.db.renamecolumn',
+                                                { 'map'    : self.vectorName,
+                                                  'layer'  : self.layer,
+                                                  'column' : '%s,%s' % (name, nameTo) }
+                                                ))
+            else:
+                wx.MessageBox(parent=self,
+                              message=_("Unable to rename column. "
+                                        "Column <%(column)s> doesn't exist in the table <%(table)s>.") % 
+                              {'column' : name, 'table' : table},
+                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                return
+            
+        # apply changes
+        self.ApplyCommands()
+
+        # update widgets
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
+        self.FindWindowById(self.layerPage[self.layer]['renameColTo']).SetValue('')
+
+        event.Skip()
+
+    def OnTableRightUp(self, event):
+        """!Table description area, context menu"""
+        if not hasattr(self, "popupTableID"):
+            self.popupTableID1 = wx.NewId()
+            self.popupTableID2 = wx.NewId()
+            self.popupTableID3 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnTableItemDelete,    id=self.popupTableID1)
+            self.Bind(wx.EVT_MENU, self.OnTableItemDeleteAll, id=self.popupTableID2)
+            self.Bind(wx.EVT_MENU, self.OnTableReload,        id=self.popupTableID3)
+
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupTableID1, _("Drop selected column"))
+        if self.FindWindowById(self.layerPage[self.layer]['tableData']).GetFirstSelected() == -1:
+            menu.Enable(self.popupTableID1, False)
+        menu.Append(self.popupTableID2, _("Drop all columns"))
+        menu.AppendSeparator()
+        menu.Append(self.popupTableID3, _("Reload"))
+
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def OnTableItemDelete(self, event):
+        """!Delete selected item(s) from the list"""
+        list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+        
+        item = list.GetFirstSelected()
+        
+        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
+            deleteDialog = wx.MessageBox(parent=self,
+                                         message=_("Selected column '%s' will PERMANENTLY removed "
+                                                   "from table. Do you want to drop the column?") % \
+                                             (list.GetItemText(item)),
+                                         caption=_("Drop column(s)"),
+                                         style=wx.YES_NO | wx.CENTRE)
+            if deleteDialog != wx.YES:
+                return False
+        
+        while item != -1:
+            self.listOfCommands.append(('v.db.dropcolumn',
+                                        { 'map' : self.vectorName,
+                                          'layer' : self.layer,
+                                          'column' : list.GetItemText(item) }
+                                        ))
+            list.DeleteItem(item)
+            item = list.GetFirstSelected()
+        
+        # apply changes
+        self.ApplyCommands()
+        
+        # update widgets
+        table = self.mapDBInfo.layers[self.layer]['table']
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
+        
+        event.Skip()
+
+    def OnTableItemDeleteAll(self, event):
+        """!Delete all items from the list"""
+        table     = self.mapDBInfo.layers[self.layer]['table']
+        cols      = self.mapDBInfo.GetColumns(table)
+        keyColumn = self.mapDBInfo.layers[self.layer]['key']
+        if keyColumn in cols:
+            cols.remove(keyColumn)
+        
+        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
+            deleteDialog = wx.MessageBox(parent=self,
+                                         message=_("Selected columns\n%s\nwill PERMANENTLY removed "
+                                                   "from table. Do you want to drop the columns?") % \
+                                             ('\n'.join(cols)),
+                                         caption=_("Drop column(s)"),
+                                         style=wx.YES_NO | wx.CENTRE)
+            if deleteDialog != wx.YES:
+                return False
+        
+        for col in cols:
+            self.listOfCommands.append(('v.db.dropcolumn',
+                                        { 'map' : self.vectorName,
+                                          'layer' : self.layer,
+                                          'column' : col }
+                                        ))
+        self.FindWindowById(self.layerPage[self.layer]['tableData']).DeleteAllItems()
+
+        # apply changes
+        self.ApplyCommands()
+
+        # update widgets
+        table = self.mapDBInfo.layers[self.layer]['table']
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
+
+        event.Skip()
+
+    def OnTableReload(self, event=None):
+        """!Reload table description"""
+        self.FindWindowById(self.layerPage[self.layer]['tableData']).Populate(update=True)
+        self.listOfCommands = []
+
+    def OnTableItemAdd(self, event):
+        """!Add new column to the table"""
+	table = self.mapDBInfo.layers[self.layer]['table']
+        name = self.FindWindowById(self.layerPage[self.layer]['addColName']).GetValue()
+        
+        if not name:
+            GError(parent = self,
+                   message = _("Unable to add column to the table. "
+                               "No column name defined."))
+            return
+        
+        ctype = self.FindWindowById(self.layerPage[self.layer]['addColType']). \
+            GetStringSelection()
+        
+        # cast type if needed
+        if ctype == 'double':
+            ctype = 'double precision'
+        if ctype == 'varchar':
+            length = int(self.FindWindowById(self.layerPage[self.layer]['addColLength']). \
+                             GetValue())
+        else:
+            length = '' # FIXME
+        
+        # add item to the list of table columns
+        tlist = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+        # check for duplicate items
+        if tlist.FindItem(start=-1, str=name) > -1:
+            GError(parent = self,
+                   message = _("Column <%(column)s> already exists in table <%(table)s>.") % \
+                       {'column' : name, 'table' : self.mapDBInfo.layers[self.layer]["table"]}
+                   )
+            return
+        index = tlist.InsertStringItem(sys.maxint, str(name))
+        tlist.SetStringItem(index, 0, str(name))
+        tlist.SetStringItem(index, 1, str(ctype))
+        tlist.SetStringItem(index, 2, str(length))
+        
+        # add v.db.addcolumn command to the list
+        if ctype == 'varchar':
+            ctype += ' (%d)' % length
+        self.listOfCommands.append(('v.db.addcolumn',
+                                    { 'map'     : self.vectorName,
+                                      'layer'   : self.layer,
+                                      'columns' : '%s %s' % (name, ctype) }
+                                    ))
+        # apply changes
+        self.ApplyCommands()
+        
+        # update widgets
+        self.FindWindowById(self.layerPage[self.layer]['addColName']).SetValue('')
+	self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
+        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
+        
+        event.Skip()
+        
+    def OnLayerPageChanged(self, event):
+        """!Layer tab changed"""
+        pageNum = event.GetSelection()
+        self.layer = self.mapDBInfo.layers.keys()[pageNum]
+        
+        try:
+            idCol = self.layerPage[self.layer]['whereColumn']
+        except KeyError:
+            idCol = None
+        
+        try:
+            self.OnChangeSql(None)
+            # update statusbar
+            self.log.write(_("Number of loaded records: %d") % \
+                               self.FindWindowById(self.layerPage[self.layer]['data']).\
+                               GetItemCount())
+        except:
+            pass
+        
+        if idCol:
+            winCol = self.FindWindowById(idCol)
+            table = self.mapDBInfo.layers[self.layer]["table"]
+            self.mapDBInfo.GetColumns(table)
+        
+        event.Skip()
+        
+    def OnPageChanged(self, event):
+        try:
+            id = self.layerPage[self.layer]['data']
+        except KeyError:
+            id = None
+        
+        if event.GetSelection() == 0 and id:
+            win = self.FindWindowById(id)
+            if win:
+                self.log.write(_("Number of loaded records: %d") % win.GetItemCount())
+            else:
+                self.log.write("")
+            self.btnReload.Enable()
+        else:
+            self.log.write("")
+            self.btnReload.Enable(False)
+        
+        event.Skip()
+        
+    def OnLayerRightUp(self, event):
+        """!Layer description area, context menu"""
+        pass
+
+    def OnChangeSql(self, event):
+        """!Switch simple/advanced sql statement"""
+        if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue():
+            self.FindWindowById(self.layerPage[self.layer]['where']).Enable(True)
+            self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(False)
+            self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(False)
+        else:
+            self.FindWindowById(self.layerPage[self.layer]['where']).Enable(False)
+            self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(True)
+            self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(True)
+
+    def ApplyCommands(self):
+        """!Apply changes"""
+        # perform GRASS commands (e.g. v.db.addcolumn)
+        wx.BeginBusyCursor()
+        
+        if len(self.listOfCommands) > 0:
+            for cmd in self.listOfCommands:
+                RunCommand(prog = cmd[0],
+                           quiet = True,
+                           parent = self,
+                           **cmd[1])
+            
+            self.mapDBInfo = VectorDBInfo(self.vectorName)
+            table = self.mapDBInfo.layers[self.layer]['table']
+
+            # update table description
+            list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+            list.Update(table=self.mapDBInfo.tables[table],
+                        columns=self.mapDBInfo.GetColumns(table))
+            self.OnTableReload(None)
+
+            # update data list
+            list = self.FindWindowById(self.layerPage[self.layer]['data'])
+            list.Update(self.mapDBInfo)
+
+            # reset list of commands
+            self.listOfCommands = []
+        
+        # perform SQL non-select statements (e.g. 'delete from table where cat=1')
+        if len(self.listOfSQLStatements) > 0:
+            sqlFile = tempfile.NamedTemporaryFile(mode="wt")
+            for sql in self.listOfSQLStatements:
+                enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
+                if not enc and 'GRASS_DB_ENCODING' in os.environ:
+                    enc = os.environ['GRASS_DB_ENCODING']
+                if enc:
+                    sqlFile.file.write(sql.encode(enc) + ';')
+                else:
+                    sqlFile.file.write(sql + ';')
+                sqlFile.file.write(os.linesep)
+                sqlFile.file.flush()
+
+            driver   = self.mapDBInfo.layers[self.layer]["driver"]
+            database = self.mapDBInfo.layers[self.layer]["database"]
+            
+            Debug.msg(3, 'AttributeManger.ApplyCommands(): %s' %
+                      ';'.join(["%s" % s for s in self.listOfSQLStatements]))
+            
+            RunCommand('db.execute',
+                       parent = self,
+                       input = sqlFile.name,
+                       driver = driver,
+                       database = database)
+            
+            # reset list of statements
+            self.listOfSQLStatements = []
+            
+        wx.EndBusyCursor()
+        
+    def OnApplySqlStatement(self, event):
+        """!Apply simple/advanced sql statement"""
+        keyColumn = -1 # index of key column
+        listWin = self.FindWindowById(self.layerPage[self.layer]['data'])
+        sql = None
+        
+        wx.BeginBusyCursor()
+        
+        if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue():
+            # simple sql statement
+            whereCol = self.FindWindowById(self.layerPage[self.layer]['whereColumn']).GetStringSelection()
+            whereVal = self.FindWindowById(self.layerPage[self.layer]['where']).GetValue().strip()
+            try:
+                if len(whereVal) > 0:
+                    keyColumn = listWin.LoadData(self.layer, where=whereCol + whereVal)
+                else:
+                    keyColumn = listWin.LoadData(self.layer)
+            except GException, e:
+                GError(parent = self,
+                       message = _("Loading attribute data failed.\n\n%s") % e.value)
+                self.FindWindowById(self.layerPage[self.layer]['where']).SetValue('')
+        else:
+            # advanced sql statement
+            win = self.FindWindowById(self.layerPage[self.layer]['statement'])
+            try:
+                cols, where = self.ValidateSelectStatement(win.GetValue())
+                if cols is None and where is None:
+                    sql = win.GetValue()
+            except TypeError:
+                wx.MessageBox(parent=self,
+                              message=_("Loading attribute data failed.\n"
+                                        "Invalid SQL select statement.\n\n%s") % win.GetValue(),
+                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                win.SetValue("SELECT * FROM %s" % self.mapDBInfo.layers[self.layer]['table'])
+                cols = None
+                where = None
+            
+            if cols or where or sql:
+                try:
+                    keyColumn = listWin.LoadData(self.layer, columns=cols,
+                                                 where=where, sql=sql)
+                except GException, e:
+                    GError(parent = self,
+                           message = _("Loading attribute data failed.\n\n%s") % e.value)
+                    win.SetValue("SELECT * FROM %s" % self.mapDBInfo.layers[self.layer]['table'])
+        
+        # sort by key column
+        if sql and 'order by' in sql.lower():
+            pass # don't order by key column
+        else:
+            if keyColumn > -1:
+                listWin.SortListItems(col=keyColumn, ascending=True)
+            else:
+                listWin.SortListItems(col=0, ascending=True) 
+        
+        wx.EndBusyCursor()
+        
+        # update statusbar
+        self.log.write(_("Number of loaded records: %d") % \
+                           self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount())
+
+    def ValidateSelectStatement(self, statement):
+        """!Validate SQL select statement
+
+        @return (columns, where)
+        @return None on error
+        """
+        if statement[0:7].lower() != 'select ':
+            return None
+        
+        cols = ''
+        index = 7
+        for c in statement[index:]:
+            if c == ' ':
+                break
+            cols += c
+            index += 1
+        if cols == '*':
+            cols = None
+        else:
+            cols = cols.split(',')
+        
+        tablelen = len(self.mapDBInfo.layers[self.layer]['table'])
+        
+        if statement[index+1:index+6].lower() != 'from ' or \
+                statement[index+6:index+6+tablelen] != '%s' % \
+                (self.mapDBInfo.layers[self.layer]['table']):
+            return None
+        
+        if len(statement[index+7+tablelen:]) > 0:
+            index = statement.lower().find('where ')
+            if index > -1:
+                where = statement[index+6:]
+            else:
+                where = None
+        else:
+            where = None
+        
+        return (cols, where)
+    
+    def OnCloseWindow(self, event):
+        """!Cancel button pressed"""
+        if self.parent and self.parent.GetName() == 'LayerManager':
+            # deregister ATM
+            self.parent.dialogs['atm'].remove(self)
+                    
+        if not isinstance(event, wx.CloseEvent):
+            self.Destroy()
+        
+        event.Skip()
+
+    def OnBuilder(self,event):
+        """!SQL Builder button pressed -> show the SQLBuilder dialog"""
+        if not self.builder:
+            self.builder = SQLFrame(parent = self, id = wx.ID_ANY,
+                                    title = _("SQL Builder"),
+                                    vectmap = self.vectorName,
+                                    evtheader = self.OnBuilderEvt)
+            self.builder.Show()
+        else:
+            self.builder.Raise()
+        
+    def OnBuilderEvt(self, event):
+        if event == 'apply':
+            sqlstr = self.builder.GetSQLStatement()
+            self.FindWindowById(self.layerPage[self.layer]['statement']).SetValue(sqlstr)
+            if self.builder.CloseOnApply():
+                self.builder = None
+        elif event == 'close':
+            self.builder = None
+        
+    def OnTextEnter(self, event):
+        pass
+    
+    def OnDataItemActivated(self, event):
+        """!Item activated, highlight selected item"""
+        self.OnDataDrawSelected(event)
+
+        event.Skip()
+
+    def OnExtractSelected(self, event):
+        """!Extract vector objects selected in attribute browse window
+        to new vector map
+        """
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        # cats = list.selectedCats[:]
+        cats = list.GetSelectedItems()
+        if len(cats) == 0:
+            wx.MessageBox(parent=self,
+                          message=_('Nothing to extract.'),
+                          caption=_('Message'), style=wx.CENTRE)
+            return
+        else:
+            # dialog to get file name
+            dlg = CreateNewVector(parent = self, title = _('Extract selected features'),
+                                  log = self.cmdLog,
+                                  cmd = (('v.extract',
+                                          { 'input' : self.vectorName,
+                                            'cats' : ListOfCatsToRange(cats) },
+                                          'output')),
+                                  disableTable = True)
+            if not dlg:
+                return
+            
+            name = dlg.GetName(full = True)
+            if name and dlg.IsChecked('add'):
+                # add layer to map layer tree
+                self.parent.curr_page.maptree.AddLayer(ltype = 'vector',
+                                                       lname = name,
+                                                       lcmd = ['d.vect', 'map=%s' % name])
+            dlg.Destroy()
+            
+    def OnDeleteSelected(self, event):
+        """!Delete vector objects selected in attribute browse window
+        (attribures and geometry)
+        """
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        cats = list.GetSelectedItems()
+        if len(cats) == 0:
+            wx.MessageBox(parent=self,
+                          message=_('Nothing to delete.'),
+                          caption=_('Message'), style=wx.CENTRE)
+        
+        if self.OnDataItemDelete(None):
+            digitToolbar = self.mapdisplay.toolbars['vdigit']
+            if digitToolbar and digitToolbar.GetLayer() and \
+                    digitToolbar.GetLayer().GetName() == self.vectorName:
+                self.mapdisplay.digit.driver.SetSelected(map(int, cats), field=self.layer)
+                self.mapdisplay.digit.DeleteSelectedLines()
+            else:
+                RunCommand('v.edit',
+                           parent = self,
+                           quiet = True,
+                           map = self.vectorName,
+                           tool = 'delete',
+                           cats = ListOfCatsToRange(cats))
+                
+            self.mapdisplay.MapWindow.UpdateMap(render=True, renderVector=True)
+        
+    def AddQueryMapLayer(self):
+        """!Redraw a map
+
+        Return True if map has been redrawn, False if no map is given
+        """
+        list = self.FindWindowById(self.layerPage[self.layer]['data'])
+        cats = { 
+            self.layer : list.GetSelectedItems()
+            }
+        
+        if self.mapdisplay.Map.GetLayerIndex(self.qlayer) < 0:
+            self.qlayer = None
+            
+        if self.qlayer:
+            self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats, addLayer=False))
+        else:
+            self.qlayer = self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats)
+
+        return self.qlayer
+    
+    def UpdateDialog(self, layer):
+        """!Updates dialog layout for given layer"""
+        # delete page
+        if layer in self.mapDBInfo.layers.keys():
+            # delete page
+            # draging pages disallowed
+            # if self.browsePage.GetPageText(page).replace('Layer ', '').strip() == str(layer):
+            # self.browsePage.DeletePage(page)
+            # break
+            self.browsePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
+            self.manageTablePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
+            # set current page selection
+            self.notebook.SetSelectionByName('layers')
+            
+        # fetch fresh db info
+        self.mapDBInfo = VectorDBInfo(self.vectorName)    
+
+        #
+        # add new page
+        #
+        if layer in self.mapDBInfo.layers.keys():
+            # 'browse data' page
+            self._createBrowsePage(layer)
+            # 'manage tables' page
+            self._createManageTablePage(layer)
+            # set current page selection
+            self.notebook.SetSelectionByName('layers')
+            
+        #
+        # 'manage layers' page
+        #
+        # update list of layers
+        self.layerList.Update(self.mapDBInfo.layers)
+        self.layerList.Populate(update=True)
+        # update selected widgets
+        listOfLayers = map(str, self.mapDBInfo.layers.keys())
+        ### delete layer page
+        self.manageLayerBook.deleteLayer.SetItems(listOfLayers)
+        if len(listOfLayers) > 0:
+            self.manageLayerBook.deleteLayer.SetStringSelection(listOfLayers[0])
+            tableName = self.mapDBInfo.layers[int(listOfLayers[0])]['table']
+            maxLayer = max(self.mapDBInfo.layers.keys())
+        else:
+            tableName = ''
+            maxLayer = 0
+        self.manageLayerBook.deleteTable.SetLabel( \
+            _('Drop also linked attribute table (%s)') % \
+                tableName)
+        ### add layer page
+        self.manageLayerBook.addLayerWidgets['layer'][1].SetValue(\
+            maxLayer+1)
+        ### modify layer
+        self.manageLayerBook.modifyLayerWidgets['layer'][1].SetItems(listOfLayers)
+        self.manageLayerBook.OnChangeLayer(event=None)
+
+    def GetVectorName(self):
+        """!Get vector name"""
+        return self.vectorName
+    
+    def LoadData(self, layer, columns=None, where=None, sql=None):
+        """!Load data into list
+
+        @param layer layer number
+        @param columns list of columns for output
+        @param where where statement
+        @param sql full sql statement
+
+        @return id of key column 
+        @return -1 if key column is not displayed
+        """
+        listWin = self.FindWindowById(self.layerPage[layer]['data'])
+        return listWin.LoadData(layer, columns, where, sql)
+    
+class TableListCtrl(wx.ListCtrl,
+                    listmix.ListCtrlAutoWidthMixin):
+                    #                    listmix.TextEditMixin):
+    """!Table description list"""
+
+    def __init__(self, parent, id, table, columns, pos=wx.DefaultPosition,
+                 size=wx.DefaultSize):
+
+        self.parent  = parent
+        self.table   = table
+        self.columns = columns
+        wx.ListCtrl.__init__(self, parent, id, pos, size,
+                             style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
+                             wx.BORDER_NONE)
+
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        # listmix.TextEditMixin.__init__(self)
+
+    def Update(self, table, columns):
+        """!Update column description"""
+        self.table   = table
+        self.columns = columns
+
+    def Populate(self, update=False):
+        """!Populate the list"""
+        itemData = {} # requested by sorter
+
+        if not update:
+            headings = [_("Column name"), _("Data type"), _("Data length")]
+            i = 0
+            for h in headings:
+                self.InsertColumn(col=i, heading=h)
+                self.SetColumnWidth(col=i, width=150)
+                i += 1
+        else:
+            self.DeleteAllItems()
+
+        i = 0
+        for column in self.columns:
+            index = self.InsertStringItem(sys.maxint, str(column))
+            self.SetStringItem(index, 0, str(column))
+            self.SetStringItem(index, 1, str(self.table[column]['type']))
+            self.SetStringItem(index, 2, str(self.table[column]['length']))
+            self.SetItemData(index, i)
+            itemData[i] = (str(column),
+                           str(self.table[column]['type']),
+                           int(self.table[column]['length']))
+            i = i + 1
+
+        self.SendSizeEvent()
+        
+        return itemData
+
+class LayerListCtrl(wx.ListCtrl,
+                    listmix.ListCtrlAutoWidthMixin):
+                    # listmix.ColumnSorterMixin):
+                    # listmix.TextEditMixin):
+    """!Layer description list"""
+
+    def __init__(self, parent, id, layers,
+                 pos=wx.DefaultPosition,
+                 size=wx.DefaultSize):
+
+        self.parent = parent
+        self.layers = layers
+        wx.ListCtrl.__init__(self, parent, id, pos, size,
+                             style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
+                             wx.BORDER_NONE)
+
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        # listmix.TextEditMixin.__init__(self)
+
+    def Update(self, layers):
+        """!Update description"""
+        self.layers = layers
+
+    def Populate(self, update=False):
+        """!Populate the list"""
+        itemData = {} # requested by sorter
+
+        if not update:
+            headings = [_("Layer"),  _("Driver"), _("Database"), _("Table"), _("Key")]
+            i = 0
+            for h in headings:
+                self.InsertColumn(col=i, heading=h)
+                i += 1
+        else:
+            self.DeleteAllItems()
+
+        i = 0
+        for layer in self.layers.keys():
+            index = self.InsertStringItem(sys.maxint, str(layer))
+            self.SetStringItem(index, 0, str(layer))
+            database = str(self.layers[layer]['database'])
+            driver   = str(self.layers[layer]['driver'])
+            table    = str(self.layers[layer]['table'])
+            key      = str(self.layers[layer]['key'])
+            self.SetStringItem(index, 1, driver)
+            self.SetStringItem(index, 2, database)
+            self.SetStringItem(index, 3, table)
+            self.SetStringItem(index, 4, key)
+            self.SetItemData(index, i)
+            itemData[i] = (str(layer),
+                           driver,
+                           database,
+                           table,
+                           key)
+            i += 1
+
+        for i in range(self.GetColumnCount()):
+            self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE)
+            if self.GetColumnWidth(col=i) < 60:
+                self.SetColumnWidth(col=i, width=60)
+
+        self.SendSizeEvent()
+        
+        return itemData
+
+class LayerBook(wx.Notebook):
+    """!Manage layers (add, delete, modify)"""
+    def __init__(self, parent, id,
+                 parentDialog,
+                 style=wx.BK_DEFAULT):
+        wx.Notebook.__init__(self, parent, id, style=style)
+
+        self.parent       = parent
+        self.parentDialog = parentDialog
+        self.mapDBInfo    = self.parentDialog.mapDBInfo
+
+        #
+        # drivers
+        #
+        drivers = RunCommand('db.drivers',
+                             quiet = True,
+                             read = True,
+                             flags = 'p')
+        
+        self.listOfDrivers = []
+        for drv in drivers.splitlines():
+            self.listOfDrivers.append(drv.strip())
+        
+        #
+        # get default values
+        #
+        self.defaultConnect = {}
+        connect = RunCommand('db.connect',
+                             flags = 'p',
+                             read = True,
+                             quiet = True)
+        
+        for line in connect.splitlines():
+            item, value = line.split(':', 1)
+            self.defaultConnect[item.strip()] = value.strip()
+        
+        if len(self.defaultConnect['driver']) == 0 or \
+               len(self.defaultConnect['database']) == 0:
+            wx.MessageBox(parent=self.parent,
+                          message=_("Unknown default DB connection. "
+                                    "Please define DB connection using db.connect module."),
+                          caption=_("Warning"),
+                          style=wx.OK | wx.ICON_WARNING | wx.CENTRE)
+        
+        self.defaultTables = self._getTables(self.defaultConnect['driver'],
+                                              self.defaultConnect['database'])
+        try:
+            self.defaultColumns = self._getColumns(self.defaultConnect['driver'],
+                                                    self.defaultConnect['database'],
+                                                    self.defaultTables[0])
+        except IndexError:
+            self.defaultColumns = []
+
+        self._createAddPage()
+        self._createDeletePage()
+        self._createModifyPage()
+
+    def _createAddPage(self):
+        """!Add new layer"""
+        self.addPanel = wx.Panel(parent=self, id=wx.ID_ANY)
+        self.AddPage(page=self.addPanel, text=_("Add layer"))
+        
+        try:
+            maxLayer = max(self.mapDBInfo.layers.keys())
+        except ValueError:
+            maxLayer = 0
+
+        # layer description
+        
+        layerBox = wx.StaticBox (parent=self.addPanel, id=wx.ID_ANY,
+                                 label=" %s " % (_("Layer description")))
+        layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
+        
+        #
+        # list of layer widgets (label, value)
+        #
+        self.addLayerWidgets = {'layer':
+                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Layer")),
+                                     wx.SpinCtrl(parent=self.addPanel, id=wx.ID_ANY, size=(65, -1),
+                                                 initial=maxLayer+1,
+                                                 min=1, max=1e6)),
+                                'driver':
+                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Driver")),
+                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
+                                               choices=self.listOfDrivers)),
+                                'database':
+                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Database")),
+                                     wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
+                                                 value='',
+                                                 style=wx.TE_PROCESS_ENTER)),
+                                'table':
+                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Table")),
+                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
+                                               choices=self.defaultTables)),
+                                'key':
+                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Key column")),
+                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
+                                               choices=self.defaultColumns)),
+                                'addCat':
+                                    (wx.CheckBox(parent=self.addPanel, id=wx.ID_ANY,
+                                                 label=_("Insert record for each category into table")),
+                                     None),
+                                }
+        
+        # set default values for widgets
+        self.addLayerWidgets['driver'][1].SetStringSelection(self.defaultConnect['driver'])
+        self.addLayerWidgets['database'][1].SetValue(self.defaultConnect['database'])
+        self.addLayerWidgets['table'][1].SetSelection(0)
+        self.addLayerWidgets['key'][1].SetSelection(0)
+        # events
+        self.addLayerWidgets['driver'][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
+        self.addLayerWidgets['database'][1].Bind(wx.EVT_TEXT_ENTER, self.OnDatabaseChanged)
+        self.addLayerWidgets['table'][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
+        
+        # tooltips
+        self.addLayerWidgets['addCat'][0].SetToolTipString(_("You need to add categories "
+                                                             "by v.category module."))
+        #
+        # list of table widgets
+        #
+        keyCol = UserSettings.Get(group='atm', key='keycolumn', subkey='value')
+        self.tableWidgets = {'table': (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                     label='%s:' % _("Table name")),
+                                       wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
+                                                   value='',
+                                                   style=wx.TE_PROCESS_ENTER)),
+                             'key': (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
+                                                   label='%s:' % _("Key column")),
+                                     wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
+                                                 value=keyCol,
+                                                 style=wx.TE_PROCESS_ENTER))}
+        # events
+        self.tableWidgets['table'][1].Bind(wx.EVT_TEXT_ENTER, self.OnCreateTable)
+        self.tableWidgets['key'][1].Bind(wx.EVT_TEXT_ENTER, self.OnCreateTable)
+        
+        btnTable   = wx.Button(self.addPanel, wx.ID_ANY, _("&Create table"),
+                             size=(125,-1))
+        btnTable.Bind(wx.EVT_BUTTON, self.OnCreateTable)
+        
+        btnLayer   = wx.Button(self.addPanel, wx.ID_ANY, _("&Add layer"),
+                             size=(125,-1))
+        btnLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
+        
+        btnDefault = wx.Button(self.addPanel, wx.ID_ANY, _("&Set default"),
+                               size=(125,-1))
+        btnDefault.Bind(wx.EVT_BUTTON, self.OnSetDefault)
+        
+        # do layout
+        
+        pageSizer = wx.BoxSizer(wx.HORIZONTAL)
+                
+        # data area
+        dataSizer = wx.GridBagSizer(hgap=5, vgap=5)
+        dataSizer.AddGrowableCol(1)
+        row = 0
+        for key in ('layer', 'driver', 'database', 'table', 'key', 'addCat'):
+            label, value = self.addLayerWidgets[key]
+            if not value:
+                span = (1, 2)
+            else:
+                span = (1, 1)
+            dataSizer.Add(item=label,
+                          flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0),
+                          span=span)
+            
+            if not value:
+                row += 1
+                continue
+
+            if label.GetLabel() == "Layer:":
+                style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT
+            else:
+                style = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND
+            
+            dataSizer.Add(item=value,
+                          flag=style, pos=(row, 1))
+            
+            row += 1
+        
+        layerSizer.Add(item=dataSizer,
+                       proportion=1,
+                       flag=wx.ALL | wx.EXPAND,
+                       border=5)
+        
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item=btnDefault,
+                     proportion=0,
+                     flag=wx.ALL | wx.ALIGN_LEFT,
+                     border=5)
+        
+        btnSizer.Add(item=(5, 5),
+                     proportion=1,
+                     flag=wx.ALL | wx.EXPAND,
+                     border=5)
+        
+        btnSizer.Add(item=btnLayer,
+                     proportion=0,
+                     flag=wx.ALL | wx.ALIGN_RIGHT,
+                     border=5)
+        
+        layerSizer.Add(item=btnSizer,
+                       proportion=0,
+                       flag=wx.ALL | wx.EXPAND,
+                       border=0)
+                
+        # table description
+        tableBox = wx.StaticBox (parent=self.addPanel, id=wx.ID_ANY,
+                                 label=" %s " % (_("Table description")))
+        tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
+        
+        # data area
+        dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
+        dataSizer.AddGrowableCol(1)
+        for key in ['table', 'key']:
+            label, value = self.tableWidgets[key]
+            dataSizer.Add(item=label,
+                          flag=wx.ALIGN_CENTER_VERTICAL)
+            dataSizer.Add(item=value,
+                          flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+
+        tableSizer.Add(item=dataSizer,
+                       proportion=1,
+                       flag=wx.ALL | wx.EXPAND,
+                       border=5)
+
+        tableSizer.Add(item=btnTable,
+                       proportion=0,
+                       flag=wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT,
+                       border=5)
+
+        pageSizer.Add(item=layerSizer,
+                      proportion=3,
+                      flag=wx.ALL | wx.EXPAND,
+                      border=3)
+        
+        pageSizer.Add(item=tableSizer,
+                      proportion=2,
+                      flag=wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND,
+                      border=3)
+        
+        self.addPanel.SetAutoLayout(True)
+        self.addPanel.SetSizer(pageSizer)
+        pageSizer.Fit(self.addPanel)
+        
+    def _createDeletePage(self):
+        """!Delete layer"""
+        self.deletePanel = wx.Panel(parent=self, id=wx.ID_ANY)
+        self.AddPage(page=self.deletePanel, text=_("Remove layer"))
+
+        label = wx.StaticText(parent=self.deletePanel, id=wx.ID_ANY,
+                              label='%s:' % _("Layer to remove"))
+
+        self.deleteLayer = wx.ComboBox(parent=self.deletePanel, id=wx.ID_ANY, size=(100, -1),
+                                       style=wx.CB_SIMPLE | wx.CB_READONLY,
+                                       choices=map(str, self.mapDBInfo.layers.keys()))
+        self.deleteLayer.SetSelection(0)           
+        self.deleteLayer.Bind(wx.EVT_COMBOBOX, self.OnChangeLayer)
+
+        try:
+            tableName = self.mapDBInfo.layers[int(self.deleteLayer.GetStringSelection())]['table']
+        except ValueError:
+            tableName = ''
+            
+        self.deleteTable = wx.CheckBox(parent=self.deletePanel, id=wx.ID_ANY,
+                                       label=_('Drop also linked attribute table (%s)') % \
+                                       tableName)
+
+        if tableName == '':
+            self.deleteLayer.Enable(False)
+            self.deleteTable.Enable(False)
+            
+        btnDelete   = wx.Button(self.deletePanel, wx.ID_DELETE, _("&Remove layer"),
+                                size=(125,-1))
+        btnDelete.Bind(wx.EVT_BUTTON, self.OnDeleteLayer)
+
+        #
+        # do layout
+        #
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+
+        dataSizer = wx.BoxSizer(wx.VERTICAL)
+
+        flexSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
+        flexSizer.AddGrowableCol(2)
+
+        flexSizer.Add(item=label,
+                      flag=wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item=self.deleteLayer,
+                      flag=wx.ALIGN_CENTER_VERTICAL)
+
+        dataSizer.Add(item=flexSizer,
+                      proportion=0,
+                      flag=wx.ALL | wx.EXPAND,
+                      border=1)
+
+        dataSizer.Add(item=self.deleteTable,
+                      proportion=0,
+                      flag=wx.ALL | wx.EXPAND,
+                      border=1)
+
+        pageSizer.Add(item=dataSizer,
+                      proportion=1,
+                      flag=wx.ALL | wx.EXPAND,
+                      border=5)
+
+        pageSizer.Add(item=btnDelete,
+                      proportion=0,
+                      flag=wx.ALL | wx.ALIGN_RIGHT,
+                      border=5)
+
+        self.deletePanel.SetSizer(pageSizer)
+
+    def _createModifyPage(self):
+        """!Modify layer"""
+        self.modifyPanel = wx.Panel(parent=self, id=wx.ID_ANY)
+        self.AddPage(page=self.modifyPanel, text=_("Modify layer"))
+
+        #
+        # list of layer widgets (label, value)
+        #
+        self.modifyLayerWidgets = {'layer':
+                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                      label='%s:' % _("Layer")),
+                                        wx.ComboBox(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                    size=(100, -1),
+                                                    style=wx.CB_SIMPLE | wx.CB_READONLY,
+                                                    choices=map(str, 
+                                                                self.mapDBInfo.layers.keys()))),
+                                   'driver':
+                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                      label='%s:' % _("Driver")),
+                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                  size=(200, -1),
+                                                  choices=self.listOfDrivers)),
+                                   'database':
+                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                      label='%s:' % _("Database")),
+                                        wx.TextCtrl(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                    value='', size=(350, -1),
+                                                    style=wx.TE_PROCESS_ENTER)),
+                                   'table':
+                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                      label='%s:' % _("Table")),
+                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                  size=(200, -1),
+                                                  choices=self.defaultTables)),
+                                   'key':
+                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                      label='%s:' % _("Key column")),
+                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
+                                                  size=(200, -1),
+                                                  choices=self.defaultColumns))}
+        
+        # set default values for widgets
+        self.modifyLayerWidgets['layer'][1].SetSelection(0)
+        try:
+            layer = int(self.modifyLayerWidgets['layer'][1].GetStringSelection())
+        except ValueError:
+            layer = None
+            for label in self.modifyLayerWidgets.keys():
+                self.modifyLayerWidgets[label][1].Enable(False)
+
+        if layer:
+            driver   = self.mapDBInfo.layers[layer]['driver']
+            database = self.mapDBInfo.layers[layer]['database']
+            table    = self.mapDBInfo.layers[layer]['table']
+
+            listOfColumns = self._getColumns(driver, database, table)
+            self.modifyLayerWidgets['driver'][1].SetStringSelection(driver)
+            self.modifyLayerWidgets['database'][1].SetValue(database)
+            if table in self.modifyLayerWidgets['table'][1].GetItems():
+                self.modifyLayerWidgets['table'][1].SetStringSelection(table)
+            else:
+                if self.defaultConnect['schema'] != '':
+                    table = self.defaultConnect['schema'] + table # try with default schema
+                else:
+                    table = 'public.' + table # try with 'public' schema
+                self.modifyLayerWidgets['table'][1].SetStringSelection(table)
+            self.modifyLayerWidgets['key'][1].SetItems(listOfColumns)
+            self.modifyLayerWidgets['key'][1].SetSelection(0)
+
+        # events
+        self.modifyLayerWidgets['layer'][1].Bind(wx.EVT_COMBOBOX, self.OnChangeLayer)
+        # self.modifyLayerWidgets['driver'][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
+        # self.modifyLayerWidgets['database'][1].Bind(wx.EVT_TEXT_ENTER, self.OnDatabaseChanged)
+        # self.modifyLayerWidgets['table'][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
+
+        btnModify = wx.Button(self.modifyPanel, wx.ID_DELETE, _("&Modify layer"),
+                              size=(125,-1))
+        btnModify.Bind(wx.EVT_BUTTON, self.OnModifyLayer)
+
+        #
+        # do layout
+        #
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+
+        # data area
+        dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
+        dataSizer.AddGrowableCol(1)
+        for key in ('layer', 'driver', 'database', 'table', 'key'):
+            label, value = self.modifyLayerWidgets[key]
+            dataSizer.Add(item=label,
+                          flag=wx.ALIGN_CENTER_VERTICAL)
+            if label.GetLabel() == "Layer:":
+                dataSizer.Add(item=value,
+                              flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+            else:
+                dataSizer.Add(item=value,
+                              flag=wx.ALIGN_CENTER_VERTICAL)
+
+        pageSizer.Add(item=dataSizer,
+                      proportion=1,
+                      flag=wx.ALL | wx.EXPAND,
+                      border=5)
+
+        pageSizer.Add(item=btnModify,
+                      proportion=0,
+                      flag=wx.ALL | wx.ALIGN_RIGHT,
+                      border=5)
+
+        self.modifyPanel.SetSizer(pageSizer)
+
+    def _getTables(self, driver, database):
+        """!Get list of tables for given driver and database"""
+        tables = []
+
+        ret = RunCommand('db.tables',
+                         parent = self,
+                         read = True,
+                         flags = 'p',
+                         driver = driver,
+                         database = database)
+        
+        if ret is None:
+            wx.MessageBox(parent=self,
+                          message=_("Unable to get list of tables.\n"
+                                    "Please use db.connect to set database parameters."),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            
+            return tables
+        
+        for table in ret.splitlines():
+            tables.append(table)
+        
+        return tables
+
+    def _getColumns(self, driver, database, table):
+        """!Get list of column of given table"""
+        columns = []
+
+        ret = RunCommand('db.columns',
+                         parent = self,
+                         quiet = True,
+                         read = True,
+                         driver = driver,
+                         database = database,
+                         table = table)
+        
+        if ret == None:
+            return columns
+        
+        for column in ret.splitlines():
+            columns.append(column)
+        
+        return columns
+
+    def OnDriverChanged(self, event):
+        """!Driver selection changed, update list of tables"""
+        driver = event.GetString()
+        database = self.addLayerWidgets['database'][1].GetValue()
+
+        winTable = self.addLayerWidgets['table'][1]
+        winKey   = self.addLayerWidgets['key'][1]
+        tables   = self._getTables(driver, database)
+
+        winTable.SetItems(tables)
+        winTable.SetSelection(0)
+
+        if len(tables) == 0:
+            winKey.SetItems([])
+
+        event.Skip()
+
+    def OnDatabaseChanged(self, event):
+        """!Database selection changed, update list of tables"""
+        event.Skip()
+
+    def OnTableChanged(self, event):
+        """!Table name changed, update list of columns"""
+        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
+        database = self.addLayerWidgets['database'][1].GetValue()
+        table    = event.GetString()
+
+        win  = self.addLayerWidgets['key'][1]
+        cols = self._getColumns(driver, database, table)
+        win.SetItems(cols)
+        win.SetSelection(0)
+
+        event.Skip()
+
+    def OnSetDefault(self, event):
+        """!Set default values"""
+        driver   = self.addLayerWidgets['driver'][1]
+        database = self.addLayerWidgets['database'][1]
+        table    = self.addLayerWidgets['table'][1]
+        key      = self.addLayerWidgets['key'][1]
+
+        driver.SetStringSelection(self.defaultConnect['driver'])
+        database.SetValue(self.defaultConnect['database'])
+        tables = self._getTables(self.defaultConnect['driver'],
+                                  self.defaultConnect['database'])
+        table.SetItems(tables)
+        table.SetSelection(0)
+        if len(tables) == 0:
+            key.SetItems([])
+        else:
+            cols = self._getColumns(self.defaultConnect['driver'],
+                                     self.defaultConnect['database'],
+                                     tables[0])
+            key.SetItems(cols)
+            key.SetSelection(0)
+
+        event.Skip()
+
+    def OnCreateTable(self, event):
+        """!Create new table (name and key column given)"""
+        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
+        database = self.addLayerWidgets['database'][1].GetValue()
+        table    = self.tableWidgets['table'][1].GetValue()
+        key      = self.tableWidgets['key'][1].GetValue()
+        
+        if not table or not key:
+            wx.MessageBox(parent=self,
+                          message=_("Unable to create new table. "
+                                    "Table name or key column name is missing."),
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+
+        if table in self.addLayerWidgets['table'][1].GetItems():
+            wx.MessageBox(parent=self,
+                          message=_("Unable to create new table. "
+                                    "Table <%s> already exists in the database.") % table,
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+        
+        # create table
+        sql = 'CREATE TABLE %s (%s INTEGER)' % (table, key)
+
+        RunCommand('db.execute',
+                   quiet = True,
+                   parent = self,
+                   stdin = sql,
+                   input = '-',
+                   driver = driver,
+                   database = database)
+        
+        # update list of tables
+        tableList = self.addLayerWidgets['table'][1]
+        tableList.SetItems(self._getTables(driver, database))
+        tableList.SetStringSelection(table)
+
+        # update key column selection
+        keyList = self.addLayerWidgets['key'][1]
+        keyList.SetItems(self._getColumns(driver, database, table))
+        keyList.SetStringSelection(key)
+        
+        event.Skip()
+
+    def OnAddLayer(self, event):
+        """!Add new layer to vector map"""
+        layer    = int(self.addLayerWidgets['layer'][1].GetValue())
+        layerWin = self.addLayerWidgets['layer'][1]
+        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
+        database = self.addLayerWidgets['database'][1].GetValue()
+        table    = self.addLayerWidgets['table'][1].GetStringSelection()
+        key      = self.addLayerWidgets['key'][1].GetStringSelection()
+        
+        if layer in self.mapDBInfo.layers.keys():
+            wx.MessageBox(parent=self,
+                          message=_("Unable to add new layer to vector map <%(vector)s>. "
+                                    "Layer %(layer)d already exists.") % 
+                          {'vector' : self.mapDBInfo.map, 'layer' : layer},
+                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return
+
+        # add new layer
+        ret = RunCommand('v.db.connect',
+                         parent = self,
+                         quiet = True,
+                         map = self.mapDBInfo.map,
+                         driver = driver,
+                         database = database,
+                         table = table,
+                         key = key,
+                         layer = layer)
+        
+        # insert records into table if required
+        if self.addLayerWidgets['addCat'][0].IsChecked():
+            RunCommand('v.to.db',
+                       parent = self,
+                       quiet = True,
+                       map = self.mapDBInfo.map,
+                       layer = layer,
+                       qlayer = layer,
+                       option = 'cat',
+                       columns = key)
+
+        if ret == 0:
+            # update dialog (only for new layer)
+            self.parentDialog.UpdateDialog(layer=layer) 
+            # update db info
+            self.mapDBInfo = self.parentDialog.mapDBInfo
+            # increase layer number
+            layerWin.SetValue(layer+1)
+
+        if len(self.mapDBInfo.layers.keys()) == 1:
+            # first layer add --- enable previously disabled widgets
+            self.deleteLayer.Enable()
+            self.deleteTable.Enable()
+            for label in self.modifyLayerWidgets.keys():
+                self.modifyLayerWidgets[label][1].Enable()
+            
+    def OnDeleteLayer(self, event):
+        """!Delete layer"""
+        try:
+            layer = int(self.deleteLayer.GetValue())
+        except:
+            return
+
+        RunCommand('v.db.connect',
+                   parent = self,
+                   flags = 'd',
+                   map = self.mapDBInfo.map,
+                   layer = layer)
+
+        # drop also table linked to layer which is deleted
+        if self.deleteTable.IsChecked():
+            driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
+            database = self.addLayerWidgets['database'][1].GetValue()
+            table    = self.mapDBInfo.layers[layer]['table']
+            sql      = 'DROP TABLE %s' % (table)
+
+            RunCommand('db.execute',
+                       parent = self,
+                       stdin = sql,
+                       quiet = True,
+                       driver = driver,
+                       database = database)
+            
+            # update list of tables
+            tableList = self.addLayerWidgets['table'][1]
+            tableList.SetItems(self._getTables(driver, database))
+            tableList.SetStringSelection(table)
+        
+        # update dialog
+        self.parentDialog.UpdateDialog(layer=layer) 
+        # update db info
+        self.mapDBInfo = self.parentDialog.mapDBInfo
+
+        if len(self.mapDBInfo.layers.keys()) == 0:
+            # disable selected widgets
+            self.deleteLayer.Enable(False)
+            self.deleteTable.Enable(False)
+            for label in self.modifyLayerWidgets.keys():
+                self.modifyLayerWidgets[label][1].Enable(False)
+            
+        event.Skip()
+
+    def OnChangeLayer(self, event):
+        """!Layer number of layer to be deleted is changed"""
+        try:
+            layer = int(event.GetString())
+        except:
+            try:
+                layer = self.mapDBInfo.layers.keys()[0]
+            except:
+                return
+
+        if self.GetCurrentPage() == self.modifyPanel:
+            driver   = self.mapDBInfo.layers[layer]['driver']
+            database = self.mapDBInfo.layers[layer]['database']
+            table    = self.mapDBInfo.layers[layer]['table']
+            listOfColumns = self._getColumns(driver, database, table)
+            self.modifyLayerWidgets['driver'][1].SetStringSelection(driver)
+            self.modifyLayerWidgets['database'][1].SetValue(database)
+            self.modifyLayerWidgets['table'][1].SetStringSelection(table)
+            self.modifyLayerWidgets['key'][1].SetItems(listOfColumns)
+            self.modifyLayerWidgets['key'][1].SetSelection(0)
+        else:
+            self.deleteTable.SetLabel(_('Drop also linked attribute table (%s)') % \
+                                          self.mapDBInfo.layers[layer]['table'])
+        if event:
+            event.Skip()
+
+    def OnModifyLayer(self, event):
+        """!Modify layer connection settings"""
+
+        layer = int(self.modifyLayerWidgets['layer'][1].GetStringSelection())
+
+        modify = False
+        if self.modifyLayerWidgets['driver'][1].GetStringSelection() != \
+                self.mapDBInfo.layers[layer]['driver'] or \
+                self.modifyLayerWidgets['database'][1].GetStringSelection() != \
+                self.mapDBInfo.layers[layer]['database'] or \
+                self.modifyLayerWidgets['table'][1].GetStringSelection() != \
+                self.mapDBInfo.layers[layer]['table'] or \
+                self.modifyLayerWidgets['key'][1].GetStringSelection() != \
+                self.mapDBInfo.layers[layer]['key']:
+            modify = True
+
+        if modify:
+            # delete layer
+            RunCommand('v.db.connect',
+                       parent = self,
+                       quiet = True,
+                       flag = 'd',
+                       map = self.mapDBInfo.map,
+                       layer = layer)
+
+            # add modified layer
+            RunCommand('v.db.connect',
+                       quiet = True,
+                       map = self.mapDBInfo.map,
+                       driver = self.modifyLayerWidgets['driver'][1].GetStringSelection(),
+                       database = self.modifyLayerWidgets['database'][1].GetValue(),
+                       table = self.modifyLayerWidgets['table'][1].GetStringSelection(),
+                       key = self.modifyLayerWidgets['key'][1].GetStringSelection(),
+                       layer = int(layer))
+            
+            # update dialog (only for new layer)
+            self.parentDialog.UpdateDialog(layer=layer) 
+            # update db info
+            self.mapDBInfo = self.parentDialog.mapDBInfo
+
+        event.Skip()
+
+def main(argv = None):
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+    
+    if argv is None:
+        argv = sys.argv
+    
+    if len(argv) != 2:
+        print >> sys.stderr, __doc__
+        sys.exit()
+    
+    #some applications might require image handlers
+    wx.InitAllImageHandlers()
+    
+    app = wx.PySimpleApp()
+    f = AttributeManager(parent=None, id=wx.ID_ANY,
+                         title="%s - <%s>" % (_("GRASS GIS Attribute Table Manager"),
+                                              argv[1]),
+                         size=(900,600), vectorName=argv[1])
+    f.Show()
+    
+    app.MainLoop()
+    
+if __name__ == '__main__':
+    main()

Copied: grass/trunk/gui/wxpython/dbm/sqlbuilder.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/sqlbuilder.py)
===================================================================
--- grass/trunk/gui/wxpython/dbm/sqlbuilder.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/dbm/sqlbuilder.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,458 @@
+"""!
+ at package dbm.sqlbuilder
+
+ at brief GRASS SQL Builder
+
+Classes:
+ - SQLFrame
+
+Usage:
+ at code
+python sqlbuilder.py vector_map
+ at endcode
+
+(C) 2007-2009, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Jachym Cepicky <jachym.cepicky gmail.com> (original author)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Hamish Bowman <hamish_b yahoo com>
+"""
+
+import os
+import sys
+
+from core import globalvar
+import wx
+
+import grass.script as grass
+
+from core.gcmd import RunCommand, GError
+from dbm.vinfo import createDbInfoDesc, VectorDBInfo
+
+class SQLFrame(wx.Frame):
+    """!SQL Frame class"""
+    def __init__(self, parent, title, vectmap, id = wx.ID_ANY,
+                 layer = 1, qtype = "select", evtheader = None):
+        
+        wx.Frame.__init__(self, parent, id, title)
+        
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'),
+                             wx.BITMAP_TYPE_ICO))
+        
+        self.parent = parent
+        self.evtHeader = evtheader
+
+        #
+        # variables
+        #
+        self.vectmap = vectmap # fullname
+        if not "@" in self.vectmap:
+            self.vectmap = grass.find_file(self.vectmap, element = 'vector')['fullname']
+        self.mapname, self.mapset = self.vectmap.split("@", 1)
+        
+        # db info
+        self.layer = layer
+        self.dbInfo = VectorDBInfo(self.vectmap)
+        self.tablename = self.dbInfo.GetTable(self.layer)
+        self.driver, self.database = self.dbInfo.GetDbSettings(self.layer)
+        
+        self.qtype = qtype      # type of query: SELECT, UPDATE, DELETE, ...
+        self.colvalues = []     # array with unique values in selected column
+
+        # set dialog title
+        self.SetTitle(_("GRASS SQL Builder (%(type)s): vector map <%(map)s>") % \
+                          { 'type' : self.qtype.upper(), 'map' : self.vectmap })
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+        # statusbar
+        self.statusbar = self.CreateStatusBar(number=1)
+        self.statusbar.SetStatusText(_("SQL statement not verified"), 0)
+       
+        self._doLayout()
+
+    def _doLayout(self):
+        """!Do dialog layout"""
+      
+        pagesizer = wx.BoxSizer(wx.VERTICAL)
+
+        
+        # dbInfo
+        databasebox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                   label = " %s " % _("Database connection"))
+        databaseboxsizer = wx.StaticBoxSizer(databasebox, wx.VERTICAL)
+        databaseboxsizer.Add(item=createDbInfoDesc(self.panel, self.dbInfo, layer = self.layer),
+                             proportion=1,
+                             flag=wx.EXPAND | wx.ALL,
+                             border=3)
+
+        #
+        # text areas
+        #
+        # sql box
+        sqlbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                              label = " %s " % _("Query"))
+        sqlboxsizer = wx.StaticBoxSizer(sqlbox, wx.VERTICAL)
+
+        self.text_sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+                                    value = '', size = (-1, 50),
+                                    style=wx.TE_MULTILINE)
+        if self.qtype.lower() == "select":
+            self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
+        self.text_sql.SetInsertionPointEnd()
+        self.text_sql.SetToolTipString(_("Example: %s") % "SELECT * FROM roadsmajor WHERE MULTILANE = 'no' OR OBJECTID < 10")
+        wx.CallAfter(self.text_sql.SetFocus)
+
+        sqlboxsizer.Add(item = self.text_sql, flag = wx.EXPAND)
+        
+        #
+        # buttons
+        #
+        self.btn_clear  = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
+        self.btn_clear.SetToolTipString(_("Set SQL statement to default"))
+        self.btn_verify = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("Verify"))
+        self.btn_verify.SetToolTipString(_("Verify SQL statement"))
+        self.btn_apply  = wx.Button(parent = self.panel, id = wx.ID_APPLY)
+        self.btn_apply.SetToolTipString(_("Apply SQL statement and close the dialog"))
+        self.btn_close  = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+        self.btn_close.SetToolTipString(_("Close the dialog"))
+        
+        self.btn_lv = { 'is'    : ['=', ],
+                        'isnot' : ['!=', ],
+                        'like'  : ['LIKE', ],
+                        'gt'    : ['>', ],
+                        'ge'    : ['>=', ],
+                        'lt'    : ['<', ],
+                        'le'    : ['<=', ],
+                        'or'    : ['OR', ],
+                        'not'   : ['NOT', ],
+                        'and'   : ['AND', ],
+                        'brac'  : ['()', ],
+                        'prc'   : ['%', ] }
+        
+        for key, value in self.btn_lv.iteritems():
+            btn = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                            label = value[0])
+            self.btn_lv[key].append(btn.GetId())
+        
+        buttonsizer = wx.FlexGridSizer(cols = 4, hgap = 5, vgap = 5)
+        buttonsizer.Add(item = self.btn_clear)
+        buttonsizer.Add(item = self.btn_verify)
+        buttonsizer.Add(item = self.btn_apply)
+        buttonsizer.Add(item = self.btn_close)
+        
+        buttonsizer2 = wx.GridBagSizer(5, 5)
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['is'][1]), pos = (0,0))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['isnot'][1]), pos = (1,0))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['like'][1]), pos = (2, 0))
+
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['gt'][1]), pos = (0, 1))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['ge'][1]), pos = (1, 1))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['or'][1]), pos = (2, 1))
+
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['lt'][1]), pos = (0, 2))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['le'][1]), pos = (1, 2))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['not'][1]), pos = (2, 2))
+
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['brac'][1]), pos = (0, 3))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['prc'][1]), pos = (1, 3))
+        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['and'][1]), pos = (2, 3))
+        
+        #
+        # list boxes (columns, values)
+        #
+        hsizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        columnsbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                  label = " %s " % _("Columns"))
+        columnsizer = wx.StaticBoxSizer(columnsbox, wx.VERTICAL)
+        self.list_columns = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
+                                       choices = self.dbInfo.GetColumns(self.tablename),
+                                       style = wx.LB_MULTIPLE)
+        columnsizer.Add(item = self.list_columns, proportion = 1,
+                        flag = wx.EXPAND)
+
+        radiosizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.radio_cv = wx.RadioBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Add on double-click"),
+                                    choices = [_("columns"), _("values")])
+        self.radio_cv.SetSelection(1) # default 'values'
+        radiosizer.Add(item = self.radio_cv, proportion = 1,
+                       flag = wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND, border = 5)
+
+        columnsizer.Add(item = radiosizer, proportion = 0,
+                        flag = wx.TOP | wx.EXPAND, border = 5)
+        # self.list_columns.SetMinSize((-1,130))
+        # self.list_values.SetMinSize((-1,100))
+
+        valuesbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                 label = " %s " % _("Values"))
+        valuesizer = wx.StaticBoxSizer(valuesbox, wx.VERTICAL)
+        self.list_values = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
+                                      choices = self.colvalues,
+                                      style = wx.LB_MULTIPLE)
+        valuesizer.Add(item = self.list_values, proportion = 1,
+                       flag = wx.EXPAND)
+        
+        self.btn_unique = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("Get all values"))
+        self.btn_unique.Enable(False)
+        self.btn_uniquesample = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                          label = _("Get sample"))
+        self.btn_uniquesample.Enable(False)
+
+        buttonsizer3 = wx.BoxSizer(wx.HORIZONTAL)
+        buttonsizer3.Add(item = self.btn_uniquesample, proportion = 0,
+                         flag = wx.ALIGN_CENTER_HORIZONTAL | wx.RIGHT, border = 5)
+        buttonsizer3.Add(item = self.btn_unique, proportion = 0,
+                         flag = wx.ALIGN_CENTER_HORIZONTAL)
+
+        valuesizer.Add(item = buttonsizer3, proportion = 0,
+                       flag = wx.TOP, border = 5)
+        
+        # hsizer1.Add(wx.StaticText(self.panel,-1, "Unique values: "), border=0, proportion=1)
+ 
+        hsizer.Add(item = columnsizer, proportion = 1,
+                   flag = wx.EXPAND)
+        hsizer.Add(item = valuesizer, proportion = 1,
+                   flag = wx.EXPAND)
+        
+        self.close_onapply = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                         label = _("Close dialog on apply"))
+        self.close_onapply.SetValue(True)
+ 
+        pagesizer.Add(item = databaseboxsizer,
+                      flag = wx.ALL | wx.EXPAND, border = 5)
+        pagesizer.Add(item = hsizer, proportion = 1,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+        # pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5)
+        # pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5)
+        pagesizer.Add(item = buttonsizer2, proportion = 0,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL)
+        pagesizer.Add(item = sqlboxsizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+        pagesizer.Add(item = buttonsizer, proportion = 0,
+                      flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        pagesizer.Add(item = self.close_onapply, proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        #
+        # bindings
+        #
+        self.btn_unique.Bind(wx.EVT_BUTTON,       self.OnUniqueValues)
+        self.btn_uniquesample.Bind(wx.EVT_BUTTON, self.OnSampleValues)
+        
+        for key, value in self.btn_lv.iteritems():
+            self.FindWindowById(value[1]).Bind(wx.EVT_BUTTON, self.OnAddMark)
+        
+        self.btn_close.Bind(wx.EVT_BUTTON,       self.OnClose)
+        self.btn_clear.Bind(wx.EVT_BUTTON,       self.OnClear)
+        self.btn_verify.Bind(wx.EVT_BUTTON,      self.OnVerify)
+        self.btn_apply.Bind(wx.EVT_BUTTON,       self.OnApply)
+
+        self.list_columns.Bind(wx.EVT_LISTBOX,   self.OnAddColumn)
+        self.list_values.Bind(wx.EVT_LISTBOX,    self.OnAddValue)
+        
+        self.text_sql.Bind(wx.EVT_TEXT,          self.OnText)
+        
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(pagesizer)
+        pagesizer.Fit(self.panel)
+        
+        self.Layout()
+        self.SetMinSize((660, 525))
+        self.SetClientSize(self.panel.GetSize())
+        self.CenterOnParent()
+        
+    def OnUniqueValues(self, event, justsample = False):
+        """!Get unique values"""
+        vals = []
+        try:
+            idx = self.list_columns.GetSelections()[0]
+            column = self.list_columns.GetString(idx)
+        except:
+            self.list_values.Clear()
+            return
+        
+        self.list_values.Clear()
+        
+        querystring = "SELECT %s FROM %s" % (column, self.tablename)
+        
+        data = grass.db_select(table = self.tablename,
+                               sql = querystring,
+                               database = self.database,
+                               driver = self.driver)
+        if not data:
+            return
+
+        desc = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]
+        
+        i = 0
+        for item in sorted(map(desc['ctype'], data)):
+            if justsample and i < 256 or \
+               not justsample:
+                if desc['type'] != 'character':
+                    item = str(item)
+                self.list_values.Append(item)
+            else:
+                break
+            i += 1
+        
+    def OnSampleValues(self, event):
+        """!Get sample values"""
+        self.OnUniqueValues(None, True)
+
+    def OnAddColumn(self, event):
+        """!Add column name to the query"""
+        idx = self.list_columns.GetSelections()
+        for i in idx:
+            column = self.list_columns.GetString(i)
+            self._add(element = 'column', value = column)
+        
+        if not self.btn_uniquesample.IsEnabled():
+            self.btn_uniquesample.Enable(True)
+            self.btn_unique.Enable(True)
+        
+    def OnAddValue(self, event):
+        """!Add value"""
+        selection = self.list_values.GetSelections()
+        if not selection:
+            event.Skip()
+            return
+
+        idx = selection[0]
+        value = self.list_values.GetString(idx)
+        idx = self.list_columns.GetSelections()[0]
+        column = self.list_columns.GetString(idx)
+        
+        ctype = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]['type']
+        
+        if ctype == 'character':
+            value = "'%s'" % value
+        
+        self._add(element = 'value', value = value)
+
+    def OnAddMark(self, event):
+        """!Add mark"""
+        mark = None
+        for key, value in self.btn_lv.iteritems():
+            if event.GetId() == value[1]:
+                mark = value[0]
+                break
+        
+        self._add(element = 'mark', value = mark)
+
+    def _add(self, element, value):
+        """!Add element to the query
+
+        @param element element to add (column, value)
+        """
+        sqlstr = self.text_sql.GetValue()
+        newsqlstr = ''
+        if element == 'column':
+            if self.radio_cv.GetSelection() == 0: # -> column
+                idx1 = len('select')
+                idx2 = sqlstr.lower().find('from')
+                colstr = sqlstr[idx1:idx2].strip()
+                if colstr == '*':
+                    cols = []
+                else:
+                    cols = colstr.split(',')
+                if value in cols:
+                        cols.remove(value)
+                else:
+                    cols.append(value)
+                
+                if len(cols) < 1:
+                    cols = ['*',]
+                
+                newsqlstr = 'SELECT ' + ','.join(cols) + ' ' + sqlstr[idx2:]
+            else: # -> where
+                newsqlstr = sqlstr
+                if sqlstr.lower().find('where') < 0:
+                    newsqlstr += ' WHERE'
+                
+                newsqlstr += ' ' + value
+        
+        elif element == 'value':
+            newsqlstr = sqlstr + ' ' + value
+        elif element == 'mark':
+            newsqlstr = sqlstr + ' ' + value
+        
+        if newsqlstr:
+            self.text_sql.SetValue(newsqlstr)
+
+    def GetSQLStatement(self):
+        """!Return SQL statement"""
+        return self.text_sql.GetValue().strip().replace("\n"," ")
+    
+    def CloseOnApply(self):
+        """!Return True if the dialog will be close on apply"""
+        return self.close_onapply.IsChecked()
+    
+    def OnText(self, event):
+        """Query string changed"""
+        if len(self.text_sql.GetValue()) > 0:
+            self.btn_verify.Enable(True)
+        else:
+            self.btn_verify.Enable(False)
+        
+    def OnApply(self, event):
+        """Apply button pressed"""
+        if self.evtHeader:
+            self.evtHeader(event = 'apply')
+
+        if self.close_onapply.IsChecked():
+            self.Destroy()
+            
+        event.Skip()
+    
+    def OnVerify(self, event):
+        """!Verify button pressed"""
+        ret, msg = RunCommand('db.select',
+                              getErrorMsg = True,
+                              table = self.tablename,
+                              sql = self.text_sql.GetValue(),
+                              flags = 't',
+                              driver = self.driver,
+                              database = self.database)
+        
+        if ret != 0 and msg:
+            self.statusbar.SetStatusText(_("SQL statement is not valid"), 0)
+            GError(parent = self,
+                   message = _("SQL statement is not valid.\n\n%s") % msg)
+        else:
+            self.statusbar.SetStatusText(_("SQL statement is valid"), 0)
+                        
+    def OnClear(self, event):
+        """!Clear button pressed"""
+        if self.qtype.lower() == "select":
+            self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
+        else:
+            self.text_sql.SetValue("")
+    
+    def OnClose(self, event):
+        """!Close button pressed"""
+        if self.evtHeader:
+            self.evtHeader(event = 'close')
+        
+        self.Destroy()
+        
+        event.Skip()
+        
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        print >>sys.stderr, __doc__
+        sys.exit()
+    
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+    
+    app = wx.App(0)
+    sqlb = SQLFrame(parent = None, title = _('SQL Builder'), vectmap = sys.argv[1])
+    sqlb.Show()
+    
+    app.MainLoop()

Copied: grass/trunk/gui/wxpython/dbm/vinfo.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/dbm_base.py)
===================================================================
--- grass/trunk/gui/wxpython/dbm/vinfo.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/dbm/vinfo.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,163 @@
+"""
+ at package dbm.vinfo
+
+ at brief Support classes for Database Manager
+
+List of classes:
+ - VectorDBInfo
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import types
+
+import wx
+
+from gui_core.gselect import VectorDBInfo
+from core.gcmd        import RunCommand
+from core.settings    import UserSettings
+
+import grass.script as grass
+
+def unicodeValue(value):
+    """!Encode value"""
+    if type(value) == types.UnicodeType:
+        return value
+    
+    enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
+    if enc:
+        value = unicode(value, enc)
+    elif 'GRASS_DB_ENCODING' in os.environ:
+        value = unicode(value, os.environ['GRASS_DB_ENCODING'])
+    else:
+        try:
+            value = unicode(value, 'ascii')
+        except UnicodeDecodeError:
+            value = _("Unable to decode value. Set encoding in GUI preferences ('Attributes').")
+    
+    return value
+
+def createDbInfoDesc(panel, mapDBInfo, layer):
+    """!Create database connection information content"""
+    infoFlexSizer = wx.FlexGridSizer (cols = 2, hgap = 1, vgap = 1)
+    infoFlexSizer.AddGrowableCol(1)
+    
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "Driver:"))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = mapDBInfo.layers[layer]['driver']))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "Database:"))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = mapDBInfo.layers[layer]['database']))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "Table:"))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = mapDBInfo.layers[layer]['table']))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "Key:"))
+    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = mapDBInfo.layers[layer]['key']))
+    
+    return infoFlexSizer
+        
+class VectorDBInfo(VectorDBInfo):
+    """!Class providing information about attribute tables
+    linked to the vector map"""
+    def __init__(self, map):
+        VectorDBInfo.__init__(self, map)
+        
+    def GetColumns(self, table):
+        """!Return list of columns names (based on their index)"""
+        try:
+            names = [''] * len(self.tables[table].keys())
+        except KeyError:
+            return []
+        
+        for name, desc in self.tables[table].iteritems():
+            names[desc['index']] = name
+        
+        return names
+
+    def SelectByPoint(self, queryCoords, qdist):
+        """!Get attributes by coordinates (all available layers)
+
+        Return line id or None if no line is found"""
+        line = None
+        nselected = 0
+
+        data = grass.vector_what(map = self.map,
+                                 coord = (float(queryCoords[0]), float(queryCoords[1])),
+                                 distance = float(qdist))
+
+        if len(data) < 1 or 'Table' not in data[0]:
+            return None
+        
+        # process attributes
+        table = data[0]['Table']
+        for key, value in data[0]['Attributes'].iteritems():
+            if len(value) < 1:
+                value = None
+            else:
+                if self.tables[table][key]['ctype'] != types.StringType:
+                    value = self.tables[table][key]['ctype'] (value)
+                else:
+                    value = unicodeValue(value)
+            self.tables[table][key]['values'].append(value)
+        
+        ret = dict()
+        for key, value in data[0].iteritems():
+            if key == 'Attributes':
+                continue
+            ret[key] = list()
+            ret[key].append(value)
+        
+        return ret
+    
+    def SelectFromTable(self, layer, cols = '*', where = None):
+        """!Select records from the table
+
+        Return number of selected records, -1 on error
+        """
+        if layer <= 0:
+            return -1
+
+        nselected = 0
+
+        table = self.layers[layer]["table"] # get table desc
+        # select values (only one record)
+        if where is None or where is '':
+            sql = "SELECT %s FROM %s" % (cols, table)
+        else:
+            sql = "SELECT %s FROM %s WHERE %s" % (cols, table, where)
+        
+        ret = RunCommand('db.select',
+                         parent = self,
+                         read = True,
+                         quiet = True,
+                         flags = 'v',
+                         sql= sql,
+                         database = self.layers[layer]["database"],
+                         driver = self.layers[layer]["driver"])
+        
+        # self.tables[table][key][1] = str(cat)
+        if ret:
+            for line in ret.splitlines():
+                name, value = line.split('|')
+                # casting ...
+                if value:
+                    if self.tables[table][name]['ctype'] != type(''):
+                        value = self.tables[table][name]['ctype'] (value)
+                    else:
+                        value = unicodeValue(value)
+                else:
+                    value = None
+                self.tables[table][name]['values'].append(value)
+                nselected = 1
+
+        return nselected

Copied: grass/trunk/gui/wxpython/gcp/manager.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gcpmanager.py)
===================================================================
--- grass/trunk/gui/wxpython/gcp/manager.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gcp/manager.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2781 @@
+"""!
+ at package gcp.manager
+
+ 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-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author 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 shutil
+
+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
+
+from core              import globalvar
+from core              import utils
+from core.render       import Map
+from gui_core.gselect  import Select, LocationSelect, MapsetSelect
+from gui_core.gdialogs import GroupDialog
+from core.gcmd         import RunCommand, GMessage, GError, GWarning
+from core.settings     import UserSettings
+from gcp.mapdisp       import MapFrame
+from mapdisp.window    import BufferedWindow
+
+from location_wizard.wizard   import TitledPage as TitledPage
+
+#
+# global variables
+#
+global src_map
+global tgt_map
+global maptype
+
+src_map = ''
+tgt_map = ''
+maptype = 'cell'
+
+def getSmallUpArrowImage():
+    stream = open(os.path.join(globalvar.ETCIMGDIR, 'small_up_arrow.png'), 'rb')
+    try:
+        img = wx.ImageFromStream(stream)
+    finally:
+        stream.close()
+    return img
+
+def getSmallDnArrowImage():
+    stream = open(os.path.join(globalvar.ETCIMGDIR, '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:
+                GMessage(parent = self.parent,
+                         message = _("Georectifying setup canceled."))
+                self.Cleanup()
+        else:
+            GMessage(parent = self.parent,
+                     message = _("Georectifying setup canceled."))
+            self.Cleanup()
+
+        #
+        # start GCP display
+        #
+        if success != False:
+            # instance of render.Map to be associated with display
+            self.SwitchEnv('source')
+            self.SrcMap = Map(gisrc=self.source_gisrc) 
+            self.SwitchEnv('target')
+            self.TgtMap = Map(gisrc=self.target_gisrc)
+            self.Map = self.SrcMap
+            
+            #
+            # add layer to source map
+            #
+            if maptype == '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')
+            name, found = utils.GetLayerNameFromCmd(cmdlist)
+            self.SrcMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
+                                 name=name, 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')
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.TgtMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
+                                     name=name, 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 = 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 = 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 == '':
+            GMessage(_('You must select a valid location '
+                       'before selecting a mapset'),
+                     parent = self)
+            return
+
+        self.xymapset = event.GetString()
+        
+        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+    def OnPageChanging(self, event=None):
+        if event.GetDirection() and \
+               (self.xylocation == '' or self.xymapset == ''):
+            GMessage(_('You must select a valid location '
+                            'and mapset in order to continue'),
+                          parent = self)
+            event.Veto()
+            return
+        
+        self.parent.SetSrcEnv(self.xylocation, self.xymapset)
+        
+    def OnEnterPage(self, event=None):
+        if self.xylocation == '' or self.xymapset == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+class GroupPage(TitledPage):
+    """
+    Set group to georectify. Create group if desired.
+    """
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Select image/map group to georectify"))
+
+        self.parent = parent
+        
+        self.grassdatabase = self.parent.grassdatabase
+        self.groupList = []
+        
+        self.xylocation = ''
+        self.xymapset = ''
+        self.xygroup = ''
+
+        # default extension
+        self.extension = '.georect' + str(os.getpid())
+
+        #
+        # layout
+        #
+        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"""
+        dlg = GroupDialog(parent = self, defaultGroup = self.xygroup)
+
+        dlg.ShowModal()
+        gr = dlg.GetSelectedGroup()
+        if gr in dlg.GetExistGroups():
+            self.xygroup = gr
+        else:
+            gr = ''
+        dlg.Destroy()
+        
+        self.OnEnterPage()
+        self.Update()
+        
+    def OnVGroup(self, event):
+        """!Add vector maps to group"""
+        dlg = VectGroup(parent = self,
+                        id = wx.ID_ANY,
+                        grassdb = self.grassdatabase,
+                        location = self.xylocation,
+                        mapset = self.xymapset,
+                        group = self.xygroup)
+
+        if dlg.ShowModal() != wx.ID_OK:
+            return
+
+        dlg.MakeVGroup()
+        self.OnEnterPage()
+        
+    def OnExtension(self, event):
+        self.extension = event.GetString()
+
+    def OnPageChanging(self, event=None):
+        if event.GetDirection() and self.xygroup == '':
+            GMessage(_('You must select a valid image/map '
+                       'group in order to continue'),
+                     parent = self)
+            event.Veto()
+            return
+
+        if event.GetDirection() and self.extension == '':
+            GMessage(_('You must enter an map name '
+                       'extension in order to continue'),
+                     parent = self)
+            event.Veto()
+            return
+
+    def OnEnterPage(self, event=None):
+        global maptype
+        
+        self.groupList = []
+
+        self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
+        self.xymapset = self.parent.gisrc_dict['MAPSET']
+
+        # create a list of groups in selected mapset
+        if os.path.isdir(os.path.join(self.grassdatabase,
+                                      self.xylocation,
+                                      self.xymapset,
+                                      'group')):
+            tmplist = os.listdir(os.path.join(self.grassdatabase,
+                                              self.xylocation,
+                                              self.xymapset,
+                                              'group'))
+            for item in tmplist:
+                if os.path.isdir(os.path.join(self.grassdatabase,
+                                              self.xylocation,
+                                              self.xymapset,
+                                              'group',
+                                              item)):
+                    self.groupList.append(item)
+        
+        if maptype == '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:
+            if self.xygroup and self.xygroup in self.groupList:
+                self.cb_group.SetStringSelection(self.xygroup)
+            else:
+                self.cb_group.SetSelection(0)
+                self.xygroup = self.groupList[0]
+        
+        if self.xygroup == '' or \
+                self.extension == '':
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+        
+        # switch to source
+        self.parent.SwitchEnv('source')
+    
+class DispMapPage(TitledPage):
+    """
+    Select ungeoreferenced map to display for interactively
+    setting ground control points (GCPs).
+    """
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard,
+                            _("Select maps to display for ground control point (GCP) creation"))
+
+        self.parent = parent
+        global maptype
+
+        #
+        # layout
+        #
+        self.sizer.Add(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 = 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 = 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 = RunCommand('g.region', 'rast=src_map')
+            elif maptype == 'vector':
+                p = RunCommand('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 == ''):
+            GMessage(_('You must select a source map '
+                       'in order to continue'),
+                     parent = self)
+            event.Veto()
+            return
+
+        self.parent.SwitchEnv('target')
+        
+    def OnEnterPage(self, event=None):
+        global maptype
+        global src_map
+        global tgt_map
+
+        self.srcselection.SetElementList(maptype)
+        ret = RunCommand('i.group',
+                         parent = self,
+                         read = True,
+                         group = self.parent.grouppage.xygroup,
+                         flags = 'g')            
+
+        if ret:
+            self.parent.src_maps = ret.splitlines()
+        else:
+            GError(parent = self,
+                   message = _('No maps in selected group <%s>.\n'
+                               'Please edit group or select another group.') %
+                   self.parent.grouppage.xygroup)
+            return
+
+        # 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, 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 = parent, title = title, size = size,
+                            Map = Map, toolbars = toolbars, 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 
+        # interpolation method for georectification
+        self.gr_method = 'nearest'
+        # region clipping for georectified map
+        self.clip_to_region = False
+        # number of GCPs selected to be used for georectification (checked)
+        self.GCPcount = 0
+        # forward RMS error
+        self.fwd_rmserror = 0.0
+        # backward RMS error
+        self.bkw_rmserror = 0.0
+        # list map coords and ID of map display they came from
+        self.mapcoordlist = []
+        self.mapcoordlist.append([ 0,        # GCP number
+                                   0.0,      # source east
+                                   0.0,      # source north
+                                   0.0,      # 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)
+
+        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
+        #
+        if self.show_target:
+            self.MapWindow = self.TgtMapWindow
+            self.Map = self.TgtMap
+            self.OnZoomToMap(None)
+
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        self.OnZoomToMap(None)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(wx.EVT_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
+        
+    def GetMapCoordList(self):
+        return self.mapcoordlist
+
+    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
+    def GetSortImages(self):
+        return (self.sm_dn, self.sm_up)
+
+    def GetFwdError(self):
+        return self.fwd_rmserror
+        
+    def GetBkwError(self):
+        return self.bkw_rmserror
+                
+    def InitMapDisplay(self):
+        self.list.LoadData()
+        
+        # initialize column sorter
+        self.itemDataMap = self.mapcoordlist
+        ncols = self.list.GetColumnCount()
+        ColumnSorterMixin.__init__(self, ncols)
+        # init to ascending sort on first click
+        self._colSortFlag = [1] * ncols
+
+    def SetTarget(self, tgroup, tlocation, tmapset):
+        """
+        Sets rectification target to current location and mapset
+        """
+        # check to see if we are georectifying map in current working location/mapset
+        if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
+            RunCommand('i.target',
+                       parent = self,
+                       flags = 'c',
+                       group = tgroup)
+        else:
+            self.grwiz.SwitchEnv('source')
+            RunCommand('i.target',
+                       parent = self,
+                       group = tgroup,
+                       location = tlocation,
+                       mapset = tmapset)
+            self.grwiz.SwitchEnv('target')
+
+    def AddGCP(self, event):
+        """
+        Appends an item to GCP list
+        """
+        keyval = self.list.AddGCPItem() + 1
+        # source east, source north, target east, target north, forward error, backward error
+        self.mapcoordlist.append([ keyval,             # GCP number
+                                   0.0,                # source east
+                                   0.0,                # source north
+                                   0.0,                # target east
+                                   0.0,                # target north
+                                   0.0,                # forward error
+                                   0.0 ] )             # backward error
+
+        if self.statusbarManager.GetMode() == 8: # go to
+            self.StatusbarUpdate()
+
+    def DeleteGCP(self, event):
+        """
+        Deletes selected item in GCP list
+        """
+        minNumOfItems = self.OnGROrder(None)
+
+        if self.list.GetItemCount() <= minNumOfItems:
+            GMessage(parent = self,
+                     message=_("At least %d GCPs required. Operation cancelled.") % minNumOfItems)
+            return
+
+        key = self.list.DeleteGCPItem()
+        del self.mapcoordlist[key]
+
+        # update key and GCP number
+        for newkey in range(key, len(self.mapcoordlist)):
+            index = self.list.FindItemData(-1, newkey + 1)
+            self.mapcoordlist[newkey][0] = newkey
+            self.list.SetStringItem(index, 0, str(newkey))
+            self.list.SetItemData(index, newkey)
+
+        # update selected
+        if self.list.GetItemCount() > 0:
+            if self.list.selected < self.list.GetItemCount():
+                self.list.selectedkey = self.list.GetItemData(self.list.selected)
+            else:
+                self.list.selected = self.list.GetItemCount() - 1
+                self.list.selectedkey = self.list.GetItemData(self.list.selected)
+                
+            self.list.SetItemState(self.list.selected,
+                              wx.LIST_STATE_SELECTED,
+                              wx.LIST_STATE_SELECTED)
+        else:
+            self.list.selected = wx.NOT_FOUND
+            self.list.selectedkey = -1
+
+        self.UpdateColours()
+
+        if self.statusbarManager.GetMode() == 8: # go to
+            self.StatusbarUpdate()
+            if self.list.selectedkey > 0:
+                self.statusbarManager.SetProperty('gotoGCP', self.list.selectedkey)
+
+    def ClearGCP(self, event):
+        """
+        Clears all values in selected item of GCP list and unchecks it
+        """
+        index = self.list.GetSelected()
+
+        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:
+            GError(parent = self,
+                   message="%s%s." % (_("mapwin not defined for "),
+                                      str(idx)))
+            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 %(coor)s coordinates for GCP No. %(key)s? \n\n'
+                                          'East: %(coor0)s \n'
+                                          'North: %(coor1)s') % \
+                                    { 'coor' : currloc,
+                                      'key' : str(key),
+                                      'coor0' : str(coord0),
+                                      'coor1' : str(coord1) },
+                                style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
+
+            # for wingrass
+            if os.name == 'nt':
+                self.MapWindow.SetFocus()
+            if ret == wx.NO:
+                return
+            
+        if coordtype == 'source':
+            self.list.SetStringItem(index, 1, str(coord0))
+            self.list.SetStringItem(index, 2, str(coord1))
+            self.mapcoordlist[key][1] = coord[0]
+            self.mapcoordlist[key][2] = coord[1]
+        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:
+            GError(parent = self,
+                   message="%s <%s>. %s%s" % (_("Writing POINTS file failed"),
+                                              self.file['points'], os.linesep, err))
+            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:
+            GError(parent = self,
+                   message = "%s. %s%s" % (_("source mapwin not defined"),
+                                           os.linesep, err))
+        
+        if not targetMapWin:
+            GError(parent = self,
+                   message="%s. %s%s" % (_("target mapwin not defined"),
+                                         os.linesep, err))
+        
+        try:
+            f = open(self.file['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:
+            GError(parent = self,
+                   message = "%s <%s>. %s%s" % (_("Reading POINTS file failed"),
+                                                self.file['points'], os.linesep, err))
+            return
+
+        f.close()
+
+        if GCPcnt == 0:
+            # 3 gcp is minimum
+            for i in range(3):
+                self.AddGCP(None)
+
+        if self.CheckGCPcount():
+            # calculate RMS
+            self.RMSError(self.xygroup, self.gr_order)
+
+    def ReloadGCPs(self, event):
+        """!Reload data from file"""
+
+        # use backup
+        shutil.copy(self.file['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
+
+        if self._col != -1:
+            self.list.ClearColumnImage(self._col)
+        self._colSortFlag = [1] * self.list.GetColumnCount()
+
+        # draw GCPs (source and target)
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=False, renderVector=False)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+    
+    def OnFocus(self, event):
+        # self.grwiz.SwitchEnv('source')
+        pass
+        
+    def OnRMS(self, event):
+        """
+        RMS button handler
+        """
+        self.RMSError(self.xygroup,self.gr_order)
+
+        sourceMapWin = self.SrcMapWindow
+        sourceMapWin.UpdateMap(render=False, renderVector=False)
+        if self.show_target:
+            targetMapWin = self.TgtMapWindow
+            targetMapWin.UpdateMap(render=False, renderVector=False)
+        
+    def CheckGCPcount(self, msg=False):
+        """
+        Checks to make sure that the minimum number of GCPs have been defined and
+        are active for the selected transformation order
+        """
+        if (self.GCPcount < 3 and self.gr_order == 1) or \
+            (self.GCPcount < 6 and self.gr_order == 2) or \
+            (self.GCPcount < 10 and self.gr_order == 3):
+            if msg:
+                GWarning(parent = self,
+                         message=_('Insufficient points defined and active (checked) '
+                                   'for selected rectification method.\n'
+                                   '3+ points needed for 1st order,\n'
+                                   '6+ points for 2nd order, and\n'
+                                   '10+ points for 3rd order.'))
+                return False
+        else:
+            return True
+
+    def OnGeorect(self, event):
+        """
+        Georectifies map(s) in group using i.rectify or v.transform
+        """
+        global maptype
+        self.SaveGCPs(None)
+        
+        if self.CheckGCPcount(msg=True) == False:
+            return
+
+        if maptype == 'cell':
+            self.grwiz.SwitchEnv('source')
+
+            if self.clip_to_region:
+                flags = "ac"
+            else:
+                flags = "a"
+
+            busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
+                               parent=self)
+            wx.Yield()
+
+            ret, msg = RunCommand('i.rectify',
+                                  parent = self,
+                                  getErrorMsg = True,
+                                  quiet = True,
+                                  group = self.xygroup,
+                                  extension = self.extension,
+                                  order = self.gr_order,
+                                  method=self.gr_method,
+                                  flags = flags)
+
+            busy.Destroy()
+
+            # provide feedback on failure
+            if ret != 0:
+                print >> sys.stderr, msg
+                
+        elif maptype == 'vector':
+            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 = RunCommand('v.transform',
+                                           overwrite = True,
+                                           input = vect,
+                                           output = self.outname,
+                                           pointsfile = self.file['points'],
+                                           getErrorMsg = True, read = True) 
+                
+                if ret == 0:
+                    self.VectGRList.append(self.outname)
+                    # 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
+                                                   
+            GMessage(_('For all vector maps georectified successfully,') + '\n' +
+                     _('you will need to copy any attribute tables') + '\n' +
+                     _('and reconnect them to the georectified vectors'),
+                     parent = self)
+        
+        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 m.transform to calculate forward and backward error for each used GCP
+        in POINTS file and insert error values into GCP list.
+        Calculates total forward and backward RMS error for all used points
+        """
+        # save GCPs to points file to make sure that all checked GCPs are used
+        self.SaveGCPs(None)
+        #self.SetStatusText('')
+        
+        if self.CheckGCPcount(msg=True) == False:
+            return
+        
+        # get list of forward and reverse rms error values for each point
+        self.grwiz.SwitchEnv('source')
+        
+        ret = RunCommand('m.transform',
+                         parent = self,
+                         read = True,
+                         group = xygroup,
+                         order = order)
+        
+        self.grwiz.SwitchEnv('target')
+
+        if ret:
+            errlist = ret.splitlines()
+        else:
+            GError(parent = self,
+                   message=_('Could not calculate RMS Error.\n'
+                             'Possible error with m.transform.'))
+            return
+        
+        # insert error values into GCP list for checked items
+        sdfactor = float(UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor'))
+        GCPcount = 0
+        sumsq_fwd_err = 0.0
+        sumsq_bkw_err = 0.0
+        sum_fwd_err = 0.0
+        highest_fwd_err = 0.0
+        self.highest_key = 0
+        highest_idx = 0
+        
+        for index in range(self.list.GetItemCount()):
+            key = self.list.GetItemData(index)
+            if self.list.IsChecked(index):
+                fwd_err, bkw_err = errlist[GCPcount].split()
+                self.list.SetStringItem(index, 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()
+
+    def GetNewExtent(self, region, map = None):
+
+        coord_file = utils.GetTempfile()
+        newreg = { 'n' : 0.0, 's' : 0.0, 'e' : 0.0, 'w' : 0.0,}
+
+        try:
+            f = open(coord_file, mode='w')
+            # NW corner        
+            f.write(str(region['e']) + " " + str(region['n']) + "\n")
+            # NE corner        
+            f.write(str(region['e']) + " " + str(region['s']) + "\n")
+            # SW corner        
+            f.write(str(region['w']) + " " + str(region['n']) + "\n")
+            # SE corner        
+            f.write(str(region['w']) + " " + str(region['s']) + "\n")
+        finally:
+            f.close()
+
+        # save GCPs to points file to make sure that all checked GCPs are used
+        self.SaveGCPs(None)
+
+        order = self.gr_order
+        self.gr_order = 1
+
+        if self.CheckGCPcount(msg=True) == False:
+            self.gr_order = order
+            return
+        
+        self.gr_order = order
+
+        # get list of forward and reverse rms error values for each point
+        self.grwiz.SwitchEnv('source')
+        
+        if map == 'source':
+            ret = RunCommand('m.transform',
+                             parent = self,
+                             read = True,
+                             group = self.xygroup,
+                             order = 1,
+                             format = 'dst',
+                             coords = coord_file)
+
+        elif map == 'target':
+            ret = RunCommand('m.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:
+            GError(parent = self,
+                   message=_('Could not calculate new extends.\n'
+                             'Possible error with m.transform.'))
+            return
+
+        # fist corner
+        e, n = errlist[0].split()
+        fe = float(e)
+        fn = float(n)
+        newreg['n'] = fn
+        newreg['s'] = fn
+        newreg['e'] = fe
+        newreg['w'] = fe
+        # other three corners
+        for i in range(1, 4):
+            e, n = errlist[i].split()
+            fe = float(e)
+            fn = float(n)
+            if fe < newreg['w']:
+                newreg['w'] = fe
+            if fe > newreg['e']:
+                newreg['e'] = fe
+            if fn < newreg['s']:
+                newreg['s'] = fn
+            if fn > newreg['n']:
+                newreg['n'] = fn
+
+        return newreg
+
+    def OnHelp(self, event):
+        """!Show GCP Manager manual page"""
+        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.GetMapToolbar().Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
+
+        if self.activemap.GetSelection() != (win == self.TgtMapWindow):
+            self.activemap.SetSelection(win == self.TgtMapWindow)
+        self.StatusbarUpdate()
+
+    def AdjustMap(self, newreg):
+        """!Adjust map window to new extents
+        """
+
+        # adjust map window
+        self.Map.region['n'] = newreg['n']
+        self.Map.region['s'] = newreg['s']
+        self.Map.region['e'] = newreg['e']
+        self.Map.region['w'] = newreg['w']
+
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                 self.Map.region['e'], self.Map.region['w'])
+
+        # LL locations
+        if self.Map.projinfo['proj'] == 'll':
+            if newreg['n'] > 90.0:
+                newreg['n'] = 90.0
+            if newreg['s'] < -90.0:
+                newreg['s'] = -90.0
+        
+        ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
+        cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
+        
+        # calculate new center point and display resolution
+        self.Map.region['center_easting'] = ce
+        self.Map.region['center_northing'] = cn
+        self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
+        self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height
+        self.Map.AlignExtentFromDisplay()
+
+        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                 self.Map.region['e'], self.Map.region['w'])
+
+        if self.MapWindow.redrawAll is False:
+            self.MapWindow.redrawAll = True
+
+        self.MapWindow.UpdateMap()
+        self.StatusbarUpdate()
+
+    def OnZoomToSource(self, event):
+        """!Set target map window to match extents of source map window
+        """
+
+        if not self.MapWindow == self.TgtMapWindow:
+            self.MapWindow = self.TgtMapWindow
+            self.Map = self.TgtMap
+            self.UpdateActive(self.TgtMapWindow)
+
+        # get new N, S, E, W for target
+        newreg = self.GetNewExtent(self.SrcMap.region, 'source')
+        if newreg:
+            self.AdjustMap(newreg)
+
+    def OnZoomToTarget(self, event):
+        """!Set source map window to match extents of target map window
+        """
+
+        if not self.MapWindow == self.SrcMapWindow:
+            self.MapWindow = self.SrcMapWindow
+            self.Map = self.SrcMap
+            self.UpdateActive(self.SrcMapWindow)
+
+        # get new N, S, E, W for target
+        newreg = self.GetNewExtent(self.TgtMap.region, 'target')
+        if newreg:
+            self.AdjustMap(newreg)
+
+    def OnZoomMenuGCP(self, event):
+        """!Popup Zoom menu
+        """
+        point = wx.GetMousePosition()
+        zoommenu = wx.Menu()
+        # Add items to the menu
+
+        zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust source display to target display'))
+        zoommenu.AppendItem(zoomsource)
+        self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
+
+        zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust target display to source display'))
+        zoommenu.AppendItem(zoomtarget)
+        self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
+
+        # Popup the menu. If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(zoommenu)
+        zoommenu.Destroy()
+        
+    def OnDispResize(self, event):
+        """!GCP Map Display resized, adjust Map Windows
+        """
+        if self.GetMapToolbar():
+            srcwidth, srcheight = self.SrcMapWindow.GetSize()
+            tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
+            srcwidth = (srcwidth + tgtwidth) / 2
+            self._mgr.GetPane("target").Hide()
+            self._mgr.Update()
+            self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+            self._mgr.GetPane("target").BestSize((srcwidth, 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:
+                GError(parent = self,
+                       message=_("Invalid coordinate value. Operation cancelled."))
+            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 = {}
+        
+        self.methods = ["nearest",
+                        "bilinear",
+                        "bilinear_f",
+                        "cubic", 
+                        "cubic_f",
+                        "lanczos",
+                        "lanczos_f"]
+
+        # notebook
+        notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
+        self.__CreateSymbologyPage(notebook)
+        self.__CreateRectificationPage(notebook)
+
+        # buttons
+        btnSave = wx.Button(self, wx.ID_SAVE)
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnClose = wx.Button(self, wx.ID_CLOSE)
+        btnApply.SetDefault()
+
+        # bindings
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnApply.SetToolTipString(_("Apply changes for the current session"))
+        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
+        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
+        btnClose.SetToolTipString(_("Close dialog"))
+
+        # sizers
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
+        
+        # sizers
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(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 = 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 = 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_grorder = wx.RadioBox(parent=panel, id=wx.ID_ANY,
+                                       label=" %s " % _("Select rectification order"),
+                                       choices=[_('1st order'), _('2nd order'), _('3rd order')],
+                                       majorDimension=wx.RA_SPECIFY_COLS)
+        sizer.Add(item=self.rb_grorder, proportion=0,
+                       flag=wx.EXPAND | wx.ALL, border=5)
+        self.rb_grorder.SetSelection(self.parent.gr_order - 1)
+
+        # interpolation method
+        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+        gridSizer.AddGrowableCol(1)
+        gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select interpolation method:')),
+                       pos=(0,0), flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
+        self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
+                                  choices = self.methods)
+        gridSizer.Add(item=self.grmethod, pos=(0,1),
+                       flag=wx.ALIGN_RIGHT, border=5)
+        self.grmethod.SetStringSelection(self.parent.gr_method)
+        sizer.Add(item=gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
+
+        # clip to region
+        self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+                                label=_("clip to computational region in target location"))
+        sizer.Add(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_grorder)
+        self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
+        self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
+
+        panel.SetSizer(sizer)
+        
+        return panel
+
+    def OnHighlight(self, event):
+        """!Checkbox 'highlighthighest' checked/unchecked"""
+        if self.highlighthighest.IsChecked():
+            self.parent.highest_only = True
+            self.rmsWin.Disable()
+        else:
+            self.parent.highest_only = False
+            self.rmsWin.Enable()
+
+    def OnSDFactor(self,event):
+        """!New factor for RMS threshold = M + SD * factor"""
+
+        self.sdfactor = float(event.GetString())
+
+        if self.sdfactor <= 0:
+            GError(parent = self,
+                   message=_('RMS threshold factor must be > 0'))
+        elif self.sdfactor < 1:
+            GError(parent = self,
+                   message=_('RMS threshold factor is < 1\n'
+                             'Too many points might be highlighted'))
+        
+    def OnSrcSelection(self,event):
+        """!Source map to display selected"""
+        global src_map
+
+        tmp_map = 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 OnMethod(self, event):
+        self.parent.gr_method = self.methods[event.GetSelection()]
+
+    def OnClipRegion(self, event):
+        self.parent.clip_to_region = event.IsChecked()
+        
+    def OnExtension(self, event):
+        self.parent.extension = 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')
+            name, found = utils.GetLayerNameFromCmd(cmdlist),
+            self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
+                              name=name, 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]
+                name, found = utils.GetLayerNameFromCmd(cmdlist)
+                self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
+                                  name=name, 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._mgr.Update()
+                    self.parent.GetMapToolbar().Enable('zoommenu', enable = True)
+                    self.parent.activemap.Enable()
+                    self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
+            else: # tgt_map == ''
+                if self.parent.show_target == True:
+                    self.parent.show_target = False
+                    self.parent._mgr.GetPane("target").Hide()
+                    self.parent._mgr.Update()
+                    self.parent.activemap.SetSelection(0)
+                    self.parent.activemap.Enable(False)
+                    self.parent.GetMapToolbar().Enable('zoommenu', enable = False)
+
+        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()

Copied: grass/trunk/gui/wxpython/gcp/mapdisp.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gcpmapdisp.py)
===================================================================
--- grass/trunk/gui/wxpython/gcp/mapdisp.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gcp/mapdisp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,629 @@
+"""!
+ at package gcp.mapdisp
+
+ 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-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import math
+import platform
+
+from core import globalvar
+import wx
+import wx.aui
+
+from core.render      import EVT_UPDATE_PRGBAR
+from mapdisp.toolbars import MapToolbar
+from gcp.toolbars     import GCPDisplayToolbar, GCPManToolbar
+from mapdisp.gprint   import PrintOptions
+from core.gcmd        import GMessage
+from gui_core.dialogs import GetImageHandlers, ImageSizeDialog
+from gui_core.mapdisp import MapFrameBase
+from core.settings    import UserSettings
+from mapdisp.window   import BufferedWindow
+
+import mapdisp.statusbar as sb
+
+# for standalone app
+cmdfilename = None
+
+class MapFrame(MapFrameBase):
+    """!Main frame for map display window. Drawing takes place in
+    child double buffered drawing window.
+    """
+    def __init__(self, parent=None, title=_("GRASS GIS Manage Ground Control Points"),
+                 toolbars=["gcpdisp"], tree=None, notebook=None, lmgr=None,
+                 page=None, Map=None, auimgr=None, name = 'GCPMapWindow', **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
+        """
+        
+        MapFrameBase.__init__(self, parent = parent, title = title, toolbars = toolbars,
+                              Map = Map, auimgr = auimgr, name = name, **kwargs)
+        
+        self._layerManager = lmgr   # Layer Manager object
+        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
+        #
+        # Add toolbars
+        #
+        for toolb in toolbars:
+            self.AddToolbar(toolb)
+
+        self.activemap = self.toolbars['gcpdisp'].togglemap
+        self.activemap.SetSelection(0)
+        
+        self.SrcMap        = self.grwiz.SrcMap       # instance of render.Map
+        self.TgtMap        = self.grwiz.TgtMap       # instance of render.Map
+        self._mgr.SetDockSizeConstraint(0.5, 0.5)
+
+        #
+        # Add statusbar
+        #
+        
+        # items for choice
+        self.statusbarItems = [sb.SbCoordinates,
+                               sb.SbRegionExtent,
+                               sb.SbCompRegionExtent,
+                               sb.SbShowRegion,
+                               sb.SbResolution,
+                               sb.SbDisplayGeometry,
+                               sb.SbMapScale,
+                               sb.SbProjection,
+                               sb.SbGoToGCP,
+                               sb.SbRMSError]
+                            
+        
+        # create statusbar and its manager
+        statusbar = self.CreateStatusBar(number = 4, style = 0)
+        statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
+        
+        # fill statusbar manager
+        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
+        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
+        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
+        
+        self.statusbarManager.SetMode(8) # goto GCP
+        self.statusbarManager.Update()
+        
+
+        #
+        # 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._initMap(map = self.SrcMap) 
+        self._initMap(map = self.TgtMap) 
+
+        #
+        # Bind various events
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(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()
+        srcwidth = (srcwidth + tgtwidth) / 2
+        self._mgr.GetPane("target").Hide()
+        self._mgr.Update()
+        self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
+        self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
+        if self.show_target:
+            self._mgr.GetPane("target").Show()
+        else:
+            self.activemap.Enable(False)
+        # needed by Mac OS, does not harm on Linux, breaks display on Windows
+        if platform.system() != 'Windows':
+            self._mgr.Update()
+
+        #
+        # Init print module and classes
+        #
+        self.printopt = PrintOptions(self, self.MapWindow)
+        
+        #
+        # Initialization of digitization tool
+        #
+        self.digit = None
+
+        # set active map
+        self.MapWindow = self.SrcMapWindow
+        self.Map = self.SrcMap
+        
+        # do not init zoom history here, that happens when zooming to map(s)
+
+        #
+        # Re-use dialogs
+        #
+        self.dialogs = {}
+        self.dialogs['attributes'] = None
+        self.dialogs['category'] = None
+        self.dialogs['barscale'] = None
+        self.dialogs['legend'] = None
+
+        self.decorationDialog = None # decoration/overlays
+
+    def AddToolbar(self, name):
+        """!Add defined toolbar to the window
+        
+        Currently known toolbars are:
+         - 'map'     - basic map toolbar
+         - 'vdigit'  - vector digitizer
+         - 'gcpdisp' - GCP Manager, Display
+         - 'gcpman'  - GCP Manager, points management
+         - 'nviz'    - 3D view mode
+        """
+        # default toolbar
+        if name == "map":
+            self.toolbars['map'] = MapToolbar(self, self.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'] = 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'] = GCPManToolbar(self)
+
+            self._mgr.AddPane(self.toolbars['gcpman'],
+                              wx.aui.AuiPaneInfo().
+                              Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
+                              ToolbarPane().Top().Row(1).
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2))
+            
+        self._mgr.Update()
+
+    def OnUpdateProgress(self, event):
+        """
+        Update progress bar info
+        """
+        self.GetProgressBar().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)
+        if self.show_target:
+            self.TgtMapWindow.UpdateMap(render=True)
+        
+        # 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.GetToolbar('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.GetToolbar('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 OnPan(self, event):
+        """
+        Panning, set mouse to drag
+        """
+        if self.GetToolbar('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 SaveToFile(self, event):
+        """!Save map to image
+        """
+        img = self.MapWindow.img
+        if not img:
+            GMessage(parent = self,
+                     message = _("Nothing to render (empty map). Operation canceled."))
+            return
+        filetype, ltype = GetImageHandlers(img)
+
+        # get size
+        dlg = ImageSizeDialog(self)
+        dlg.CentreOnParent()
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        width, height = dlg.GetValues()
+        dlg.Destroy()
+        
+        # get filename
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to save the image "
+                                        "(no need to add extension)"),
+                            wildcard = filetype,
+                            style=wx.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 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 OnZoomToRaster(self, event):
+        """!
+        Set display extents to match selected raster map (ignore NULLs)
+        """
+        self.MapWindow.ZoomToMap(ignoreNulls = True)
+        
+    def OnZoomToSaved(self, event):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        self.MapWindow.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 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
+    
+    def GetSrcWindow(self):
+        return self.SrcMapWindow
+        
+    def GetTgtWindow(self):
+        return self.TgtMapWindow
+    
+    def GetShowTarget(self):
+        return self.show_target
+        
+    def GetMapToolbar(self):
+        """!Returns toolbar with zooming tools"""
+        return self.toolbars['gcpdisp']

Added: grass/trunk/gui/wxpython/gcp/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/gcp/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gcp/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,127 @@
+"""!
+ at package gcp.toolbars
+
+ at brief Georectification module - toolbars
+
+Classes:
+ - GCPMapToolbar
+ - GCPDisplayToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import sys
+
+import wx
+
+from core              import globalvar
+from gui_core.toolbars import BaseToolbar
+
+sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
+from icon              import Icons
+    
+class GCPManToolbar(BaseToolbar):
+    """!Toolbar for managing ground control points
+
+    @param parent reference to GCP widget
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        icons = Icons['georectify']
+        return self._getToolbarData((('gcpSave', icons["gcpSave"],
+                                      self.parent.SaveGCPs),
+                                     ('gcpReload', icons["gcpReload"],
+                                      self.parent.ReloadGCPs),
+                                     (None, ),
+                                     ('gcpAdd', icons["gcpAdd"],
+                                      self.parent.AddGCP),
+                                     ('gcpDelete', icons["gcpDelete"],
+                                      self.parent.DeleteGCP),
+                                     ('gcpClear', icons["gcpClear"],
+                                      self.parent.ClearGCP),
+                                     (None, ),
+                                     ('rms', icons["gcpRms"],
+                                      self.parent.OnRMS),
+                                     ('georect', icons["georectify"],
+                                      self.parent.OnGeorect))
+                                    )
+    
+class GCPDisplayToolbar(BaseToolbar):
+    """!GCP Display toolbar
+    """
+    def __init__(self, parent):
+        """!GCP Display toolbar constructor
+        """
+        BaseToolbar.__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['displayWindow']["zoomBack"].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"""
+        icons = Icons['displayWindow']
+        return self._getToolbarData((("displaymap", icons["display"],
+                                      self.parent.OnDraw),
+                                     ("rendermap", icons["render"],
+                                      self.parent.OnRender),
+                                     ("erase", icons["erase"],
+                                      self.parent.OnErase),
+                                     (None, ),
+                                     ("gcpset", Icons["georectify"]["gcpSet"],
+                                      self.parent.OnPointer),
+                                     ("pan", icons["pan"],
+                                      self.parent.OnPan),
+                                     ("zoomin", icons["zoomIn"],
+                                      self.parent.OnZoomIn),
+                                     ("zoomout", icons["zoomOut"],
+                                      self.parent.OnZoomOut),
+                                     ("zoommenu", icons["zoomMenu"],
+                                      self.parent.OnZoomMenuGCP),
+                                     (None, ),
+                                     ("zoomback", icons["zoomBack"],
+                                      self.parent.OnZoomBack),
+                                     ("zoomtomap", icons["zoomExtent"],
+                                      self.parent.OnZoomToMap),
+                                     (None, ),
+                                     ('settings', Icons["georectify"]["settings"],
+                                      self.parent.OnSettings),
+                                     ('help', Icons["misc"]["help"],
+                                      self.parent.OnHelp),
+                                     (None, ),
+                                     ('quit', Icons["georectify"]["quit"],
+                                      self.parent.OnQuit))
+                                    )


Property changes on: grass/trunk/gui/wxpython/gcp/toolbars.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/gmodeler/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gmodeler/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,628 @@
+"""!
+ at package gmodeler.dialogs
+
+ at brief wxGUI Graphical Modeler - dialogs
+
+Classes:
+ - ModelDataDialog
+ - ModelSearchDialog
+ - ModelRelationDialog
+ - ModelParamDialog
+ - ModelItemDialog
+ - ModelLoopDialog
+ - ModelConditionDialog
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+
+from core                 import globalvar
+from gui_core.widgets     import GNotebook
+from core.gcmd            import GError, EncodeString
+from gui_core.dialogs     import ElementDialog, MapLayersDialog
+from gui_core.ghelp       import SearchModuleWindow
+
+from grass.script import task as gtask
+
+class ModelDataDialog(ElementDialog):
+    """!Data item properties dialog"""
+    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Data properties"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        self.parent = parent
+        self.shape = shape
+        
+        label, etype = self._getLabel()
+        ElementDialog.__init__(self, parent, title, label = label, etype = etype)
+                
+        self.element = gselect.Select(parent = self.panel,
+                                      type = prompt)
+        self.element.SetValue(shape.GetValue())
+        
+        self.Bind(wx.EVT_BUTTON, self.OnOK,     self.btnOK)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
+        
+        self.PostInit()
+        
+        if shape.GetValue():
+            self.btnOK.Enable()
+        
+        self._layout()
+        self.SetMinSize(self.GetSize())
+        
+    def _getLabel(self):
+        etype = False
+        prompt = self.shape.GetPrompt()
+        if prompt == 'raster':
+            label = _('Name of raster map:')
+        elif prompt == 'vector':
+            label = _('Name of vector map:')
+        else:
+            etype = True
+            label = _('Name of element:')
+
+        return label, etype
+    
+    def _layout(self):
+        """!Do layout"""
+        self.dataSizer.Add(self.element, proportion=0,
+                      flag=wx.EXPAND | wx.ALL, border=1)
+        
+        self.panel.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+    def OnOK(self, event):
+        """!Ok pressed"""
+        self.shape.SetValue(self.GetElement())
+        if self.etype:
+            elem = self.GetType()
+            if elem == 'rast':
+                self.shape.SetPrompt('raster')
+            elif elem == 'vect':
+                self.shape.SetPrompt('raster')
+        
+        self.parent.canvas.Refresh()
+        self.parent.SetStatusText('', 0)
+        self.shape.SetPropDialog(None)
+        
+        if self.IsModal():
+            event.Skip() 
+        else:
+            self.Destroy()
+    
+    def OnCancel(self, event):
+        """!Cancel pressed"""
+        self.shape.SetPropDialog(None)
+        if self.IsModal():
+            event.Skip()
+        else:
+            self.Destroy()
+class ModelSearchDialog(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, title = _("Add new GRASS module to the model"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        """!Graphical modeler module search window
+        
+        @param parent parent window
+        @param id window id
+        @param title window title
+        @param kwargs wx.Dialogs' arguments
+        """
+        self.parent = parent
+        
+        wx.Dialog.__init__(self, parent = parent, id = id, title = title, **kwargs)
+        self.SetName("ModelerDialog")
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.cmdBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                   label=" %s " % _("Command"))
+        
+        self.cmd_prompt = prompt.GPromptSTC(parent = self)
+        self.search = SearchModuleWindow(parent = self.panel, cmdPrompt = self.cmd_prompt, showTip = True)
+        wx.CallAfter(self.cmd_prompt.SetFocus)
+        
+        # get commands
+        items = self.cmd_prompt.GetCommandItems()
+        
+        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
+        self.btnOk     = wx.Button(self.panel, wx.ID_OK)
+        self.btnOk.SetDefault()
+        self.btnOk.Enable(False)
+
+        self.cmd_prompt.Bind(wx.EVT_KEY_UP, self.OnText)
+        self.search.searchChoice.Bind(wx.EVT_CHOICE, self.OnText)
+        self.Bind(wx.EVT_BUTTON, self.OnOk, self.btnOk)
+        
+        self._layout()
+        
+        self.SetSize((500, 275))
+        
+    def _layout(self):
+        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
+        cmdSizer.Add(item = self.cmd_prompt, proportion = 1,
+                     flag = wx.EXPAND)
+        
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.search, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 3)
+        mainSizer.Add(item = cmdSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.panel.SetSizer(mainSizer)
+        mainSizer.Fit(self.panel)
+        
+        self.Layout()
+
+    def GetPanel(self):
+        """!Get dialog panel"""
+        return self.panel
+
+    def GetCmd(self):
+        """!Get command"""
+        line = self.cmd_prompt.GetCurLine()[0].strip()
+        if len(line) == 0:
+            list()
+        
+        try:
+            cmd = utils.split(str(line))
+        except UnicodeError:
+            cmd = utils.split(EncodeString((line)))
+            
+        return cmd
+    
+    def OnOk(self, event):
+        """!Button 'OK' pressed"""
+        self.btnOk.SetFocus()
+        cmd = self.GetCmd()
+        
+        if len(cmd) < 1:
+            GError(parent = self,
+                   message = _("Command not defined.\n\n"
+                               "Unable to add new action to the model."))
+            return
+        
+        if cmd[0] not in globalvar.grassCmd['all']:
+            GError(parent = self,
+                   message = _("'%s' is not a GRASS module.\n\n"
+                               "Unable to add new action to the model.") % cmd[0])
+            return
+        
+        self.EndModal(wx.ID_OK)
+        
+    def OnText(self, event):
+        """!Text in prompt changed"""
+        if self.cmd_prompt.AutoCompActive():
+            event.Skip()
+            return
+        
+        if isinstance(event, wx.KeyEvent):
+            entry = self.cmd_prompt.GetTextLeft()
+        elif isinstance(event, wx.stc.StyledTextEvent):
+            entry = event.GetText()
+        else:
+            entry = event.GetString()
+        
+        if entry:
+            self.btnOk.Enable()
+        else:
+            self.btnOk.Enable(False)
+            
+        event.Skip()
+        
+    def Reset(self):
+        """!Reset dialog"""
+        self.search.Reset()
+        self.cmd_prompt.OnCmdErase(None)
+        self.btnOk.Enable(False)
+        self.cmd_prompt.SetFocus()
+
+class ModelRelationDialog(wx.Dialog):
+    """!Relation properties dialog"""
+    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Relation properties"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        self.parent = parent
+        self.shape = shape
+        
+        options = self._getOptions()
+        if not options:
+            self.valid = False
+            return
+        
+        self.valid = True
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.fromBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("From"))
+        self.toBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                  label = " %s " % _("To"))
+        
+        self.option = wx.ComboBox(parent = self.panel, id = wx.ID_ANY,
+                                  style = wx.CB_READONLY,
+                                  choices = options)
+        self.option.Bind(wx.EVT_COMBOBOX, self.OnOption)
+        
+        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
+        self.btnOk     = wx.Button(self.panel, wx.ID_OK)
+        self.btnOk.Enable(False)
+        
+        self._layout()
+
+    def _layout(self):
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+
+        fromSizer = wx.StaticBoxSizer(self.fromBox, wx.VERTICAL)
+        self._layoutShape(shape = self.shape.GetFrom(), sizer = fromSizer)
+        toSizer = wx.StaticBoxSizer(self.toBox, wx.VERTICAL)
+        self._layoutShape(shape = self.shape.GetTo(), sizer = toSizer)
+
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+        
+        mainSizer.Add(item = fromSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = toSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.panel.SetSizer(mainSizer)
+        mainSizer.Fit(self.panel)
+        
+        self.Layout()
+        self.SetSize(self.GetBestSize())
+        
+    def _layoutShape(self, shape, sizer):
+        if isinstance(shape, ModelData):
+            sizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                           label = _("Data: %s") % shape.GetLog()),
+                      proportion = 1, flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+        elif isinstance(shape, ModelAction):
+            gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                               label = _("Command:")),
+                          pos = (0, 0))
+            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                               label = shape.GetName()),
+                          pos = (0, 1))
+            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                               label = _("Option:")),
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (1, 0))
+            gridSizer.Add(item = self.option,
+                          pos = (1, 1))
+            sizer.Add(item = gridSizer,
+                      proportion = 1, flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+            
+    def _getOptions(self):
+        """!Get relevant options"""
+        items = []
+        fromShape = self.shape.GetFrom()
+        if not isinstance(fromShape, ModelData):
+            GError(parent = self.parent,
+                   message = _("Relation doesn't start with data item.\n"
+                               "Unable to add relation."))
+            return items
+        
+        toShape = self.shape.GetTo()
+        if not isinstance(toShape, ModelAction):
+            GError(parent = self.parent,
+                   message = _("Relation doesn't point to GRASS command.\n"
+                               "Unable to add relation."))
+            return items
+        
+        prompt = fromShape.GetPrompt()
+        task = toShape.GetTask()
+        for p in task.get_options()['params']:
+            if p.get('prompt', '') == prompt and \
+                    'name' in p:
+                items.append(p['name'])
+        
+        if not items:
+            GError(parent = self.parent,
+                   message = _("No relevant option found.\n"
+                               "Unable to add relation."))
+        return items
+    
+    def GetOption(self):
+        """!Get selected option"""
+        return self.option.GetStringSelection()
+    
+    def IsValid(self):
+        """!Check if relation is valid"""
+        return self.valid
+    
+    def OnOption(self, event):
+        """!Set option"""
+        if event.GetString():
+            self.btnOk.Enable()
+        else:
+            self.btnOk.Enable(False)
+
+class ModelParamDialog(wx.Dialog):
+    def __init__(self, parent, params, id = wx.ID_ANY, title = _("Model parameters"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        """!Model parameters dialog
+        """
+        self.parent = parent
+        self.params = params
+        self.tasks  = list() # list of tasks/pages
+        
+        wx.Dialog.__init__(self, parent = parent, id = id, title = title, style = style, **kwargs)
+        
+        self.notebook = GNotebook(parent = self, 
+                                  style = globalvar.FNPageDStyle)
+        
+        panel = self._createPages()
+        wx.CallAfter(self.notebook.SetSelection, 0)
+        
+        self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+        self.btnRun    = wx.Button(parent = self, id = wx.ID_OK,
+                                   label = _("&Run"))
+        self.btnRun.SetDefault()
+        
+        self._layout()
+        
+        size = self.GetBestSize()
+        self.SetMinSize(size)
+        self.SetSize((size.width, size.height +
+                      panel.constrained_size[1] -
+                      panel.panelMinHeight))
+                
+    def _layout(self):
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnRun)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.notebook, proportion = 1,
+                      flag = wx.EXPAND)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+    def _createPages(self):
+        """!Create for each parameterized module its own page"""
+        nameOrdered = [''] * len(self.params.keys())
+        for name, params in self.params.iteritems():
+            nameOrdered[params['idx']] = name
+        for name in nameOrdered:
+            params = self.params[name]
+            panel = self._createPage(name, params)
+            if name == 'variables':
+                name = _('Variables')
+            self.notebook.AddPage(page = panel, text = name)
+        
+        return panel
+    
+    def _createPage(self, name, params):
+        """!Define notebook page"""
+        if name in globalvar.grassCmd['all']:
+            task = gtask.grassTask(name)
+        else:
+            task = gtask.grassTask()
+        task.flags  = params['flags']
+        task.params = params['params']
+        
+        panel = menuform.cmdPanel(parent = self, id = wx.ID_ANY, task = task)
+        self.tasks.append(task)
+        
+        return panel
+
+    def GetErrors(self):
+        """!Check for errors, get list of messages"""
+        errList = list()
+        for task in self.tasks:
+            errList += task.get_cmd_error()
+        
+        return errList
+
+class ModelItemDialog(wx.Dialog):
+    """!Abstract item properties dialog"""
+    def __init__(self, parent, shape, title, id = wx.ID_ANY,
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        self.parent = parent
+        self.shape = shape
+        
+        wx.Dialog.__init__(self, parent, id, title = title, style = style, **kwargs)
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.condBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label=" %s " % _("Condition"))
+        self.condText = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+                                    value = shape.GetText())
+        
+        self.itemList = ItemCheckListCtrl(parent = self.panel,
+                                          window = self,
+                                          columns = [_("ID"), _("Name"),
+                                                     _("Command")],
+                                          shape = shape)
+        self.itemList.Populate(self.parent.GetModel().GetItems())
+        
+        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.btnOk     = wx.Button(parent = self.panel, id = wx.ID_OK)
+        self.btnOk.SetDefault()
+        
+    def _layout(self):
+        """!Do layout (virtual method)"""
+        pass
+    
+    def GetCondition(self):
+        """!Get loop condition"""
+        return self.condText.GetValue()
+
+class ModelLoopDialog(ModelItemDialog):
+    """!Loop properties dialog"""
+    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Loop properties"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        ModelItemDialog.__init__(self, parent, shape, title,
+                                 style = style, **kwargs)
+        
+        self.listBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label=" %s " % _("List of items in loop"))
+        
+        self.btnSeries = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                   label = _("Series"))
+        self.btnSeries.SetToolTipString(_("Define map series as condition for the loop"))
+        self.btnSeries.Bind(wx.EVT_BUTTON, self.OnSeries)
+        
+        self._layout()
+        self.SetMinSize(self.GetSize())
+        self.SetSize((500, 400))
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        condSizer = wx.StaticBoxSizer(self.condBox, wx.HORIZONTAL)
+        condSizer.Add(item = self.condText, proportion = 1,
+                      flag = wx.ALL, border = 3)
+        condSizer.Add(item = self.btnSeries, proportion = 0,
+                      flag = wx.EXPAND)
+
+        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+        listSizer.Add(item = self.itemList, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+
+        sizer.Add(item = condSizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALL, border = 3)
+        sizer.Add(item = listSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+        sizer.Add(item = btnSizer, proportion=0,
+                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+        
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        
+        self.Layout()
+        
+    def GetItems(self):
+        """!Get list of selected actions"""
+        return self.itemList.GetItems()
+
+    def OnSeries(self, event):
+        """!Define map series as condition"""
+        dialog = MapLayersDialog(parent = self, title = _("Define series of maps"), modeler = True)
+        if dialog.ShowModal() != wx.ID_OK:
+            dialog.Destroy()
+            return
+        
+        cond = dialog.GetDSeries()
+        if not cond:
+            cond = 'map in %s' % map(lambda x: str(x), dialog.GetMapLayers())
+        
+        self.condText.SetValue(cond)
+                               
+        dialog.Destroy()
+
+class ModelConditionDialog(ModelItemDialog):
+    """!Condition properties dialog"""
+    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("If-else properties"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        ModelItemDialog.__init__(self, parent, shape, title,
+                                 style = style, **kwargs)
+        
+        self.listBoxIf = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                      label=" %s " % _("List of items in 'if' block"))
+        self.itemListIf = self.itemList
+        self.itemListIf.SetName('IfBlockList')
+        
+        self.listBoxElse = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                        label=" %s " % _("List of items in 'else' block"))
+        self.itemListElse = ItemCheckListCtrl(parent = self.panel,
+                                              window = self,
+                                              columns = [_("ID"), _("Name"),
+                                                         _("Command")],
+                                              shape = shape)
+        self.itemListElse.SetName('ElseBlockList')
+        self.itemListElse.Populate(self.parent.GetModel().GetItems())
+        
+        self._layout()
+        self.SetMinSize(self.GetSize())
+        self.SetSize((500, 400))
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        condSizer = wx.StaticBoxSizer(self.condBox, wx.VERTICAL)
+        condSizer.Add(item = self.condText, proportion = 1,
+                      flag = wx.EXPAND)
+        
+        listIfSizer = wx.StaticBoxSizer(self.listBoxIf, wx.VERTICAL)
+        listIfSizer.Add(item = self.itemListIf, proportion = 1,
+                        flag = wx.EXPAND)
+        listElseSizer = wx.StaticBoxSizer(self.listBoxElse, wx.VERTICAL)
+        listElseSizer.Add(item = self.itemListElse, proportion = 1,
+                          flag = wx.EXPAND)
+        
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOk)
+        btnSizer.Realize()
+
+        sizer.Add(item = condSizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALL, border = 3)
+        sizer.Add(item = listIfSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+        sizer.Add(item = listElseSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+        sizer.Add(item = btnSizer, proportion=0,
+                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+        
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        
+        self.Layout()
+
+    def OnCheckItemIf(self, index, flag):
+        """!Item in if-block checked/unchecked"""
+        if flag is False:
+            return
+        
+        aId = int(self.itemListIf.GetItem(index, 0).GetText())
+        if aId in self.itemListElse.GetItems()['checked']:
+            self.itemListElse.CheckItemById(aId, False)
+            
+    def OnCheckItemElse(self, index, flag):
+        """!Item in else-block checked/unchecked"""
+        if flag is False:
+            return
+        
+        aId = int(self.itemListElse.GetItem(index, 0).GetText())
+        if aId in self.itemListIf.GetItems()['checked']:
+            self.itemListIf.CheckItemById(aId, False)
+        
+    def GetItems(self):
+        """!Get items"""
+        return { 'if'   : self.itemListIf.GetItems(),
+                 'else' : self.itemListElse.GetItems() }


Property changes on: grass/trunk/gui/wxpython/gmodeler/dialogs.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/gmodeler/frame.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gmodeler.py)
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/frame.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gmodeler/frame.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2656 @@
+"""!
+ at package gmodeler.py
+
+ at brief wxGUI Graphical Modeler for creating, editing, and managing models
+
+Classes:
+ - ModelerData
+ - ModelToolbar
+ - ModelFrame
+ - ModelCanvas
+ - ModelObject
+ - ModelAction
+ - ModelData
+ - ModelEvtHandler
+ - ModelRelation
+ - ModelListCtrl
+ - VariablePanel
+ - ValiableListCtrl
+ - ModelItem
+ - ModelLoop
+ - ItemPanel
+ - ItemListCtrl
+ - ItemCheckListCtrl
+ - ModelCondition
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import time
+import stat
+import textwrap
+import tempfile
+import copy
+import re
+
+import wx
+import wx.lib.ogl             as ogl
+import wx.lib.flatnotebook    as FN
+import wx.lib.mixins.listctrl as listmix
+
+from core                 import globalvar
+from gui_core.widgets     import GNotebook
+from gui_core.goutput     import GMConsole
+from core.debug           import Debug
+from core.gcmd            import GMessage, GException, GWarning, GError, RunCommand
+from gui_core.dialogs     import GetImageHandlers
+from gui_core.preferences import PreferencesBaseDialog
+from core.settings        import UserSettings
+from core.menudata        import MenuData
+from gui_core.toolbars    import BaseToolbar
+
+from grass.script import core as grass
+
+class ModelerData(MenuData):
+    def __init__(self, filename = None):
+        if not filename:
+            gisbase = os.getenv('GISBASE')
+            global etcwxdir
+	    filename = os.path.join(globalvar.ETCWXDIR, 'xml', 'menudata_modeler.xml')
+        
+        MenuData.__init__(self, filename)
+
+class ModelToolbar(BaseToolbar):
+    """!Graphical modeler toolbaro (see gmodeler.py)
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['modeler']
+        return self._getToolbarData((('new', icons['new'],
+                                      self.parent.OnModelNew),
+                                     ('open', icons['open'],
+                                      self.parent.OnModelOpen),
+                                     ('save', icons['save'],
+                                      self.parent.OnModelSave),
+                                     ('image', icons['toImage'],
+                                      self.parent.OnExportImage),
+                                     ('python', icons['toPython'],
+                                      self.parent.OnExportPython),
+                                     (None, ),
+                                     ('action', icons['actionAdd'],
+                                      self.parent.OnAddAction),
+                                     ('data', icons['dataAdd'],
+                                      self.parent.OnAddData),
+                                     ('relation', icons['relation'],
+                                      self.parent.OnDefineRelation),
+                                     ('loop', icons['loop'],
+                                      self.parent.OnDefineLoop),
+                                     (None, ),
+                                     ('redraw', icons['redraw'],
+                                      self.parent.OnCanvasRefresh),
+                                     ('validate', icons['validate'],
+                                      self.parent.OnValidateModel),
+                                     ('run', icons['run'],
+                                      self.parent.OnRunModel),
+                                     (None, ),
+                                     ("variables", icons['variables'],
+                                      self.parent.OnVariables),
+                                     ("settings", icons['settings'],
+                                      self.parent.OnPreferences),
+                                     ("help", Icons['misc']['help'],
+                                      self.parent.OnHelp),
+                                     (None, ),
+                                     ('quit', icons['quit'],
+                                      self.parent.OnCloseWindow))
+                                    
+)
+
+class ModelFrame(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _("GRASS GIS Graphical Modeler"), **kwargs):
+        """!Graphical modeler main window
+        
+        @param parent parent window
+        @param id window id
+        @param title window title
+
+        @param kwargs wx.Frames' arguments
+        """
+        self.parent = parent
+        self.searchDialog = None # module search dialog
+        self.baseTitle = title
+        self.modelFile = None    # loaded model
+        self.modelChanged = False
+        
+        self.cursors = {
+            "default" : wx.StockCursor(wx.CURSOR_ARROW),
+            "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
+            }
+        
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+        self.SetName("Modeler")
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.menubar = Menu(parent = self, data = ModelerData())
+        
+        self.SetMenuBar(self.menubar)
+        
+        self.toolbar = ModelToolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+        
+        self.statusbar = self.CreateStatusBar(number = 1)
+        
+        self.notebook = GNotebook(parent = self,
+                                  style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
+                                  FN.FNB_NO_NAV_BUTTONS | FN.FNB_NO_X_BUTTON)
+        
+        self.canvas = ModelCanvas(self)
+        self.canvas.SetBackgroundColour(wx.WHITE)
+        self.canvas.SetCursor(self.cursors["default"])
+        
+        self.model = Model(self.canvas)
+        
+        self.variablePanel = VariablePanel(parent = self)
+        
+        self.itemPanel = ItemPanel(parent = self)
+        
+        self.goutput = GMConsole(parent = self, notebook = self.notebook)
+        
+        self.notebook.AddPage(page = self.canvas, text=_('Model'), name = 'model')
+        self.notebook.AddPage(page = self.itemPanel, text=_('Items'), name = 'items')
+        self.notebook.AddPage(page = self.variablePanel, text=_('Variables'), name = 'variables')
+        self.notebook.AddPage(page = self.goutput, text=_('Command output'), name = 'output')
+        wx.CallAfter(self.notebook.SetSelectionByName, 'model')
+        wx.CallAfter(self.ModelChanged, False)
+
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+        self._layout()
+        self.SetMinSize((475, 300))
+        self.SetSize((640, 480))
+        
+        # fix goutput's pane size
+        if self.goutput:
+            self.goutput.SetSashPosition(int(self.GetSize()[1] * .75))
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        sizer.Add(item = self.notebook, proportion = 1,
+                  flag = wx.EXPAND)
+        
+        self.SetAutoLayout(True)
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+        
+        self.Layout()
+
+    def _addEvent(self, item):
+        """!Add event to item"""
+        evthandler = ModelEvtHandler(self.statusbar,
+                                     self)
+        evthandler.SetShape(item)
+        evthandler.SetPreviousHandler(item.GetEventHandler())
+        item.SetEventHandler(evthandler)
+
+    def GetCanvas(self):
+        """!Get canvas"""
+        return self.canvas
+    
+    def GetModel(self):
+        """!Get model"""
+        return self.model
+    
+    def ModelChanged(self, changed = True):
+        """!Update window title"""
+        self.modelChanged = changed
+        
+        if self.modelFile:
+            if self.modelChanged:
+                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile) + '*')
+            else:
+                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
+        else:
+            self.SetTitle(self.baseTitle)
+        
+    def OnVariables(self, event):
+        """!Switch to variables page"""
+        self.notebook.SetSelectionByName('variables')
+        
+    def OnRemoveItem(self, event):
+        """!Remove shape
+        """
+        self.GetCanvas().RemoveSelected()
+        
+    def OnCanvasRefresh(self, event):
+        """!Refresh canvas"""
+        self.SetStatusText(_("Redrawing model..."), 0)
+        self.GetCanvas().Refresh()
+        self.SetStatusText("", 0)
+
+    def OnCmdRun(self, event):
+        """!Run command"""
+        try:
+            action = self.GetModel().GetItems()[event.pid]
+            if hasattr(action, "task"):
+                action.Update(running = True)
+        except IndexError:
+            pass
+        
+    def OnCmdPrepare(self, event):
+        """!Prepare for running command"""
+        event.onPrepare(item = event.userData['item'],
+                        params = event.userData['params'])
+        
+    def OnCmdDone(self, event):
+        """!Command done (or aborted)"""
+        try:
+            action = self.GetModel().GetItems()[event.pid]
+            if hasattr(action, "task"):
+                action.Update(running = True)
+        except IndexError:
+            pass
+        
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        if self.modelChanged and \
+                UserSettings.Get(group='manager', key='askOnQuit', subkey='enabled'):
+            if self.modelFile:
+                message = _("Do you want to save changes in the model?")
+            else:
+                message = _("Do you want to store current model settings "
+                            "to model file?")
+            
+            # ask user to save current settings
+            dlg = wx.MessageDialog(self,
+                                   message = message,
+                                   caption=_("Quit Graphical Modeler"),
+                                   style = wx.YES_NO | wx.YES_DEFAULT |
+                                   wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
+            ret = dlg.ShowModal()
+            if ret == wx.ID_YES:
+                if not self.modelFile:
+                        self.OnWorkspaceSaveAs()
+                else:
+                    self.WriteModelFile(self.modelFile)
+            elif ret == wx.ID_CANCEL:
+                dlg.Destroy()
+                return
+            dlg.Destroy()
+        
+        self.Destroy()
+
+    def OnSize(self, event):
+        """Window resized, save to the model"""
+        self.ModelChanged()
+        event.Skip()
+        
+    def OnPreferences(self, event):
+        """!Open preferences dialog"""
+        dlg = PreferencesDialog(parent = self)
+        dlg.CenterOnParent()
+        
+        dlg.ShowModal()
+        self.canvas.Refresh()
+        
+    def OnHelp(self, event):
+        """!Show help"""
+        if self.parent and self.parent.GetName() == 'LayerManager':
+            log = self.parent.GetLogWindow()
+            log.RunCmd(['g.manual',
+                        'entry=wxGUI.Modeler'])
+        else:
+            RunCommand('g.manual',
+                       quiet = True,
+                       entry = 'wxGUI.Modeler')
+        
+    def OnModelProperties(self, event):
+        """!Model properties dialog"""
+        dlg = PropertiesDialog(parent = self)
+        dlg.CentreOnParent()
+        properties = self.model.GetProperties()
+        dlg.Init(properties)
+        if dlg.ShowModal() == wx.ID_OK:
+            self.ModelChanged()
+            for key, value in dlg.GetValues().iteritems():
+                properties[key] = value
+            for action in self.model.GetItems(objType = ModelAction):
+                action.GetTask().set_flag('overwrite', properties['overwrite'])
+        
+        dlg.Destroy()
+        
+    def OnDeleteData(self, event):
+        """!Delete intermediate data"""
+        rast, vect, rast3d, msg = self.model.GetIntermediateData()
+        
+        if not rast and not vect and not rast3d:
+            GMessage(parent = self,
+                     message = _('Nothing to delete.'))
+            return
+        
+        dlg = wx.MessageDialog(parent = self,
+                               message= _("Do you want to permanently delete data?%s" % msg),
+                               caption=_("Delete intermediate data?"),
+                               style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+        
+        ret = dlg.ShowModal()
+        if ret == wx.ID_YES:
+            dlg.Destroy()
+            
+            if rast:
+                self.goutput.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
+            if rast3d:
+                self.goutput.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
+            if vect:
+                self.goutput.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
+            
+            self.SetStatusText(_("%d maps deleted from current mapset") % \
+                                 int(len(rast) + len(rast3d) + len(vect)))
+            return
+        
+        dlg.Destroy()
+                
+    def OnModelNew(self, event):
+        """!Create new model"""
+        Debug.msg(4, "ModelFrame.OnModelNew():")
+        
+        # ask user to save current model
+        if self.modelFile and self.modelChanged:
+            self.OnModelSave()
+        elif self.modelFile is None and \
+                (self.model.GetNumItems() > 0 or len(self.model.GetData()) > 0):
+            dlg = wx.MessageDialog(self, message=_("Current model is not empty. "
+                                                   "Do you want to store current settings "
+                                                   "to model file?"),
+                                   caption=_("Create new model?"),
+                                   style=wx.YES_NO | wx.YES_DEFAULT |
+                                   wx.CANCEL | wx.ICON_QUESTION)
+            ret = dlg.ShowModal()
+            if ret == wx.ID_YES:
+                self.OnModelSaveAs()
+            elif ret == wx.ID_CANCEL:
+                dlg.Destroy()
+                return
+            
+            dlg.Destroy()
+        
+        # delete all items
+        self.canvas.GetDiagram().DeleteAllShapes()
+        self.model.Reset()
+        self.canvas.Refresh()
+        self.itemPanel.Update()
+        self.variablePanel.Reset()
+        
+        # no model file loaded
+        self.modelFile = None
+        self.modelChanged = False
+        self.SetTitle(self.baseTitle)
+        
+    def OnModelOpen(self, event):
+        """!Load model from file"""
+        filename = ''
+        dlg = wx.FileDialog(parent = self, message=_("Choose model file"),
+                            defaultDir = os.getcwd(),
+                            wildcard=_("GRASS Model File (*.gxm)|*.gxm"))
+        if dlg.ShowModal() == wx.ID_OK:
+            filename = dlg.GetPath()
+                    
+        if not filename:
+            return
+        
+        Debug.msg(4, "ModelFrame.OnModelOpen(): filename=%s" % filename)
+        
+        # close current model
+        self.OnModelClose()
+        
+        self.LoadModelFile(filename)
+        
+        self.modelFile = filename
+        self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
+        self.SetStatusText(_('%(items)d items (%(actions)d actions) loaded into model') % \
+                               { 'items' : self.model.GetNumItems(),
+                                 'actions' : self.model.GetNumItems(actionOnly = True) }, 0)
+        
+    def OnModelSave(self, event = None):
+        """!Save model to file"""
+        if self.modelFile and self.modelChanged:
+            dlg = wx.MessageDialog(self, message=_("Model file <%s> already exists. "
+                                                   "Do you want to overwrite this file?") % \
+                                       self.modelFile,
+                                   caption=_("Save model"),
+                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+            if dlg.ShowModal() == wx.ID_NO:
+                dlg.Destroy()
+            else:
+                Debug.msg(4, "ModelFrame.OnModelSave(): filename=%s" % self.modelFile)
+                self.WriteModelFile(self.modelFile)
+                self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
+                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
+        elif not self.modelFile:
+            self.OnModelSaveAs(None)
+        
+    def OnModelSaveAs(self, event):
+        """!Create model to file as"""
+        filename = ''
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose file to save current model"),
+                            defaultDir = os.getcwd(),
+                            wildcard=_("GRASS Model File (*.gxm)|*.gxm"),
+                            style=wx.FD_SAVE)
+        
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            filename = dlg.GetPath()
+        
+        if not filename:
+            return
+        
+        # check for extension
+        if filename[-4:] != ".gxm":
+            filename += ".gxm"
+        
+        if os.path.exists(filename):
+            dlg = wx.MessageDialog(parent = self,
+                                   message=_("Model file <%s> already exists. "
+                                             "Do you want to overwrite this file?") % filename,
+                                   caption=_("File already exists"),
+                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+            if dlg.ShowModal() != wx.ID_YES:
+                dlg.Destroy()
+                return
+        
+        Debug.msg(4, "GMFrame.OnModelSaveAs(): filename=%s" % filename)
+        
+        self.WriteModelFile(filename)
+        self.modelFile = filename
+        self.SetTitle(self.baseTitle + " - " + os.path.basename(self.modelFile))
+        self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
+
+    def OnModelClose(self, event = None):
+        """!Close model file"""
+        Debug.msg(4, "ModelFrame.OnModelClose(): file=%s" % self.modelFile)
+        # ask user to save current model
+        if self.modelFile and self.modelChanged:
+            self.OnModelSave()
+        elif self.modelFile is None and \
+                (self.model.GetNumItems() > 0 or len(self.model.GetData()) > 0):
+            dlg = wx.MessageDialog(self, message=_("Current model is not empty. "
+                                                   "Do you want to store current settings "
+                                                   "to model file?"),
+                                   caption=_("Create new model?"),
+                                   style=wx.YES_NO | wx.YES_DEFAULT |
+                                   wx.CANCEL | wx.ICON_QUESTION)
+            ret = dlg.ShowModal()
+            if ret == wx.ID_YES:
+                self.OnModelSaveAs()
+            elif ret == wx.ID_CANCEL:
+                dlg.Destroy()
+                return
+            
+            dlg.Destroy()
+        
+        self.modelFile = None
+        self.SetTitle(self.baseTitle)
+        
+        self.canvas.GetDiagram().DeleteAllShapes()
+        self.model.Reset()
+        
+        self.canvas.Refresh()
+        
+    def OnRunModel(self, event):
+        """!Run entire model"""
+        self.model.Run(self.goutput, self.OnDone, parent = self)
+        
+    def OnDone(self, cmd, returncode):
+        """!Computation finished"""
+        self.SetStatusText('', 0)
+        # restore original files
+        if hasattr(self.model, "fileInput"):
+            for finput in self.model.fileInput:
+                data = self.model.fileInput[finput]
+                if not data:
+                    continue
+                
+                fd = open(finput, "w")
+                try:
+                    fd.write(data)
+                finally:
+                    fd.close()
+            del self.model.fileInput
+        
+    def OnValidateModel(self, event, showMsg = True):
+        """!Validate entire model"""
+        if self.model.GetNumItems() < 1:
+            GMessage(parent = self, 
+                     message = _('Model is empty. Nothing to validate.'))
+            return
+        
+        
+        self.SetStatusText(_('Validating model...'), 0)
+        errList = self.model.Validate()
+        self.SetStatusText('', 0)
+        
+        if errList:
+            GWarning(parent = self,
+                     message = _('Model is not valid.\n\n%s') % '\n'.join(errList))
+        else:
+            GMessage(parent = self,
+                     message = _('Model is valid.'))
+    
+    def OnExportImage(self, event):
+        """!Export model to image (default image)
+        """
+        xminImg = 0
+        xmaxImg = 0
+        yminImg = 0
+        ymaxImg = 0
+        # get current size of canvas
+        for shape in self.canvas.GetDiagram().GetShapeList():
+            w, h = shape.GetBoundingBoxMax()
+            x    = shape.GetX()
+            y    = shape.GetY()
+            xmin = x - w / 2
+            xmax = x + w / 2
+            ymin = y - h / 2
+            ymax = y + h / 2
+            if xmin < xminImg:
+                xminImg = xmin
+            if xmax > xmaxImg:
+                xmaxImg = xmax
+            if ymin < yminImg:
+                yminImg = ymin
+            if ymax > ymaxImg:
+                ymaxImg = ymax
+        size = wx.Size(int(xmaxImg - xminImg) + 50,
+                       int(ymaxImg - yminImg) + 50)
+        bitmap = wx.EmptyBitmap(width = size.width, height = size.height)
+        
+        filetype, ltype = GetImageHandlers(wx.ImageFromBitmap(bitmap))
+        
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to save the image (no need to add extension)"),
+                            defaultDir = "",
+                            defaultFile = "",
+                            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
+            
+            dc = wx.MemoryDC(bitmap)
+            dc.SetBackground(wx.WHITE_BRUSH)
+            dc.SetBackgroundMode(wx.SOLID)
+            
+            dc.BeginDrawing()
+            self.canvas.GetDiagram().Clear(dc)
+            self.canvas.GetDiagram().Redraw(dc)
+            dc.EndDrawing()
+            
+            bitmap.SaveFile(path, fileType)
+            self.SetStatusText(_("Model exported to <%s>") % path)
+        
+        dlg.Destroy()
+        
+    def OnExportPython(self, event):
+        """!Export model to Python script"""
+        filename = ''
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose file to save"),
+                            defaultDir = os.getcwd(),
+                            wildcard=_("Python script (*.py)|*.py"),
+                            style=wx.FD_SAVE)
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            filename = dlg.GetPath()
+        
+        if not filename:
+            return
+        
+        # check for extension
+        if filename[-3:] != ".py":
+            filename += ".py"
+        
+        if os.path.exists(filename):
+            dlg = wx.MessageDialog(self, message=_("File <%s> already exists. "
+                                                   "Do you want to overwrite this file?") % filename,
+                                   caption=_("Save file"),
+                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+            if dlg.ShowModal() == wx.ID_NO:
+                dlg.Destroy()
+                return
+            
+            dlg.Destroy()
+        
+        fd = open(filename, "w")
+        try:
+            WritePythonFile(fd, self.model)
+        finally:
+            fd.close()
+        
+        # executable file
+        os.chmod(filename, stat.S_IRWXU | stat.S_IWUSR)
+        
+        self.SetStatusText(_("Model exported to <%s>") % filename)
+
+    def OnDefineRelation(self, event):
+        """!Define relation between data and action items"""
+        self.canvas.SetCursor(self.cursors["cross"])
+        self.defineRelation = { 'from' : None,
+                                'to'   : None }
+        
+    def OnDefineLoop(self, event):
+        """!Define new loop in the model"""
+        self.ModelChanged()
+        
+        width, height = self.canvas.GetSize()
+        loop = ModelLoop(self, x = width/2, y = height/2,
+                         id = self.model.GetNumItems() + 1)
+        self.canvas.diagram.AddShape(loop)
+        loop.Show(True)
+        
+        self._addEvent(loop)
+        self.model.AddItem(loop)
+        
+        self.canvas.Refresh()
+        
+    def OnDefineCondition(self, event):
+        """!Define new condition in the model"""
+        self.ModelChanged()
+        
+        width, height = self.canvas.GetSize()
+        cond = ModelCondition(self, x = width/2, y = height/2,
+                              id = self.model.GetNumItems() + 1)
+        self.canvas.diagram.AddShape(cond)
+        cond.Show(True)
+        
+        self._addEvent(cond)
+        self.model.AddItem(cond)
+        
+        self.canvas.Refresh()
+    
+    def OnAddAction(self, event):
+        """!Add action to model"""
+        if self.searchDialog is None:
+            self.searchDialog = ModelSearchDialog(self)
+            self.searchDialog.CentreOnParent()
+        else:
+            self.searchDialog.Reset()
+            
+        if self.searchDialog.ShowModal() == wx.ID_CANCEL:
+            self.searchDialog.Hide()
+            return
+            
+        cmd = self.searchDialog.GetCmd()
+        self.searchDialog.Hide()
+        
+        self.ModelChanged()
+        
+        # add action to canvas
+        width, height = self.canvas.GetSize()
+        action = ModelAction(self.model, cmd = cmd, x = width/2, y = height/2,
+                             id = self.model.GetNextId())
+        overwrite = self.model.GetProperties().get('overwrite', None)
+        if overwrite is not None:
+            action.GetTask().set_flag('overwrite', overwrite)
+        
+        self.canvas.diagram.AddShape(action)
+        action.Show(True)
+
+        self._addEvent(action)
+        self.model.AddItem(action)
+        
+        self.itemPanel.Update()
+        self.canvas.Refresh()
+        time.sleep(.1)
+        
+        # show properties dialog
+        win = action.GetPropDialog()
+        if not win:
+            if action.IsValid():
+                self.GetOptData(dcmd = action.GetLog(string = False), layer = action,
+                                params = action.GetParams(), propwin = None)
+            else:
+                GUI(parent = self, show = True).ParseCommand(action.GetLog(string = False),
+                                                             completed = (self.GetOptData, action, action.GetParams()))
+        elif win and not win.IsShown():
+            win.Show()
+        
+        if win:
+            win.Raise()
+        
+    def OnAddData(self, event):
+        """!Add data item to model
+        """
+        # add action to canvas
+        width, height = self.canvas.GetSize()
+        data = ModelData(self, x = width/2, y = height/2)
+       
+        dlg = ModelDataDialog(parent = self, shape = data)
+        data.SetPropDialog(dlg)
+        dlg.CentreOnParent()
+        ret = dlg.ShowModal()
+        dlg.Destroy()
+        if ret != wx.ID_OK:
+            return
+        
+        data.Update()
+        self.canvas.diagram.AddShape(data)
+        data.Show(True)
+        
+        self.ModelChanged()
+        
+        self._addEvent(data)
+        self.model.AddItem(data)
+        
+        self.canvas.Refresh()
+        
+        
+    def OnHelp(self, event):
+        """!Display manual page"""
+        grass.run_command('g.manual',
+                          entry = 'wxGUI.Modeler')
+
+    def OnAbout(self, event):
+        """!Display About window"""
+        info = wx.AboutDialogInfo()
+
+        info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        info.SetName(_('wxGUI Graphical Modeler'))
+        info.SetWebSite('http://grass.osgeo.org')
+        year = grass.version()['date']
+        info.SetDescription(_('(C) 2010-%s by the GRASS Development Team\n\n') % year + 
+                            '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
+                                                      '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
+        
+        wx.AboutBox(info)
+        
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """!Process action data"""
+        if params: # add data items
+            width, height = self.canvas.GetSize()
+            x = [width/2 + 200, width/2 - 200]
+            for p in params['params']:
+                if p.get('prompt', '') in ('raster', 'vector', 'raster3d') and \
+                        (p.get('value', None) or \
+                             (p.get('age', 'old') != 'old' and p.get('required', 'no') == 'yes')):
+                    data = layer.FindData(p.get('name', ''))
+                    if data:
+                        data.SetValue(p.get('value', ''))
+                        data.Update()
+                        continue
+                    
+                    data = self.model.FindData(p.get('value', ''),
+                                               p.get('prompt', ''))
+                    if data:
+                        if p.get('age', 'old') == 'old':
+                            rel = ModelRelation(parent = self, fromShape = data,
+                                                toShape = layer, param = p.get('name', ''))
+                        else:
+                            rel = ModelRelation(parent = self, fromShape = layer,
+                                                toShape = data, param = p.get('name', ''))
+                        layer.AddRelation(rel)
+                        data.AddRelation(rel)
+                        self.AddLine(rel)
+                        data.Update()
+                        continue
+                    
+                    data = ModelData(self, value = p.get('value', ''),
+                                     prompt = p.get('prompt', ''),
+                                     x = x.pop(), y = height/2)
+                    self._addEvent(data)
+                    self.canvas.diagram.AddShape(data)
+                    data.Show(True)
+                                                            
+                    if p.get('age', 'old') == 'old':
+                        rel = ModelRelation(parent = self, fromShape = data,
+                                            toShape = layer, param = p.get('name', ''))
+                    else:
+                        rel = ModelRelation(parent = self, fromShape = layer,
+                                            toShape = data, param = p.get('name', ''))
+                    layer.AddRelation(rel)
+                    data.AddRelation(rel)
+                    self.AddLine(rel)
+                    data.Update()
+            
+            # valid / parameterized ?
+            layer.SetValid(params)
+            
+            self.canvas.Refresh()
+        
+        if dcmd:
+            layer.SetProperties(params, propwin)
+            
+        self.SetStatusText(layer.GetLog(), 0)
+        
+    def AddLine(self, rel):
+        """!Add connection between model objects
+        
+        @param rel relation
+        """
+        fromShape = rel.GetFrom()
+        toShape   = rel.GetTo()
+        
+        rel.SetCanvas(self)
+        rel.SetPen(wx.BLACK_PEN)
+        rel.SetBrush(wx.BLACK_BRUSH)
+        rel.AddArrow(ogl.ARROW_ARROW)
+        points = rel.GetControlPoints()
+        rel.MakeLineControlPoints(2)
+        if points:
+            for x, y in points:
+                rel.InsertLineControlPoint(point = wx.RealPoint(x, y))
+        
+        self._addEvent(rel)
+        try:
+            fromShape.AddLine(rel, toShape)
+        except TypeError:
+            pass # bug when connecting ModelCondition and ModelLoop - to be fixed
+        
+        self.canvas.diagram.AddShape(rel)
+        rel.Show(True)
+        
+    def LoadModelFile(self, filename):
+        """!Load model definition stored in GRASS Model XML file (gxm)
+        """
+        try:
+            self.model.LoadModel(filename)
+        except GException, e:
+            GError(parent = self,
+                   message = _("Reading model file <%s> failed.\n"
+                               "Invalid file, unable to parse XML document.") % filename)
+        
+        self.modelFile = filename
+        self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
+        
+        self.SetStatusText(_("Please wait, loading model..."), 0)
+        
+        # load actions
+        for item in self.model.GetItems(objType = ModelAction):
+            self._addEvent(item)
+            self.canvas.diagram.AddShape(item)
+            item.Show(True)
+            # relations/data
+            for rel in item.GetRelations():
+                if rel.GetFrom() == item:
+                    dataItem = rel.GetTo()
+                else:
+                    dataItem = rel.GetFrom()
+                self._addEvent(dataItem)
+                self.canvas.diagram.AddShape(dataItem)
+                self.AddLine(rel)
+                dataItem.Show(True)
+        
+        # load loops
+        for item in self.model.GetItems(objType = ModelLoop):
+            self._addEvent(item)
+            self.canvas.diagram.AddShape(item)
+            item.Show(True)
+            
+            # connect items in the loop
+            self.DefineLoop(item)
+
+        # load conditions
+        for item in self.model.GetItems(objType = ModelCondition):
+            self._addEvent(item)
+            self.canvas.diagram.AddShape(item)
+            item.Show(True)
+            
+            # connect items in the condition
+            self.DefineCondition(item)
+        
+        # load variables
+        self.variablePanel.Update()
+        self.itemPanel.Update()
+        self.SetStatusText('', 0)
+        
+        # final updates
+        for action in self.model.GetItems(objType = ModelAction):
+            action.SetValid(action.GetParams())
+            action.Update()
+        
+        self.canvas.Refresh(True)
+        
+    def WriteModelFile(self, filename):
+        """!Save model to model file, recover original file on error.
+        
+        @return True on success
+        @return False on failure
+        """
+        self.ModelChanged(False)
+        tmpfile = tempfile.TemporaryFile(mode='w+b')
+        try:
+            WriteModelFile(fd = tmpfile, model = self.model)
+        except StandardError:
+            GError(parent = self,
+                   message = _("Writing current settings to model file failed."))
+            return False
+        
+        try:
+            mfile = open(filename, "w")
+            tmpfile.seek(0)
+            for line in tmpfile.readlines():
+                mfile.write(line)
+        except IOError:
+            wx.MessageBox(parent = self,
+                          message = _("Unable to open file <%s> for writing.") % filename,
+                          caption = _("Error"),
+                          style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return False
+        
+        mfile.close()
+        
+        return True
+    
+    def DefineLoop(self, loop):
+        """!Define loop with given list of items"""
+        parent = loop
+        items = loop.GetItems()
+        if not items:
+            return
+        
+        # remove defined relations first
+        for rel in loop.GetRelations():
+            self.canvas.GetDiagram().RemoveShape(rel)
+        loop.Clear()
+        
+        for item in items:
+            rel = ModelRelation(parent = self, fromShape = parent, toShape = item)
+            dx = item.GetX() - parent.GetX()
+            dy = item.GetY() - parent.GetY()
+            loop.AddRelation(rel)
+            if dx != 0:
+                rel.SetControlPoints(((parent.GetX(), parent.GetY() + dy / 2),
+                                      (parent.GetX() + dx, parent.GetY() + dy / 2)))
+            self.AddLine(rel)
+            parent = item
+        
+        # close loop
+        item = loop.GetItems()[-1]
+        rel = ModelRelation(parent = self, fromShape = item, toShape = loop)
+        loop.AddRelation(rel)
+        self.AddLine(rel)
+        dx = (item.GetX() - loop.GetX()) + loop.GetWidth() / 2 + 50
+        dy = item.GetHeight() / 2 + 50
+        rel.MakeLineControlPoints(0)
+        rel.InsertLineControlPoint(point = wx.RealPoint(loop.GetX() - loop.GetWidth() / 2 ,
+                                                        loop.GetY()))
+        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
+                                                        item.GetY() + item.GetHeight() / 2))
+        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
+                                                        item.GetY() + dy))
+        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
+                                                        item.GetY() + dy))
+        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
+                                                        loop.GetY()))
+        
+        self.canvas.Refresh()
+
+    def DefineCondition(self, condition):
+        """!Define if-else statement with given list of items"""
+        parent = condition
+        items = condition.GetItems()
+        if not items['if'] and not items['else']:
+            return
+        
+        # remove defined relations first
+        for rel in condition.GetRelations():
+            self.canvas.GetDiagram().RemoveShape(rel)
+        condition.Clear()
+        dxIf   = condition.GetX() + condition.GetWidth() / 2
+        dxElse = condition.GetX() - condition.GetWidth() / 2
+        dy     = condition.GetY()
+        for branch in items.keys():
+            for item in items[branch]:
+                rel = ModelRelation(parent = self, fromShape = parent,
+                                    toShape = item)
+                condition.AddRelation(rel)
+                self.AddLine(rel)
+                rel.MakeLineControlPoints(0)
+                if branch == 'if':
+                    rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
+                    rel.InsertLineControlPoint(point = wx.RealPoint(dxIf, dy))
+                else:
+                    rel.InsertLineControlPoint(point = wx.RealPoint(dxElse, dy))
+                    rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
+                parent = item
+        
+        self.canvas.Refresh()
+        
+class ModelCanvas(ogl.ShapeCanvas):
+    """!Canvas where model is drawn"""
+    def __init__(self, parent):
+        self.parent = parent
+        ogl.OGLInitialize()
+        ogl.ShapeCanvas.__init__(self, parent)
+        
+        self.diagram = ogl.Diagram()
+        self.SetDiagram(self.diagram)
+        self.diagram.SetCanvas(self)
+        
+        self.SetScrollbars(20, 20, 1000/20, 1000/20)
+        
+        self.Bind(wx.EVT_CHAR,  self.OnChar)
+        
+    def OnChar(self, event):
+        """!Key pressed"""
+        kc = event.GetKeyCode()
+        diagram = self.GetDiagram()
+        if kc == wx.WXK_DELETE:
+            self.RemoveSelected()
+        
+    def RemoveSelected(self):
+        """!Remove selected shapes"""
+        self.parent.ModelChanged()
+        
+        diagram = self.GetDiagram()
+        for shape in diagram.GetShapeList():
+            if not shape.Selected():
+                continue
+            remList, upList = self.parent.GetModel().RemoveItem(shape)
+            shape.Select(False)
+            diagram.RemoveShape(shape)
+            shape.__del__()
+            for item in remList:
+                diagram.RemoveShape(item)
+                item.__del__()
+            
+            for item in upList:
+                item.Update()
+        
+        self.Refresh()
+        
+class ModelObject:
+    def __init__(self, id = -1):
+        self.id   = id
+        self.rels = list() # list of ModelRelations
+        
+        self.isEnabled = True
+        self.inBlock   = list() # list of related loops/conditions
+        
+    def __del__(self):
+        pass
+    
+    def GetId(self):
+        """!Get id"""
+        return self.id
+    
+    def AddRelation(self, rel):
+        """!Record new relation
+        """
+        self.rels.append(rel)
+
+    def GetRelations(self, fdir = None):
+        """!Get list of relations
+        
+        @param fdir True for 'from'
+        """
+        if fdir is None:
+            return self.rels
+        
+        result = list()
+        for rel in self.rels:
+            if fdir == 'from':
+                if rel.GetFrom() == self:
+                    result.append(rel)
+            else:
+                if rel.GetTo() == self:
+                    result.append(rel)
+        
+        return result
+    
+    def IsEnabled(self):
+        """!Get True if action is enabled, otherwise False"""
+        return self.isEnabled
+    
+    def Enable(self, enabled = True):
+        """!Enable/disable action"""
+        self.isEnabled = enabled
+        self.Update()
+
+    def Update(self):
+        pass
+
+    def SetBlock(self, item):
+        """!Add object to the block (loop/condition)
+
+        @param item reference to ModelLoop or ModelCondition which
+        defines loops/condition
+        """
+        if item not in self.inBlock:
+            self.inBlock.append(item)
+        
+    def UnSetBlock(self, item):
+        """!Remove object from the block (loop/consition)
+
+        @param item reference to ModelLoop or ModelCondition which
+        defines loops/codition
+        """
+        if item in self.inBlock:
+            self.inBlock.remove(item)
+        
+    def GetBlock(self):
+        """!Get list of related ModelObject(s) which defines block
+        (loop/condition)
+
+        @return list of ModelObjects
+        """
+        return self.inBlock
+    
+    def GetBlockId(self):
+        """!Get list of related ids which defines block
+
+        @return list of ids
+        """
+        ret = list()
+        for mo in self.inBlock:
+            ret.append(mo.GetId())
+        
+        return ret
+    
+class ModelAction(ModelObject, ogl.RectangleShape):
+    """!Action class (GRASS module)"""
+    def __init__(self, parent, x, y, id = -1, cmd = None, task = None, width = None, height = None):
+        ModelObject.__init__(self, id)
+        
+        self.parent  = parent
+        self.task    = task
+        
+        if not width:
+            width = UserSettings.Get(group='modeler', key='action', subkey=('size', 'width'))
+        if not height:
+            height = UserSettings.Get(group='modeler', key='action', subkey=('size', 'height'))
+        
+        if cmd:
+            self.task = GUI(show = None).ParseCommand(cmd = cmd)
+        else:
+            if task:
+                self.task = task
+            else:
+                self.task = None
+        
+        self.propWin = None
+        
+        self.data = list()   # list of connected data items
+        
+        self.isValid = False
+        self.isParameterized = False
+        
+        if self.parent.GetCanvas():
+            ogl.RectangleShape.__init__(self, width, height)
+            
+            self.SetCanvas(self.parent)
+            self.SetX(x)
+            self.SetY(y)
+            self.SetPen(wx.BLACK_PEN)
+            self._setPen()
+            self._setBrush()
+            self.SetId(id)
+        
+        if self.task:
+            self.SetValid(self.task.get_options())
+        
+    def _setBrush(self, running = False):
+        """!Set brush"""
+        if running:
+            color = UserSettings.Get(group='modeler', key='action',
+                                     subkey=('color', 'running'))
+        elif not self.isEnabled:
+            color = UserSettings.Get(group='modeler', key='disabled',
+                                     subkey='color')
+        elif self.isValid:
+            color = UserSettings.Get(group='modeler', key='action',
+                                     subkey=('color', 'valid'))
+        else:
+            color = UserSettings.Get(group='modeler', key='action',
+                                     subkey=('color', 'invalid'))
+        
+        wxColor = wx.Color(color[0], color[1], color[2])
+        self.SetBrush(wx.Brush(wxColor))
+        
+    def _setPen(self):
+        """!Set pen"""
+        if self.isParameterized:
+            width = int(UserSettings.Get(group='modeler', key='action',
+                                         subkey=('width', 'parameterized')))
+        else:
+            width = int(UserSettings.Get(group='modeler', key='action',
+                                         subkey=('width', 'default')))
+        pen = self.GetPen()
+        pen.SetWidth(width)
+        self.SetPen(pen)
+
+    def SetId(self, id):
+        """!Set id"""
+        self.id = id
+        cmd = self.task.get_cmd(ignoreErrors = True)
+        if cmd and len(cmd) > 0:
+            self.ClearText()
+            self.AddText('(%d) %s' % (self.id, cmd[0]))
+        else:
+            self.AddText('(%d) <<%s>>' % (self.id, _("unknown")))
+        
+    def SetProperties(self, params, propwin):
+        """!Record properties dialog"""
+        self.task.params = params['params']
+        self.task.flags  = params['flags']
+        self.propWin = propwin
+
+    def GetPropDialog(self):
+        """!Get properties dialog"""
+        return self.propWin
+
+    def GetLog(self, string = True, substitute = None):
+        """!Get logging info
+
+        @param string True to get cmd as a string otherwise a list
+        @param substitute dictionary of parameter to substitute or None
+        """
+        cmd = self.task.get_cmd(ignoreErrors = True, ignoreRequired = True,
+                                ignoreDefault = False)
+        
+        # substitute variables
+        if substitute:
+            variables = []
+            if 'variables' in substitute:
+                for p in substitute['variables']['params']:
+                    variables.append(p.get('name', ''))
+            else:
+                variables = self.parent.GetVariables()
+            for variable in variables:
+                pattern= re.compile('%' + variable)
+                value = ''
+                if substitute and 'variables' in substitute:
+                    for p in substitute['variables']['params']:
+                        if variable == p.get('name', ''):
+                            if p.get('type', 'string') == 'string':
+                                value = p.get('value', '')
+                            else:
+                                value = str(p.get('value', ''))
+                            break
+                    
+                if not value:
+                    value = variables[variable].get('value', '')
+                
+                if not value:
+                    continue
+                
+                for idx in range(len(cmd)):
+                    if pattern.search(cmd[idx]):
+                        cmd[idx] = pattern.sub(value, cmd[idx])
+                        break
+                    idx += 1
+        
+        if string:
+            if cmd is None:
+                return ''
+            else:
+                return ' '.join(cmd)
+        
+        return cmd
+    
+    def GetName(self):
+        """!Get name"""
+        cmd = self.task.get_cmd(ignoreErrors = True)
+        if cmd and len(cmd) > 0:
+            return cmd[0]
+        
+        return _('unknown')
+
+    def GetParams(self, dcopy = False):
+        """!Get dictionary of parameters"""
+        if dcopy:
+            return copy.deepcopy(self.task.get_options())
+        
+        return self.task.get_options()
+
+    def GetTask(self):
+        """!Get grassTask instance"""
+        return self.task
+    
+    def SetParams(self, params):
+        """!Set dictionary of parameters"""
+        self.task.params = params['params']
+        self.task.flags  = params['flags']
+        
+    def MergeParams(self, params):
+        """!Merge dictionary of parameters"""
+        if 'flags' in params:
+            for f in params['flags']:
+                self.task.set_flag(f['name'],
+                                   f.get('value', False))
+        if 'params' in params:
+            for p in params['params']:
+                self.task.set_param(p['name'],
+                                    p.get('value', ''))
+        
+    def SetValid(self, options):
+        """!Set validity for action
+        
+        @param options dictionary with flags and params (gtask)
+        """
+        self.isValid = True
+        self.isParameterized = False
+        
+        for f in options['flags']:
+            if f.get('parameterized', False):
+                self.IsParameterized = True
+                break
+        
+        for p in options['params']:
+            if self.isValid and p.get('required', False) and \
+                    p.get('value', '') == '' and \
+                    p.get('default', '') == '':
+                self.isValid = False
+            if not self.isParameterized and p.get('parameterized', False):
+                self.isParameterized = True
+        
+        if self.parent.GetCanvas():
+            self._setBrush()
+            self._setPen()
+        
+    def IsValid(self):
+        """!Check validity (all required parameters set)"""
+        return self.isValid
+    
+    def IsParameterized(self):
+        """!Check if action is parameterized"""
+        return self.isParameterized
+    
+    def FindData(self, name):
+        """!Find data item by name"""
+        for rel in self.GetRelations():
+            data = rel.GetData()
+            if name == rel.GetName() and name in data.GetName():
+                return data
+        
+        return None
+
+    def Update(self, running = False):
+        """!Update action"""
+        if running:
+            self._setBrush(running = True)
+        else:
+            self._setBrush()
+        self._setPen()
+
+    def OnDraw(self, dc):
+        """!Draw action in canvas"""
+        self._setBrush()
+        self._setPen()
+        ogl.RectangleShape.OnDraw(self, dc)
+
+class ModelData(ModelObject, ogl.EllipseShape):
+    def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
+        """Data item class
+        
+        @param parent window parent
+        @param x, y   position of the shape
+        @param fname, tname list of parameter names from / to
+        @param value  value
+        @param prompt type of GIS element
+        @param width,height dimension of the shape
+        """
+        ModelObject.__init__(self)
+        
+        self.parent  = parent
+        self.value   = value
+        self.prompt  = prompt
+        self.intermediate = False
+        self.propWin = None
+        if not width:
+            width = UserSettings.Get(group='modeler', key='data', subkey=('size', 'width'))
+        if not height:
+            height = UserSettings.Get(group='modeler', key='data', subkey=('size', 'height'))
+        
+        if self.parent.GetCanvas():
+            ogl.EllipseShape.__init__(self, width, height)
+            
+            self.SetCanvas(self.parent)
+            self.SetX(x)
+            self.SetY(y)
+            self.SetPen(wx.BLACK_PEN)
+            self._setBrush()
+            
+            self._setText()
+            
+    def IsIntermediate(self):
+        """!Checks if data item is intermediate"""
+        return self.intermediate
+    
+    def SetIntermediate(self, im):
+        """!Set intermediate flag"""
+        self.intermediate = im
+  
+    def OnDraw(self, dc):
+        pen = self.GetPen()
+        pen.SetWidth(1)
+        if self.intermediate:
+            pen.SetStyle(wx.SHORT_DASH)
+        else:
+            pen.SetStyle(wx.SOLID)
+        self.SetPen(pen)
+        
+        ogl.EllipseShape.OnDraw(self, dc)
+        
+    def GetLog(self, string = True):
+        """!Get logging info"""
+        name = list()
+        for rel in self.GetRelations():
+            name.append(rel.GetName())
+        if name:
+            return '/'.join(name) + '=' + self.value + ' (' + self.prompt + ')'
+        else:
+            return self.value + ' (' + self.prompt + ')'
+
+    def GetName(self):
+        """!Get list of names"""
+        name = list()
+        for rel in self.GetRelations():
+            name.append(rel.GetName())
+        
+        return name
+    
+    def GetPrompt(self):
+        """!Get prompt"""
+        return self.prompt
+
+    def SetPrompt(self, prompt):
+        """!Set prompt
+        
+        @param prompt
+        """
+        self.prompt = prompt
+        
+    def GetValue(self):
+        """!Get value"""
+        return self.value
+
+    def SetValue(self, value):
+        """!Set value
+
+        @param value
+        """
+        self.value = value
+        self._setText()
+        for direction in ('from', 'to'):
+            for rel in self.GetRelations(direction):
+                if direction == 'from':
+                    action = rel.GetTo()
+                else:
+                    action = rel.GetFrom()
+                
+                task = GUI(show = None).ParseCommand(cmd = action.GetLog(string = False))
+                task.set_param(rel.GetName(), self.value)
+                action.SetParams(params = task.get_options())
+        
+    def GetPropDialog(self):
+        """!Get properties dialog"""
+        return self.propWin
+
+    def SetPropDialog(self, win):
+        """!Get properties dialog"""
+        self.propWin = win
+
+    def _setBrush(self):
+        """!Set brush"""
+        if self.prompt == 'raster':
+            color = UserSettings.Get(group = 'modeler', key = 'data',
+                                     subkey = ('color', 'raster'))
+        elif self.prompt == 'raster3d':
+            color = UserSettings.Get(group = 'modeler', key = 'data',
+                                     subkey = ('color', 'raster3d'))
+        elif self.prompt == 'vector':
+            color = UserSettings.Get(group = 'modeler', key = 'data',
+                                     subkey = ('color', 'vector'))
+        else:
+            color = UserSettings.Get(group = 'modeler', key = 'action',
+                                     subkey = ('color', 'invalid'))
+        wxColor = wx.Color(color[0], color[1], color[2])
+        self.SetBrush(wx.Brush(wxColor))
+        
+    def _setPen(self):
+        """!Set pen"""
+        isParameterized = False
+        for rel in self.GetRelations('from'):
+            if rel.GetTo().IsParameterized():
+                isParameterized = True
+                break
+        if not isParameterized:
+            for rel in self.GetRelations('to'):
+                if rel.GetFrom().IsParameterized():
+                    isParameterized = True
+                    break
+
+        if isParameterized:
+            width = int(UserSettings.Get(group = 'modeler', key = 'action',
+                                         subkey = ('width', 'parameterized')))
+        else:
+            width = int(UserSettings.Get(group = 'modeler', key = 'action',
+                                         subkey = ('width', 'default')))
+        pen = self.GetPen()
+        pen.SetWidth(width)
+        self.SetPen(pen)
+        
+    def _setText(self):
+        """!Update text"""
+        self.ClearText()
+        name = []
+        for rel in self.GetRelations():
+            name.append(rel.GetName())
+        self.AddText('/'.join(name))
+        if self.value:
+            self.AddText(self.value)
+        else:
+            self.AddText(_('<not defined>'))
+        
+    def Update(self):
+        """!Update action"""
+        self._setBrush()
+        self._setPen()
+        self._setText()
+       
+class ModelEvtHandler(ogl.ShapeEvtHandler):
+    """!Model event handler class"""
+    def __init__(self, log, frame):
+        ogl.ShapeEvtHandler.__init__(self)
+        self.log = log
+        self.frame = frame
+        self.x = self.y = None
+        
+    def OnLeftClick(self, x, y, keys = 0, attachment = 0):
+        """!Left mouse button pressed -> select item & update statusbar"""
+        shape = self.GetShape()
+        canvas = shape.GetCanvas()
+        dc = wx.ClientDC(canvas)
+        canvas.PrepareDC(dc)
+        
+        if hasattr(self.frame, 'defineRelation'):
+            drel = self.frame.defineRelation
+            if drel['from'] is None:
+                drel['from'] = shape
+            elif drel['to'] is None:
+                drel['to'] = shape
+                rel = ModelRelation(parent = self.frame, fromShape = drel['from'],
+                                    toShape = drel['to'])
+                dlg = ModelRelationDialog(parent = self.frame,
+                                          shape = rel)
+                if dlg.IsValid():
+                    ret = dlg.ShowModal()
+                    if ret == wx.ID_OK:
+                        option = dlg.GetOption()
+                        rel.SetName(option)
+                        drel['from'].AddRelation(rel)
+                        drel['to'].AddRelation(rel)
+                        drel['from'].Update()
+                        params = { 'params' : [{ 'name' : option,
+                                                 'value' : drel['from'].GetValue()}] }
+                        drel['to'].MergeParams(params)
+                        self.frame.AddLine(rel)
+                
+                    dlg.Destroy()
+                del self.frame.defineRelation
+        
+        if shape.Selected():
+            shape.Select(False, dc)
+        else:
+            redraw = False
+            shapeList = canvas.GetDiagram().GetShapeList()
+            toUnselect = list()
+            
+            for s in shapeList:
+                if s.Selected():
+                    toUnselect.append(s)
+            
+            shape.Select(True, dc)
+            
+            for s in toUnselect:
+                s.Select(False, dc)
+                
+        canvas.Refresh(False)
+
+        if hasattr(shape, "GetLog"):
+            self.log.SetStatusText(shape.GetLog(), 0)
+        else:
+            self.log.SetStatusText('', 0)
+        
+    def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
+        """!Left mouse button pressed (double-click) -> show properties"""
+        self.OnProperties()
+        
+    def OnProperties(self, event = None):
+        """!Show properties dialog"""
+        self.frame.ModelChanged()
+        shape = self.GetShape()
+        if isinstance(shape, ModelAction):
+            module = GUI(parent = self.frame, show = True).ParseCommand(shape.GetLog(string = False),
+                                                                        completed = (self.frame.GetOptData, shape, shape.GetParams()))
+        
+        elif isinstance(shape, ModelData):
+            dlg = ModelDataDialog(parent = self.frame, shape = shape)
+            shape.SetPropDialog(dlg)
+            dlg.CentreOnParent()
+            dlg.Show()
+        
+        elif isinstance(shape, ModelLoop):
+            dlg = ModelLoopDialog(parent = self.frame, shape = shape)
+            dlg.CentreOnParent()
+            if dlg.ShowModal() == wx.ID_OK:
+                shape.SetText(dlg.GetCondition())
+                alist = list()
+                ids = dlg.GetItems()
+                for aId in ids['unchecked']:
+                    action = self.frame.GetModel().GetItem(aId)
+                    action.UnSetBlock(shape)
+                for aId in ids['checked']:
+                    action = self.frame.GetModel().GetItem(aId)
+                    action.SetBlock(shape)
+                    if action:
+                        alist.append(action)
+                shape.SetItems(alist)
+                self.frame.DefineLoop(shape)
+                self.frame.SetStatusText(shape.GetLog(), 0)
+            self.frame.GetCanvas().Refresh()
+            
+            dlg.Destroy()
+        
+        elif isinstance(shape, ModelCondition):
+            dlg = ModelConditionDialog(parent = self.frame, shape = shape)
+            dlg.CentreOnParent()
+            if dlg.ShowModal() == wx.ID_OK:
+                shape.SetText(dlg.GetCondition())
+                ids = dlg.GetItems()
+                for b in ids.keys():
+                    alist = list()
+                    for aId in ids[b]['unchecked']:
+                        action = self.frame.GetModel().GetItem(aId)
+                        action.UnSetBlock(shape)
+                    for aId in ids[b]['checked']:
+                        action = self.frame.GetModel().GetItem(aId)
+                        action.SetBlock(shape)
+                        if action:
+                            alist.append(action)
+                    shape.SetItems(alist, branch = b)
+                self.frame.DefineCondition(shape)
+            self.frame.GetCanvas().Refresh()
+            
+            dlg.Destroy()
+                   
+    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
+        """!Drag shape (begining)"""
+        self.frame.ModelChanged()
+        if self._previousHandler:
+            self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
+        
+    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
+        """!Drag shape (end)"""
+        if self._previousHandler:
+            self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
+        
+        shape = self.GetShape()
+        if isinstance(shape, ModelLoop):
+            self.frame.DefineLoop(shape)
+        elif isinstance(shape, ModelCondition):
+            self.frame.DefineCondition(shape)
+        
+        for mo in shape.GetBlock():
+            if isinstance(mo, ModelLoop):
+                self.frame.DefineLoop(mo)
+            elif isinstance(mo, ModelCondition):
+                self.frame.DefineCondition(mo)
+        
+    def OnEndSize(self, x, y):
+        """!Resize shape"""
+        self.frame.ModelChanged()
+        if self._previousHandler:
+            self._previousHandler.OnEndSize(x, y)
+        
+    def OnRightClick(self, x, y, keys = 0, attachment = 0):
+        """!Right click -> pop-up menu"""
+        if not hasattr (self, "popupID"):
+            self.popupID = dict()
+            for key in ('remove', 'enable', 'addPoint',
+                        'delPoint', 'intermediate', 'props', 'id'):
+                self.popupID[key] = wx.NewId()
+        
+        # record coordinates
+        self.x = x
+        self.y = y
+        
+        shape = self.GetShape()
+        popupMenu = wx.Menu()
+        popupMenu.Append(self.popupID['remove'], text=_('Remove'))
+        self.frame.Bind(wx.EVT_MENU, self.OnRemove, id = self.popupID['remove'])
+        if isinstance(shape, ModelAction) or isinstance(shape, ModelLoop):
+            if shape.IsEnabled():
+                popupMenu.Append(self.popupID['enable'], text=_('Disable'))
+                self.frame.Bind(wx.EVT_MENU, self.OnDisable, id = self.popupID['enable'])
+            else:
+                popupMenu.Append(self.popupID['enable'], text=_('Enable'))
+                self.frame.Bind(wx.EVT_MENU, self.OnEnable, id = self.popupID['enable'])
+        
+        if isinstance(shape, ModelRelation):
+            popupMenu.AppendSeparator()
+            popupMenu.Append(self.popupID['addPoint'], text=_('Add control point'))
+            self.frame.Bind(wx.EVT_MENU, self.OnAddPoint, id = self.popupID['addPoint'])
+            popupMenu.Append(self.popupID['delPoint'], text=_('Remove control point'))
+            self.frame.Bind(wx.EVT_MENU, self.OnRemovePoint, id = self.popupID['delPoint'])
+            if len(shape.GetLineControlPoints()) == 2:
+                popupMenu.Enable(self.popupID['delPoint'], False)
+        
+        if isinstance(shape, ModelData) and '@' not in shape.GetValue():
+            popupMenu.AppendSeparator()
+            popupMenu.Append(self.popupID['intermediate'], text=_('Intermediate'),
+                             kind = wx.ITEM_CHECK)
+            if self.GetShape().IsIntermediate():
+                popupMenu.Check(self.popupID['intermediate'], True)
+            
+            self.frame.Bind(wx.EVT_MENU, self.OnIntermediate, id = self.popupID['intermediate'])
+            
+        if isinstance(shape, ModelData) or \
+                isinstance(shape, ModelAction) or \
+                isinstance(shape, ModelLoop):
+            popupMenu.AppendSeparator()
+            popupMenu.Append(self.popupID['props'], text=_('Properties'))
+            self.frame.Bind(wx.EVT_MENU, self.OnProperties, id = self.popupID['props'])
+        
+        self.frame.PopupMenu(popupMenu)
+        popupMenu.Destroy()
+
+    def OnDisable(self, event):
+        """!Disable action"""
+        self._onEnable(False)
+        
+    def OnEnable(self, event):
+        """!Disable action"""
+        self._onEnable(True)
+        
+    def _onEnable(self, enable):
+        shape = self.GetShape()
+        shape.Enable(enable)
+        self.frame.ModelChanged()
+        self.frame.canvas.Refresh()
+        
+    def OnAddPoint(self, event):
+        """!Add control point"""
+        shape = self.GetShape()
+        shape.InsertLineControlPoint(point = wx.RealPoint(self.x, self.y))
+        shape.ResetShapes()
+        shape.Select(True)
+        self.frame.ModelChanged()
+        self.frame.canvas.Refresh()
+        
+    def OnRemovePoint(self, event):
+        """!Remove control point"""
+        shape = self.GetShape()
+        shape.DeleteLineControlPoint()
+        shape.Select(False)
+        shape.Select(True)
+        self.frame.ModelChanged()
+        self.frame.canvas.Refresh()
+        
+    def OnIntermediate(self, event):
+        """!Mark data as intermediate"""
+        self.frame.ModelChanged()
+        shape = self.GetShape()
+        shape.SetIntermediate(event.IsChecked())
+        self.frame.canvas.Refresh()
+
+    def OnRemove(self, event):
+        """!Remove shape
+        """
+        self.frame.GetCanvas().RemoveSelected()
+        self.frame.itemPanel.Update()
+        
+class ModelRelation(ogl.LineShape):
+    """!Data - action relation"""
+    def __init__(self, parent, fromShape, toShape, param = ''):
+        self.fromShape = fromShape
+        self.toShape   = toShape
+        self.param     = param
+        self.parent    = parent
+        
+        self._points    = None
+        
+        if self.parent.GetCanvas():        
+            ogl.LineShape.__init__(self)
+    
+    def __del__(self):
+        if self in self.fromShape.rels:
+            self.fromShape.rels.remove(self)
+        if self in self.toShape.rels:
+            self.toShape.rels.remove(self)
+        
+    def GetFrom(self):
+        """!Get id of 'from' shape"""
+        return self.fromShape
+    
+    def GetTo(self):
+        """!Get id of 'to' shape"""
+        return self.toShape
+    
+    def GetData(self):
+        """!Get related ModelData instance
+
+        @return ModelData instance
+        @return None if not found
+        """
+        if isinstance(self.fromShape, ModelData):
+            return self.fromShape
+        elif isinstance(self.toShape, ModelData):
+            return self.toShape
+        
+        return None
+    
+    def GetName(self):
+        """!Get parameter name"""
+        return self.param
+    
+    def ResetShapes(self):
+        """!Reset related objects"""
+        self.fromShape.ResetControlPoints()
+        self.toShape.ResetControlPoints()
+        self.ResetControlPoints()
+        
+    def SetControlPoints(self, points):
+        """!Set control points"""
+        self._points = points
+        
+    def GetControlPoints(self):
+        """!Get list of control points"""
+        return self._points
+    
+    def _setPen(self):
+        """!Set pen"""
+        pen = self.GetPen()
+        pen.SetWidth(1)
+        pen.SetStyle(wx.SOLID)
+        self.SetPen(pen)
+        
+    def OnDraw(self, dc):
+        """!Draw relation"""
+        self._setPen()
+        ogl.LineShape.OnDraw(self, dc)
+    
+    def SetName(self, param):
+        self.param = param
+        
+class ModelListCtrl(wx.ListCtrl,
+                    listmix.ListCtrlAutoWidthMixin,
+                    listmix.TextEditMixin,
+                    listmix.ColumnSorterMixin):
+    def __init__(self, parent, columns, id = wx.ID_ANY,
+                 style = wx.LC_REPORT | wx.BORDER_NONE |
+                 wx.LC_SORT_ASCENDING |wx.LC_HRULES |
+                 wx.LC_VRULES, **kwargs):
+        """!List of model variables"""
+        self.parent = parent
+        self.columns = columns
+        self.shape = None
+        try:
+            self.frame  = parent.parent
+        except AttributeError:
+            self.frame = None
+        
+        wx.ListCtrl.__init__(self, parent, id = id, style = style, **kwargs)
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.TextEditMixin.__init__(self)
+        listmix.ColumnSorterMixin.__init__(self, 4)
+        
+        i = 0
+        for col in columns:
+            self.InsertColumn(i, col)
+            self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
+            i += 1
+        
+        self.itemDataMap = {} # requested by sorter
+        self.itemCount   = 0
+        
+        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit)
+        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit)
+        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
+        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
+        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)            #wxGTK
+                
+    def OnBeginEdit(self, event):
+        """!Editing of item started"""
+        event.Allow()
+
+    def OnEndEdit(self, event):
+        """!Finish editing of item"""
+        pass
+    
+    def OnColClick(self, event):
+        """!Click on column header (order by)"""
+        event.Skip()
+
+class VariablePanel(wx.Panel):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 **kwargs):
+        """!Manage model variables panel
+        """
+        self.parent = parent
+        
+        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+        
+        self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                    label=" %s " % _("List of variables - right-click to delete"))
+        
+        self.list = VariableListCtrl(parent = self,
+                                     columns = [_("Name"), _("Data type"),
+                                                _("Default value"), _("Description")])
+        
+        # add new category
+        self.addBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                   label = " %s " % _("Add new variable"))
+        self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        wx.CallAfter(self.name.SetFocus)
+        self.type = wx.Choice(parent = self, id = wx.ID_ANY,
+                              choices = [_("integer"),
+                                         _("float"),
+                                         _("string"),
+                                         _("raster"),
+                                         _("vector"),
+                                         _("mapset"),
+                                         _("file")])
+        self.type.SetSelection(2) # string
+        self.value = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        self.desc = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        
+        # buttons
+        self.btnAdd = wx.Button(parent = self, id = wx.ID_ADD)
+        self.btnAdd.SetToolTipString(_("Add new variable to the model"))
+        self.btnAdd.Enable(False)
+        
+        # bindings
+        self.name.Bind(wx.EVT_TEXT, self.OnText)
+        self.value.Bind(wx.EVT_TEXT, self.OnText)
+        self.desc.Bind(wx.EVT_TEXT, self.OnText)
+        self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAdd)
+        
+        self._layout()
+
+    def _layout(self):
+        """!Layout dialog"""
+        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+        listSizer.Add(item = self.list, proportion = 1,
+                      flag = wx.EXPAND)
+        
+        addSizer = wx.StaticBoxSizer(self.addBox, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridSizer.AddGrowableCol(1)
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Name")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 0))
+        gridSizer.Add(item = self.name,
+                      pos = (0, 1),
+                      flag = wx.EXPAND)
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Data type")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 2))
+        gridSizer.Add(item = self.type,
+                      pos = (0, 3))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Default value")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1, 0))
+        gridSizer.Add(item = self.value,
+                      pos = (1, 1), span = (1, 3),
+                      flag = wx.EXPAND)
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = "%s:" % _("Description")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 0))
+        gridSizer.Add(item = self.desc,
+                      pos = (2, 1), span = (1, 3),
+                      flag = wx.EXPAND)
+        addSizer.Add(item = gridSizer,
+                     flag = wx.EXPAND)
+        addSizer.Add(item = self.btnAdd, proportion = 0,
+                     flag = wx.TOP | wx.ALIGN_RIGHT, border = 5)
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = listSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        mainSizer.Add(item = addSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALIGN_CENTER |
+                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+    def OnText(self, event):
+        """!Text entered"""
+        if self.name.GetValue():
+            self.btnAdd.Enable()
+        else:
+            self.btnAdd.Enable(False)
+    
+    def OnAdd(self, event):
+        """!Add new variable to the list"""
+        msg = self.list.Append(self.name.GetValue(),
+                               self.type.GetStringSelection(),
+                               self.value.GetValue(),
+                               self.desc.GetValue())
+        self.name.SetValue('')
+        self.name.SetFocus()
+        
+        if msg:
+            GError(parent = self,
+                   message = msg)
+        else:
+            self.type.SetSelection(2) # string
+            self.value.SetValue('')
+            self.desc.SetValue('')
+            self.UpdateModelVariables()
+        
+    def UpdateModelVariables(self):
+        """!Update model variables"""
+        variables = dict()
+        for values in self.list.GetData().itervalues():
+            name = values[0]
+            variables[name] = { 'type' : str(values[1]) }
+            if values[2]:
+                variables[name]['value'] = values[2]
+            if values[3]:
+                variables[name]['description'] = values[3]
+        
+        self.parent.GetModel().SetVariables(variables)
+        self.parent.ModelChanged()
+
+    def Update(self):
+        """!Reload list of variables"""
+        self.list.OnReload(None)
+        
+    def Reset(self):
+        """!Remove all variables"""
+        self.list.DeleteAllItems()
+        self.parent.GetModel().SetVariables([])
+        
+class VariableListCtrl(ModelListCtrl):
+    def __init__(self, parent, columns, **kwargs):
+        """!List of model variables"""
+        ModelListCtrl.__init__(self, parent, columns, **kwargs)
+
+        self.SetColumnWidth(2, 200) # default value
+
+    def GetListCtrl(self):
+        """!Used by ColumnSorterMixin"""
+        return self
+    
+    def GetData(self):
+        """!Get list data"""
+        return self.itemDataMap
+    
+    def Populate(self, data):
+        """!Populate the list"""
+        self.itemDataMap = dict()
+        i = 0
+        for name, values in data.iteritems():
+            self.itemDataMap[i] = [name, values['type'],
+                                   values.get('value', ''),
+                                   values.get('description', '')]
+            i += 1
+        
+        self.itemCount = len(self.itemDataMap.keys())
+        self.DeleteAllItems()
+        i = 0
+        for name, vtype, value, desc in self.itemDataMap.itervalues():
+            index = self.InsertStringItem(sys.maxint, name)
+            self.SetStringItem(index, 0, name)
+            self.SetStringItem(index, 1, vtype)
+            self.SetStringItem(index, 2, value)
+            self.SetStringItem(index, 3, desc)
+            self.SetItemData(index, i)
+            i += 1
+        
+    def Append(self, name, vtype, value, desc):
+        """!Append new item to the list
+
+        @return None on success
+        @return error string
+        """
+        for iname, ivtype, ivalue, idesc in self.itemDataMap.itervalues():
+            if iname == name:
+                return _("Variable <%s> already exists in the model. "
+                         "Adding variable failed.") % name
+        
+        index = self.InsertStringItem(sys.maxint, name)
+        self.SetStringItem(index, 0, name)
+        self.SetStringItem(index, 1, vtype)
+        self.SetStringItem(index, 2, value)
+        self.SetStringItem(index, 3, desc)
+        self.SetItemData(index, self.itemCount)
+        
+        self.itemDataMap[self.itemCount] = [name, vtype, value, desc]
+        self.itemCount += 1
+        
+        return None
+
+    def OnRemove(self, event):
+        """!Remove selected variable(s) from the model"""
+        item = self.GetFirstSelected()
+        while item != -1:
+            self.DeleteItem(item)
+            del self.itemDataMap[item]
+            item = self.GetFirstSelected()
+        self.parent.UpdateModelVariables()
+        
+        event.Skip()
+        
+    def OnRemoveAll(self, event):
+        """!Remove all variable(s) from the model"""
+        dlg = wx.MessageBox(parent=self,
+                            message=_("Do you want to delete all variables from "
+                                      "the model?"),
+                            caption=_("Delete variables"),
+                            style=wx.YES_NO | wx.CENTRE)
+        if dlg != wx.YES:
+            return
+        
+        self.DeleteAllItems()
+        self.itemDataMap = dict()
+        
+        self.parent.UpdateModelVariables()
+        
+    def OnEndEdit(self, event):
+        """!Finish editing of item"""
+        itemIndex = event.GetIndex()
+        columnIndex = event.GetColumn()
+        nameOld = self.GetItem(itemIndex, 0).GetText()
+
+        if columnIndex == 0: # TODO
+            event.Veto()
+        
+        self.itemDataMap[itemIndex][columnIndex] = event.GetText()
+        
+        self.parent.UpdateModelVariables()
+
+    def OnReload(self, event):
+        """!Reload list of variables"""
+        self.Populate(self.parent.parent.GetModel().GetVariables())
+
+    def OnRightUp(self, event):
+        """!Mouse right button up"""
+        if not hasattr(self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.popupID3 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
+            self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
+            self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
+        
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupID1, _("Delete selected"))
+        menu.Append(self.popupID2, _("Delete all"))
+        if self.GetFirstSelected() == -1:
+            menu.Enable(self.popupID1, False)
+            menu.Enable(self.popupID2, False)
+        
+        menu.AppendSeparator()
+        menu.Append(self.popupID3, _("Reload"))
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+        
+class ModelItem(ModelObject):
+    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
+        """!Abstract class for loops and conditions"""
+        ModelObject.__init__(self, id)
+        self.parent  = parent
+        self.text    = text
+        self.items   = items  # list of items in the loop
+        
+    def GetText(self):
+        """!Get loop text"""
+        return self.text
+
+    def GetItems(self):
+        """!Get items (id)"""
+        return self.items
+
+    def SetId(self, id):
+        """!Set loop id"""
+        self.id = id
+
+    def SetText(self, cond):
+        """!Set loop text (condition)"""
+        self.text = cond
+        self.ClearText()
+        self.AddText('(' + str(self.id) + ') ' + self.text)
+
+    def GetLog(self):
+        """!Get log info"""
+        if self.text:
+            return _("Condition: ") + self.text
+        else:
+            return _("Condition: not defined")
+
+    def AddRelation(self, rel):
+        """!Record relation"""
+        self.rels.append(rel)
+        
+    def Clear(self):
+        """!Clear object, remove rels"""
+        self.rels = list()
+   
+class ModelLoop(ModelItem, ogl.RectangleShape):
+    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
+        """!Defines a loop"""
+        ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
+        
+        if not width:
+            width = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'width'))
+        if not height:
+            height = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'height'))
+        
+        if self.parent.GetCanvas():
+            ogl.RectangleShape.__init__(self, width, height)
+            
+            self.SetCanvas(self.parent)
+            self.SetX(x)
+            self.SetY(y)
+            self.SetPen(wx.BLACK_PEN)
+            self.SetCornerRadius(100)
+            if text:
+                self.AddText('(' + str(self.id) + ') ' + text)
+            else:
+                self.AddText('(' + str(self.id) + ')')
+        
+        self._setBrush()
+        
+    def _setBrush(self):
+        """!Set brush"""
+        if not self.isEnabled:
+            color = UserSettings.Get(group='modeler', key='disabled',
+                                     subkey='color')
+        else:
+            color = UserSettings.Get(group='modeler', key='loop',
+                                     subkey=('color', 'valid'))
+        
+        wxColor = wx.Color(color[0], color[1], color[2])
+        self.SetBrush(wx.Brush(wxColor))
+
+    def Enable(self, enabled = True):
+        """!Enable/disable action"""
+        for item in self.items:
+            if not isinstance(item, ModelAction):
+                continue
+            item.Enable(enabled)
+        
+        ModelObject.Enable(self, enabled)
+        
+    def Update(self):
+        self._setBrush()
+        
+    def GetName(self):
+        """!Get name"""
+        return _("loop")
+    
+    def SetItems(self, items):
+        """!Set items (id)"""
+        self.items = items
+
+class ItemPanel(wx.Panel):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 **kwargs):
+        """!Manage model items
+        """
+        self.parent = parent
+        
+        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+        
+        self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                    label=" %s " % _("List of items - right-click to delete"))
+        
+        self.list = ItemListCtrl(parent = self,
+                                 columns = [_("ID"), _("Name"), _("In block"),
+                                            _("Command / Condition")])
+        
+        self._layout()
+
+    def _layout(self):
+        """!Layout dialog"""
+        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+        listSizer.Add(item = self.list, proportion = 1,
+                      flag = wx.EXPAND)
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = listSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+    def Update(self):
+        """!Reload list of variables"""
+        self.list.OnReload(None)
+        
+class ItemListCtrl(ModelListCtrl):
+    def __init__(self, parent, columns, disablePopup = False, **kwargs):
+        """!List of model actions"""
+        self.disablePopup = disablePopup
+                
+        ModelListCtrl.__init__(self, parent, columns, **kwargs)
+        self.SetColumnWidth(1, 100)
+        self.SetColumnWidth(2, 65)
+        
+    def GetListCtrl(self):
+        """!Used by ColumnSorterMixin"""
+        return self
+    
+    def GetData(self):
+        """!Get list data"""
+        return self.itemDataMap
+    
+    def Populate(self, data):
+        """!Populate the list"""
+        self.itemDataMap = dict()
+        
+        if self.shape:
+            if isinstance(self.shape, ModelCondition):
+                if self.GetName() == 'ElseBlockList':
+                    shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['else'])
+                else:
+                    shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['if'])
+            else:
+                shapeItems = map(lambda x: x.GetId(), self.shape.GetItems())
+        else:
+            shapeItems = list()
+        
+        i = 0
+        if len(self.columns) == 3: # ItemCheckList
+            checked = list()
+        for action in data:
+            if isinstance(action, ModelData) or \
+                    action == self.shape:
+                continue
+            
+            if len(self.columns) == 3:
+                self.itemDataMap[i] = [str(action.GetId()),
+                                       action.GetName(),
+                                       action.GetLog()]
+                aId = action.GetBlockId()
+                if action.GetId() in shapeItems:
+                    checked.append(aId)
+                else:
+                    checked.append(None)
+            else:
+                bId = action.GetBlockId()
+                if not bId:
+                    bId = ''
+                self.itemDataMap[i] = [str(action.GetId()),
+                                       action.GetName(),
+                                       ','.join(map(str, bId)),
+                                       action.GetLog()]
+            
+            i += 1
+        
+        self.itemCount = len(self.itemDataMap.keys())
+        self.DeleteAllItems()
+        i = 0
+        if len(self.columns) == 3:
+            for aid, name, desc in self.itemDataMap.itervalues():
+                index = self.InsertStringItem(sys.maxint, aid)
+                self.SetStringItem(index, 0, aid)
+                self.SetStringItem(index, 1, name)
+                self.SetStringItem(index, 2, desc)
+                self.SetItemData(index, i)
+                if checked[i]:
+                    self.CheckItem(index, True)
+                i += 1
+        else:
+            for aid, name, inloop, desc in self.itemDataMap.itervalues():
+                index = self.InsertStringItem(sys.maxint, aid)
+                self.SetStringItem(index, 0, aid)
+                self.SetStringItem(index, 1, name)
+                self.SetStringItem(index, 2, inloop)
+                self.SetStringItem(index, 3, desc)
+                self.SetItemData(index, i)
+                i += 1
+                
+    def OnRemove(self, event):
+        """!Remove selected action(s) from the model"""
+        model = self.frame.GetModel()
+        canvas = self.frame.GetCanvas()
+        
+        item = self.GetFirstSelected()
+        while item != -1:
+            self.DeleteItem(item)
+            del self.itemDataMap[item]
+            
+            aId = self.GetItem(item, 0).GetText()
+            action = model.GetItem(int(aId))
+            if not action:
+                item = self.GetFirstSelected()
+                continue
+            
+            model.RemoveItem(action)
+            canvas.GetDiagram().RemoveShape(action)
+            self.frame.ModelChanged()
+            
+            item = self.GetFirstSelected()
+        
+        canvas.Refresh()
+        
+        event.Skip()
+    
+    def OnRemoveAll(self, event):
+        """!Remove all variable(s) from the model"""
+        deleteDialog = wx.MessageBox(parent=self,
+                                     message=_("Selected data records (%d) will permanently deleted "
+                                               "from table. Do you want to delete them?") % \
+                                         (len(self.listOfSQLStatements)),
+                                     caption=_("Delete records"),
+                                     style=wx.YES_NO | wx.CENTRE)
+        if deleteDialog != wx.YES:
+            return False
+        
+        self.DeleteAllItems()
+        self.itemDataMap = dict()
+
+        self.parent.UpdateModelVariables()
+
+    def OnEndEdit(self, event):
+        """!Finish editing of item"""
+        itemIndex = event.GetIndex()
+        columnIndex = event.GetColumn()
+        
+        self.itemDataMap[itemIndex][columnIndex] = event.GetText()
+        
+        aId = int(self.GetItem(itemIndex, 0).GetText())
+        action = self.frame.GetModel().GetItem(aId)
+        if not action:
+            event.Veto()
+        if columnIndex == 0:
+            action.SetId(int(event.GetText()))
+        
+        self.frame.ModelChanged()
+
+    def OnReload(self, event = None):
+        """!Reload list of actions"""
+        self.Populate(self.frame.GetModel().GetItems())
+
+    def OnRightUp(self, event):
+        """!Mouse right button up"""
+        if self.disablePopup:
+            return
+        
+        if not hasattr(self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.popupID3 = wx.NewId()
+            self.popupID4 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
+            self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
+            self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
+            self.Bind(wx.EVT_MENU, self.OnNormalize, id = self.popupID4)
+
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupID1, _("Delete selected"))
+        menu.Append(self.popupID2, _("Delete all"))
+        if self.GetFirstSelected() == -1:
+            menu.Enable(self.popupID1, False)
+            menu.Enable(self.popupID2, False)
+        
+        menu.AppendSeparator()
+        menu.Append(self.popupID4, _("Normalize"))
+        menu.Append(self.popupID3, _("Reload"))
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+    
+    def OnNormalize(self, event):
+        """!Update id of actions"""
+        model = self.frame.GetModel()
+        
+        aId = 1
+        for item in model.GetItems():
+            item.SetId(aId)
+            aId += 1
+        
+        self.OnReload(None)
+        self.frame.GetCanvas().Refresh()
+        self.frame.ModelChanged()
+
+class ItemCheckListCtrl(ItemListCtrl, listmix.CheckListCtrlMixin):
+    def __init__(self, parent, shape, columns, window = None, **kwargs):
+        self.parent = parent
+        self.window = window
+        
+        ItemListCtrl.__init__(self, parent, columns, disablePopup = True, **kwargs)
+        listmix.CheckListCtrlMixin.__init__(self)
+        self.SetColumnWidth(0, 50)
+        
+        self.shape  = shape
+        
+    def OnBeginEdit(self, event):
+        """!Disable editing"""
+        event.Veto()
+        
+    def OnCheckItem(self, index, flag):
+        """!Item checked/unchecked"""
+        name = self.GetName()
+        if name == 'IfBlockList' and self.window:
+            self.window.OnCheckItemIf(index, flag)
+        elif name == 'ElseBlockList' and self.window:
+            self.window.OnCheckItemElse(index, flag)
+        
+    def GetItems(self):
+        """!Get list of selected actions"""
+        ids = { 'checked'   : list(),
+                'unchecked' : list() }
+        for i in range(self.GetItemCount()):
+            iId = int(self.GetItem(i, 0).GetText())
+            if self.IsChecked(i):
+                ids['checked'].append(iId)
+            else:
+                ids['unchecked'].append(iId)
+            
+        return ids
+
+    def CheckItemById(self, aId, flag):
+        """!Check/uncheck given item by id"""
+        for i in range(self.GetItemCount()):
+            iId = int(self.GetItem(i, 0).GetText())
+            if iId == aId:
+                self.CheckItem(i, flag)
+                break
+        
+class ModelCondition(ModelItem, ogl.PolygonShape):
+    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '',
+                 items = { 'if' : [], 'else' : [] }):
+        """!Defines a if-else condition"""
+        ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
+        
+        if not width:
+            self.width = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'width'))
+        else:
+            self.width = width
+        if not height:
+            self.height = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'height'))
+        else:
+            self.height = height
+        
+        if self.parent.GetCanvas():
+            ogl.PolygonShape.__init__(self)
+            
+            points = [(0, - self.height / 2),
+                      (self.width / 2, 0),
+                      (0, self.height / 2),
+                      (- self.width / 2, 0)]
+            self.Create(points)
+            
+            self.SetCanvas(self.parent)
+            self.SetX(x)
+            self.SetY(y)
+            self.SetPen(wx.BLACK_PEN)
+            if text:
+                self.AddText('(' + str(self.id) + ') ' + text)
+            else:
+                self.AddText('(' + str(self.id) + ')')
+
+    def GetName(self):
+        """!Get name"""
+        return _("if-else")
+
+    def GetWidth(self):
+        """!Get object width"""
+        return self.width
+
+    def GetHeight(self):
+        """!Get object height"""
+        return self.height
+
+    def SetItems(self, items, branch = 'if'):
+        """!Set items (id)
+
+        @param items list of items
+        @param branch 'if' / 'else'
+        """
+        if branch in ['if', 'else']:
+            self.items[branch] = items
+        
+def main():
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    app = wx.PySimpleApp()
+    wx.InitAllImageHandlers()
+    frame = ModelFrame(parent = None)
+    if len(sys.argv) > 1:
+        frame.LoadModelFile(sys.argv[1])
+    frame.Show()
+    
+    app.MainLoop()
+    
+if __name__ == "__main__":
+    main()

Added: grass/trunk/gui/wxpython/gmodeler/model.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/model.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gmodeler/model.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,731 @@
+"""!
+ at package gmodeler.model
+
+ at brief wxGUI Graphical Modeler (base classes)
+
+Classes:
+ - Model
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import getpass
+import copy
+import re
+try:
+    import xml.etree.ElementTree as etree
+except ImportError:
+    import elementtree.ElementTree as etree # Python <= 2.4
+
+import wx
+
+from core.globalvar import ETCWXDIR
+from core.gcmd      import GMessage, GException, GError, RunCommand
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+class Model(object):
+    """!Class representing the model"""
+    def __init__(self, canvas = None):
+        self.items      = list() # list of actions/loops/...
+        
+        # model properties
+        self.properties = { 'name'        : _("model"),
+                            'description' : _("Script generated by wxGUI Graphical Modeler."),
+                            'author'      : getpass.getuser() }
+        # model variables
+        self.variables = dict()
+        self.variablesParams = dict()
+        
+        self.canvas  = canvas
+        
+    def GetCanvas(self):
+        """!Get canvas or None"""
+        return self.canvas
+    
+    def GetItems(self, objType = None):
+        """!Get list of model items
+
+        @param objType Object type to filter model objects
+        """
+        if not objType:
+            return self.items
+        
+        result = list()
+        for item in self.items:
+            if isinstance(item, objType):
+                result.append(item)
+        
+        return result
+
+    def GetItem(self, aId):
+        """!Get item of given id
+
+        @param aId item id
+        
+        @return Model* instance
+        @return None if no item found
+        """
+        ilist = self.GetItems()
+        for item in ilist:
+            if item.GetId() == aId:
+                return item
+        
+        return None
+
+    def GetNumItems(self, actionOnly = False):
+        """!Get number of items"""
+        if actionOnly:
+            return len(self.GetItems(objType = ModelAction))
+        
+        return len(self.GetItems())
+
+    def GetNextId(self):
+        """!Get next id (data ignored)
+
+        @return next id to be used (default: 1)
+        """
+        if len(self.items) < 1:
+            return 1
+        
+        currId = self.items[-1].GetId()
+        if currId > 0:
+            return currId + 1
+        
+        return 1
+
+    def GetProperties(self):
+        """!Get model properties"""
+        return self.properties
+
+    def GetVariables(self, params = False):
+        """!Get model variables"""
+        if params:
+            return self.variablesParams
+        
+        return self.variables
+    
+    def SetVariables(self, data):
+        """!Set model variables"""
+        self.variables = data
+    
+    def Reset(self):
+        """!Reset model"""
+        self.items = list()
+        
+    def RemoveItem(self, item):
+        """!Remove item from model
+        
+        @return list of related items to remove/update
+        """
+        relList = list()
+        upList = list()
+        
+        if not isinstance(item, ModelData):
+            self.items.remove(item)
+        
+        if isinstance(item, ModelAction):
+            for rel in item.GetRelations():
+                relList.append(rel)
+                data = rel.GetData()
+                if len(data.GetRelations()) < 2:
+                    relList.append(data)
+                else:
+                    upList.append(data)
+            
+        elif isinstance(item, ModelData):
+            for rel in item.GetRelations():
+                relList.append(rel)
+                if rel.GetFrom() == self:
+                    relList.append(rel.GetTo())
+                else:
+                    relList.append(rel.GetFrom())
+        
+        elif isinstance(item, ModelLoop):
+            for rel in item.GetRelations():
+                relList.append(rel)
+            for action in self.GetItems():
+                action.UnSetBlock(item)
+        
+        return relList, upList
+    
+    def FindAction(self, aId):
+        """!Find action by id"""
+        alist = self.GetItems(objType = ModelAction)
+        for action in alist:
+            if action.GetId() == aId:
+                return action
+        
+        return None
+
+    def GetData(self):
+        """!Get list of data items"""
+        result = list()
+        dataItems = self.GetItems(objType = ModelData)
+        
+        for action in self.GetItems(objType = ModelAction):
+            for rel in action.GetRelations():
+                dataItem = rel.GetData()
+                if dataItem not in result:
+                    result.append(dataItem)
+                if dataItem in dataItems:
+                    dataItems.remove(dataItem)
+        
+        # standalone data
+        if dataItems:
+            result += dataItems
+        
+        return result
+
+    def FindData(self, value, prompt):
+        """!Find data item in the model
+
+        @param value value
+        @param prompt prompt
+
+        @return ModelData instance
+        @return None if not found
+        """
+        for data in self.GetData():
+            if data.GetValue() == value and \
+                    data.GetPrompt() == prompt:
+                return data
+        
+        return None
+                
+    def LoadModel(self, filename):
+        """!Load model definition stored in GRASS Model XML file (gxm)
+        
+        @todo Validate against DTD
+        
+        Raise exception on error.
+        """
+        dtdFilename = os.path.join(ETCWXDIR, "xml", "grass-gxm.dtd")
+        
+        # parse workspace file
+        try:
+            gxmXml = ProcessModelFile(etree.parse(filename))
+        except StandardError, e:
+            raise GException(e)
+        
+        if self.canvas:
+            win = self.canvas.parent
+            if gxmXml.pos:
+                win.SetPosition(gxmXml.pos)
+            if gxmXml.size:
+                win.SetSize(gxmXml.size)
+        
+        # load properties
+        self.properties = gxmXml.properties
+        self.variables  = gxmXml.variables
+        
+        # load model.GetActions()
+        for action in gxmXml.actions:
+            actionItem = ModelAction(parent = self, 
+                                     x = action['pos'][0],
+                                     y = action['pos'][1],
+                                     width = action['size'][0],
+                                     height = action['size'][1],
+                                     task = action['task'],
+                                     id = action['id'])
+            
+            if action['disabled']:
+                actionItem.Enable(False)
+            
+            self.AddItem(actionItem)
+            
+            actionItem.SetValid(actionItem.GetTask().get_options())
+            actionItem.GetLog() # substitute variables (-> valid/invalid)
+        
+        # load data & relations
+        for data in gxmXml.data:
+            dataItem = ModelData(parent = self, 
+                                 x = data['pos'][0],
+                                 y = data['pos'][1],
+                                 width = data['size'][0],
+                                 height = data['size'][1],
+                                 prompt = data['prompt'],
+                                 value = data['value'])
+            dataItem.SetIntermediate(data['intermediate'])
+            
+            for rel in data['rels']:
+                actionItem = self.FindAction(rel['id'])
+                if rel['dir'] == 'from':
+                    relation = ModelRelation(parent = self, fromShape = dataItem,
+                                             toShape = actionItem, param = rel['name'])
+                else:
+                    relation = ModelRelation(parent = self, fromShape = actionItem,
+                                             toShape = dataItem, param = rel['name'])
+                relation.SetControlPoints(rel['points'])
+                actionItem.AddRelation(relation)
+                dataItem.AddRelation(relation)
+
+            if self.canvas:
+                dataItem.Update()
+           
+        # load loops
+        for loop in gxmXml.loops:
+            loopItem = ModelLoop(parent = self, 
+                                 x = loop['pos'][0],
+                                 y = loop['pos'][1],
+                                 width = loop['size'][0],
+                                 height = loop['size'][1],
+                                 text = loop['text'],
+                                 id = loop['id'])
+            self.AddItem(loopItem)
+
+        # load conditions
+        for condition in gxmXml.conditions:
+            conditionItem = ModelCondition(parent = self, 
+                                           x = condition['pos'][0],
+                                           y = condition['pos'][1],
+                                           width = condition['size'][0],
+                                           height = condition['size'][1],
+                                           text = condition['text'],
+                                           id = condition['id'])
+            self.AddItem(conditionItem)
+
+        # define loops & if/else items
+        for loop in gxmXml.loops:
+            alist = list()
+            for aId in loop['items']:
+                action = self.GetItem(aId)
+                alist.append(action)
+            
+            loopItem = self.GetItem(loop['id'])
+            loopItem.SetItems(alist)
+            
+            for action in loopItem.GetItems():
+                action.SetBlock(loopItem)
+        
+        for condition in gxmXml.conditions:
+            conditionItem = self.GetItem(condition['id'])
+            for b in condition['items'].keys():
+                alist = list()
+                for aId in condition['items'][b]:
+                    action = self.GetItem(aId)
+                    alist.append(action)
+                conditionItem.SetItems(alist, branch = b)
+            
+            items = conditionItem.GetItems()
+            for b in items.keys():
+                for action in items[b]:
+                    action.SetBlock(conditionItem)
+        
+    def AddItem(self, newItem):
+        """!Add item to the list"""
+        iId = newItem.GetId()
+        
+        i  = 0
+        for item in self.items:
+            if item.GetId() > iId:
+                self.items.insert(i, newItem)
+                return
+            i += 1
+        
+        self.items.append(newItem)
+        
+    def IsValid(self):
+        """Return True if model is valid"""
+        if self.Validate():
+            return False
+        
+        return True
+    
+    def Validate(self):
+        """!Validate model, return None if model is valid otherwise
+        error string"""
+        errList = list()
+
+        variables = self.GetVariables().keys()
+        pattern = re.compile(r'(.*)(%.+\s?)(.*)')
+        for action in self.GetItems(objType = ModelAction):
+            cmd = action.GetLog(string = False)
+            
+            task = menuform.GUI(show = None).ParseCommand(cmd = cmd)
+            errList += map(lambda x: cmd[0] + ': ' + x, task.get_cmd_error())
+            
+            # check also variables
+            for opt in cmd[1:]:
+                if '=' not in opt:
+                    continue
+                key, value = opt.split('=', 1)
+                sval = pattern.search(value)
+                if sval:
+                    var = sval.group(2).strip()[1:] # ignore '%'
+                    if var not in variables:
+                        report = True
+                        for item in filter(lambda x: isinstance(x, ModelLoop), action.GetBlock()):
+                            if var in item.GetText():
+                                report = False
+                                break
+                        if report:
+                            errList.append(_("%s: undefined variable '%s'") % (cmd[0], var))
+            ### TODO: check variables in file only optionally
+            ### errList += self._substituteFile(action, checkOnly = True)
+        
+        return errList
+
+    def _substituteFile(self, item, params = None, checkOnly = False):
+        """!Subsitute variables in command file inputs
+
+        @param checkOnly tuble - True to check variable, don't touch files
+        
+        @return list of undefined variables
+        """
+        errList = list()
+        
+        self.fileInput = dict()
+        
+        # collect ascii inputs
+        for p in item.GetParams()['params']:
+            if p.get('element', '') == 'file' and \
+                    p.get('prompt', '') == 'input' and \
+                    p.get('age', '') == 'old':
+                filename = p.get('value', p.get('default', ''))
+                if filename and \
+                        mimetypes.guess_type(filename)[0] == 'text/plain':
+                    self.fileInput[filename] = None
+        
+        for finput in self.fileInput:
+            # read lines
+            fd = open(finput, "r")
+            try:
+                data = self.fileInput[finput] = fd.read()
+            finally:
+                fd.close()
+            
+            # substitute variables
+            write = False
+            variables = self.GetVariables()
+            for variable in variables:
+                pattern = re.compile('%' + variable)
+                value = ''
+                if params and 'variables' in params:
+                    for p in params['variables']['params']:
+                        if variable == p.get('name', ''):
+                            if p.get('type', 'string') == 'string':
+                                value = p.get('value', '')
+                            else:
+                                value = str(p.get('value', ''))
+                            break
+                
+                if not value:
+                    value = variables[variable].get('value', '')
+                
+                data = pattern.sub(value, data)
+                if not checkOnly:
+                    write = True
+            
+            pattern = re.compile(r'(.*)(%.+\s?)(.*)')
+            sval = pattern.search(data)
+            if sval:
+                var = sval.group(2).strip()[1:] # ignore '%'
+                cmd = item.GetLog(string = False)[0]
+                errList.append(_("%s: undefined variable '%s'") % (cmd, var))
+            
+            if not checkOnly:
+                if write:
+                    fd = open(finput, "w")
+                    try:
+                        fd.write(data)
+                    finally:
+                        fd.close()
+                else:
+                    self.fileInput[finput] = None
+        
+        return errList
+    
+    def OnPrepare(self, item, params):
+        self._substituteFile(item, params, checkOnly = False)
+
+    def RunAction(self, item, params, log, onDone, onPrepare = None, statusbar = None):
+        """!Run given action
+
+        @param item action item
+        @param params parameters dict
+        @param log logging window
+        @param onDone on-done method
+        @param onPrepare on-prepare method
+        @param statusbar wx.StatusBar instance or None
+        """
+        name = item.GetName()
+        if name in params:
+            paramsOrig = item.GetParams(dcopy = True)
+            item.MergeParams(params[name])
+        
+        if statusbar:
+            statusbar.SetStatusText(_('Running model...'), 0)
+            
+        data = { 'item' : item,
+                 'params' : copy.deepcopy(params) }
+        log.RunCmd(command = item.GetLog(string = False, substitute = params),
+                   onDone = onDone, onPrepare = self.OnPrepare, userData = data)
+        
+        if name in params:
+            item.SetParams(paramsOrig)
+
+    def Run(self, log, onDone, parent = None):
+        """!Run model
+
+        @param log logging window (see goutput.GMConsole)
+        @param onDone on-done method
+        @param parent window for messages or None
+        """
+        if self.GetNumItems() < 1:
+            GMessage(parent = parent,
+                     message = _('Model is empty. Nothing to run.'))
+            return
+        
+        statusbar = None
+        if isinstance(parent, wx.Frame):
+            statusbar = parent.GetStatusBar()
+        
+        # validation
+        if statusbar:
+            statusbar.SetStatusText(_('Validating model...'), 0)
+        errList = self.Validate()
+        if statusbar:
+            statusbar.SetStatusText('', 0)
+        if errList:
+            dlg = wx.MessageDialog(parent = parent,
+                                   message = _('Model is not valid. Do you want to '
+                                               'run the model anyway?\n\n%s') % '\n'.join(errList),
+                                   caption = _("Run model?"),
+                                   style = wx.YES_NO | wx.NO_DEFAULT |
+                                   wx.ICON_QUESTION | wx.CENTRE)
+            ret = dlg.ShowModal()
+            if ret != wx.ID_YES:
+                return
+        
+        # parametrization
+        params = self.Parameterize()
+        if params:
+            dlg = ModelParamDialog(parent = parent,
+                                   params = params)
+            dlg.CenterOnParent()
+            
+            ret = dlg.ShowModal()
+            if ret != wx.ID_OK:
+                dlg.Destroy()
+                return
+            
+            err = dlg.GetErrors()
+            if err:
+                GError(parent = parent, message = unicode('\n'.join(err)))
+                return
+        
+            err = list()
+            for key, item in params.iteritems():
+                for p in item['params']:
+                    if p.get('value', '') == '':
+                        err.append((key, p.get('name', ''), p.get('description', '')))
+            if err:
+                GError(parent = parent,
+                       message = _("Variables below not defined:") + \
+                           "\n\n" + unicode('\n'.join(map(lambda x: "%s: %s (%s)" % (x[0], x[1], x[2]), err))))
+                return
+        
+        log.cmdThread.SetId(-1)
+        for item in self.GetItems():
+            if not item.IsEnabled():
+                continue
+            if isinstance(item, ModelAction):
+                if item.GetBlockId():
+                    continue
+                self.RunAction(item, params, log, onDone)
+            elif isinstance(item, ModelLoop):
+                cond = item.GetText()
+                # substitute variables in condition
+                variables = self.GetVariables()
+                for variable in variables:
+                    pattern = re.compile('%' + variable)
+                    if pattern.search(cond):
+                        value = ''
+                        if params and 'variables' in params:
+                            for p in params['variables']['params']:
+                                if variable == p.get('name', ''):
+                                    value = p.get('value', '')
+                                    break
+                        
+                        if not value:
+                            value = variables[variable].get('value', '')
+                        
+                        if not value:
+                            continue
+                        
+                        vtype = variables[variable].get('type', 'string')
+                        if vtype == 'string':
+                            value = '"' + value + '"'
+                        cond = pattern.sub(value, cond)
+                
+                # split condition
+                condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
+                pattern = re.compile('%' + condVar)
+                ### for vars()[condVar] in eval(condText): ?
+                if condText[0] == '`' and condText[-1] == '`':
+                    # run command
+                    cmd, dcmd = utils.CmdToTuple(condText[1:-1].split(' '))
+                    ret = RunCommand(cmd,
+                                     read = True,
+                                     **dcmd)
+                    if ret:
+                        vlist = ret.splitlines()
+                else:
+                    vlist = eval(condText)
+                
+                if 'variables' not in params:
+                    params['variables'] = { 'params' : [] }
+                varDict = { 'name' : condVar, 'value' : '' }
+                params['variables']['params'].append(varDict)
+                                
+                for var in vlist:
+                    for action in item.GetItems():
+                        if not isinstance(action, ModelAction) or \
+                                not action.IsEnabled():
+                            continue
+                        
+                        varDict['value'] = var
+                                                
+                        self.RunAction(item = action, params = params,
+                                       log = log, onDone = onDone)
+                params['variables']['params'].remove(varDict)
+                
+        # discard values
+        if params:
+            for item in params.itervalues():
+                for p in item['params']:
+                    p['value'] = ''
+        
+        if params:
+            dlg.Destroy()
+        
+    def DeleteIntermediateData(self, log):
+        """!Detele intermediate data"""
+        rast, vect, rast3d, msg = self.GetIntermediateData()
+        
+        if rast:
+            log.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
+        if rast3d:
+            log.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
+        if vect:
+            log.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
+        
+    def GetIntermediateData(self):
+        """!Get info about intermediate data"""
+        rast = list()
+        rast3d = list()
+        vect = list()
+        for data in self.GetData():
+            if not data.IsIntermediate():
+                continue
+            name = data.GetValue()
+            prompt = data.GetPrompt()
+            if prompt == 'raster':
+                rast.append(name)
+            elif prompt == 'vector':
+                vect.append(name)
+            elif prompt == 'rast3d':
+                rast3d.append(name)
+        
+        msg = ''
+        if rast:
+            msg += '\n\n%s: ' % _('Raster maps')
+            msg += ', '.join(rast)
+        if rast3d:
+            msg += '\n\n%s: ' % _('3D raster maps')
+            msg += ', '.join(rast3d)
+        if vect:
+            msg += '\n\n%s: ' % _('Vector maps')
+            msg += ', '.join(vect)
+        
+        return rast, vect, rast3d, msg
+
+    def Update(self):
+        """!Update model"""
+        for item in self.items:
+            item.Update()
+        
+    def IsParameterized(self):
+        """!Return True if model is parameterized"""
+        if self.Parameterize():
+            return True
+        
+        return False
+    
+    def Parameterize(self):
+        """!Return parameterized options"""
+        result = dict()
+        idx = 0
+        if self.variables:
+            params = list()
+            result["variables"] = { 'flags'  : list(),
+                                    'params' : params,
+                                    'idx'    : idx }
+            for name, values in self.variables.iteritems():
+                gtype = values.get('type', 'string')
+                if gtype in ('raster', 'vector', 'mapset', 'file'):
+                    gisprompt = True
+                    prompt = gtype
+                    if gtype == 'raster':
+                        element = 'cell'
+                    else:
+                        element = gtype
+                    ptype = 'string'
+                else:
+                    gisprompt = False
+                    prompt = None
+                    element = None
+                    ptype = gtype
+                params.append({ 'gisprompt' : gisprompt,
+                                'multiple'  : False,
+                                'description' : values.get('description', ''),
+                                'guidependency' : '',
+                                'default' : '',
+                                'age' : None,
+                                'required' : True,
+                                'value' : values.get('value', ''),
+                                'label' : '',
+                                'guisection' : '',
+                                'key_desc' : '',
+                                'values' : list(),
+                                'parameterized' : False,
+                                'values_desc' : list(),
+                                'prompt' : prompt,
+                                'element' : element,
+                                'type' : ptype,
+                                'name' : name })
+            
+            idx += 1
+        
+        for action in self.GetItems(objType = ModelAction):
+            if not action.IsEnabled():
+                continue
+            name   = action.GetName()
+            params = action.GetParams()
+            for f in params['flags']:
+                if f.get('parameterized', False):
+                    if name not in result:
+                        result[name] = { 'flags' : list(),
+                                         'params': list(),
+                                         'idx'   : idx }
+                    result[name]['flags'].append(f)
+            for p in params['params']:
+                if p.get('parameterized', False):
+                    if name not in result:
+                        result[name] = { 'flags' : list(),
+                                         'params': list(),
+                                         'idx'   : idx }
+                    result[name]['params'].append(p)
+            if name in result:
+                idx += 1
+        
+        self.variablesParams = result # record parameters
+        
+        return result


Property changes on: grass/trunk/gui/wxpython/gmodeler/model.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/gmodeler/model_file.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/model_file.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gmodeler/model_file.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,695 @@
+"""!
+ at package gmodeler.model_file
+
+ at brief wxGUI Graphical Modeler - model definition file
+
+Classes:
+ - ProcessModelFile
+ - WriteModelFile
+ - WritePythonFile
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import time
+import re
+
+from gui_core.forms import GUI
+from core.gcmd      import GWarning, EncodeString
+
+class ProcessModelFile:
+    """!Process GRASS model file (gxm)"""
+    def __init__(self, tree):
+        """!A ElementTree handler for the GXM XML file, as defined in
+        grass-gxm.dtd.
+        """
+        self.tree = tree
+        self.root = self.tree.getroot()
+        
+        # list of actions, data
+        self.properties = dict()
+        self.variables  = dict() 
+        self.actions = list()
+        self.data    = list()
+        self.loops   = list()
+        self.conditions = list()
+        
+        self._processWindow()
+        self._processProperties()
+        self._processVariables()
+        self._processItems()
+        self._processData()
+        
+    def _filterValue(self, value):
+        """!Filter value
+        
+        @param value
+        """
+        value = value.replace('&lt;', '<')
+        value = value.replace('&gt;', '>')
+        
+        return value
+        
+    def _getNodeText(self, node, tag, default = ''):
+        """!Get node text"""
+        p = node.find(tag)
+        if p is not None:
+            if p.text:
+                return utils.normalize_whitespace(p.text)
+            else:
+                return ''
+        
+        return default
+    
+    def _processWindow(self):
+        """!Process window properties"""
+        node = self.root.find('window')
+        if node is None:
+            self.pos = self.size = None
+            return
+        
+        self.pos, self.size = self._getDim(node)
+        
+    def _processProperties(self):
+        """!Process model properties"""
+        node = self.root.find('properties')
+        if node is None:
+            return
+        for key in ('name', 'description', 'author'):
+            self._processProperty(node, key)
+        
+        for f in node.findall('flag'):
+            name = f.get('name', '')
+            if name == 'overwrite':
+                self.properties['overwrite'] = True
+        
+    def _processProperty(self, pnode, name):
+        """!Process given property"""
+        node = pnode.find(name)
+        if node is not None:
+            self.properties[name] = node.text
+        else:
+            self.properties[name] = ''
+
+    def _processVariables(self):
+        """!Process model variables"""
+        vnode = self.root.find('variables')
+        if vnode is None:
+            return
+        for node in vnode.findall('variable'):
+            name = node.get('name', '')
+            if not name:
+                continue # should not happen
+            self.variables[name] = { 'type' : node.get('type', 'string') }
+            for key in ('description', 'value'):
+                self._processVariable(node, name, key)
+        
+    def _processVariable(self, pnode, name, key):
+        """!Process given variable"""
+        node = pnode.find(key)
+        if node is not None:
+            if node.text:
+                self.variables[name][key] = node.text
+
+    def _processItems(self):
+        """!Process model items (actions, loops, conditions)"""
+        self._processActions()
+        self._processLoops()
+        self._processConditions()
+        
+    def _processActions(self):
+        """!Process model file"""
+        for action in self.root.findall('action'):
+            pos, size = self._getDim(action)
+            disabled  = False
+            
+            task = action.find('task')
+            if task is not None:
+                if task.find('disabled') is not None:
+                    disabled = True
+                task = self._processTask(task)
+            else:
+                task = None
+            
+            aId = int(action.get('id', -1))
+            
+            self.actions.append({ 'pos'      : pos,
+                                  'size'     : size,
+                                  'task'     : task,
+                                  'id'       : aId,
+                                  'disabled' : disabled })
+            
+    def _getDim(self, node):
+        """!Get position and size of shape"""
+        pos = size = None
+        posAttr = node.get('pos', None)
+        if posAttr:
+            posVal = map(int, posAttr.split(','))
+            try:
+                pos = (posVal[0], posVal[1])
+            except:
+                pos = None
+        
+        sizeAttr = node.get('size', None)
+        if sizeAttr:
+            sizeVal = map(int, sizeAttr.split(','))
+            try:
+                size = (sizeVal[0], sizeVal[1])
+            except:
+                size = None
+        
+        return pos, size        
+    
+    def _processData(self):
+        """!Process model file"""
+        for data in self.root.findall('data'):
+            pos, size = self._getDim(data)
+            param = data.find('data-parameter')
+            prompt = value = None
+            if param is not None:
+                prompt = param.get('prompt', None)
+                value = self._filterValue(self._getNodeText(param, 'value'))
+            
+            if data.find('intermediate') is None:
+                intermediate = False
+            else:
+                intermediate = True
+            
+            rels = list()
+            for rel in data.findall('relation'):
+                defrel = { 'id'  : int(rel.get('id', -1)),
+                           'dir' : rel.get('dir', 'to'),
+                           'name' : rel.get('name', '') }
+                points = list()
+                for point in rel.findall('point'):
+                    x = self._filterValue(self._getNodeText(point, 'x'))
+                    y = self._filterValue(self._getNodeText(point, 'y'))
+                    points.append((float(x), float(y)))
+                defrel['points'] = points
+                rels.append(defrel)
+            
+            self.data.append({ 'pos' : pos,
+                               'size': size,
+                               'prompt' : prompt,
+                               'value' : value,
+                               'intermediate' : intermediate,
+                               'rels' : rels })
+        
+    def _processTask(self, node):
+        """!Process task
+
+        @return grassTask instance
+        @return None on error
+        """
+        cmd = list()
+        parameterized = list()
+        
+        name = node.get('name', None)
+        if not name:
+            return None
+        
+        cmd.append(name)
+        
+        # flags
+        for f in node.findall('flag'):
+            flag = f.get('name', '')
+            if f.get('parameterized', '0') == '1':
+                parameterized.append(('flag', flag))
+                if f.get('value', '1') == '0':
+                    continue
+            if len(flag) > 1:
+                cmd.append('--' + flag)
+            else:
+                cmd.append('-' + flag)
+        # parameters
+        for p in node.findall('parameter'):
+            name = p.get('name', '')
+            if p.find('parameterized') is not None:
+                parameterized.append(('param', name))
+            cmd.append('%s=%s' % (name,
+                                  self._filterValue(self._getNodeText(p, 'value'))))
+        
+        task, err = GUI(show = None, checkError = True).ParseCommand(cmd = cmd)
+        if err:
+            GWarning(os.linesep.join(err))
+        
+        for opt, name in parameterized:
+            if opt == 'flag':
+                task.set_flag(name, True, element = 'parameterized')
+            else:
+                task.set_param(name, True, element = 'parameterized')
+        
+        return task
+
+    def _processLoops(self):
+        """!Process model loops"""
+        for node in self.root.findall('loop'):
+            pos, size = self._getDim(node)
+            text = self._filterValue(self._getNodeText(node, 'condition')).strip()
+            aid = list()
+            for anode in node.findall('item'):
+                try:
+                    aid.append(int(anode.text))
+                except ValueError:
+                    pass
+            
+            self.loops.append({ 'pos'     : pos,
+                                'size'    : size,
+                                'text'    : text,
+                                'id'      : int(node.get('id', -1)),
+                                'items'   : aid })
+        
+    def _processConditions(self):
+        """!Process model conditions"""
+        for node in self.root.findall('if-else'):
+            pos, size = self._getDim(node)
+            text = self._filterValue(self._getNodeText(node, 'condition')).strip()
+            aid = { 'if'   : list(),
+                    'else' : list() }
+            for b in aid.keys():
+                bnode = node.find(b)
+                if bnode is None:
+                    continue
+                for anode in bnode.findall('item'):
+                    try:
+                        aid[b].append(int(anode.text))
+                    except ValueError:
+                        pass
+            
+            self.conditions.append({ 'pos'     : pos,
+                                     'size'    : size,
+                                     'text'    : text,
+                                     'id'      : int(node.get('id', -1)),
+                                     'items'   : aid })
+        
+class WriteModelFile:
+    """!Generic class for writing model file"""
+    def __init__(self, fd, model):
+        self.fd         = fd
+        self.model      = model
+        self.properties = model.GetProperties()
+        self.variables  = model.GetVariables()
+        self.items      = model.GetItems()
+        
+        self.indent = 0
+        
+        self._header()
+        
+        self._window()
+        self._properties()
+        self._variables()
+        self._items()
+        
+        dataList = list()
+        for action in model.GetItems(objType = ModelAction):
+            for rel in action.GetRelations():
+                dataItem = rel.GetData()
+                if dataItem not in dataList:
+                    dataList.append(dataItem)
+        self._data(dataList)
+        
+        self._footer()
+
+    def _filterValue(self, value):
+        """!Make value XML-valid"""
+        value = value.replace('<', '&lt;')
+        value = value.replace('>', '&gt;')
+        
+        return value
+        
+    def _header(self):
+        """!Write header"""
+        self.fd.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+        self.fd.write('<!DOCTYPE gxm SYSTEM "grass-gxm.dtd">\n')
+        self.fd.write('%s<gxm>\n' % (' ' * self.indent))
+        self.indent += 4
+                
+    def _footer(self):
+        """!Write footer"""
+        self.indent -= 4
+        self.fd.write('%s</gxm>\n' % (' ' * self.indent))
+
+    def _window(self):
+        """!Write window properties"""
+        canvas = self.model.GetCanvas()
+        if canvas is None:
+            return
+        win  = canvas.parent
+        pos  = win.GetPosition()
+        size = win.GetSize()
+        self.fd.write('%s<window pos="%d,%d" size="%d,%d" />\n' % \
+                          (' ' * self.indent, pos[0], pos[1], size[0], size[1]))
+        
+    def _properties(self):
+        """!Write model properties"""
+        self.fd.write('%s<properties>\n' % (' ' * self.indent))
+        self.indent += 4
+        if self.properties['name']:
+            self.fd.write('%s<name>%s</name>\n' % (' ' * self.indent, self.properties['name']))
+        if self.properties['description']:
+            self.fd.write('%s<description>%s</description>\n' % (' ' * self.indent,
+                                                                 EncodeString(self.properties['description'])))
+        if self.properties['author']:
+            self.fd.write('%s<author>%s</author>\n' % (' ' * self.indent,
+                                                       EncodeString(self.properties['author'])))
+        
+        if 'overwrite' in self.properties and \
+                self.properties['overwrite']:
+            self.fd.write('%s<flag name="overwrite" />\n' % (' ' * self.indent))
+        self.indent -= 4
+        self.fd.write('%s</properties>\n' % (' ' * self.indent))
+
+    def _variables(self):
+        """!Write model variables"""
+        if not self.variables:
+            return
+        self.fd.write('%s<variables>\n' % (' ' * self.indent))
+        self.indent += 4
+        for name, values in self.variables.iteritems():
+            self.fd.write('%s<variable name="%s" type="%s">\n' % \
+                              (' ' * self.indent, name, values['type']))
+            self.indent += 4
+            if 'value' in values:
+                self.fd.write('%s<value>%s</value>\n' % \
+                                  (' ' * self.indent, values['value']))
+            if 'description' in values:
+                self.fd.write('%s<description>%s</description>\n' % \
+                                  (' ' * self.indent, values['description']))
+            self.indent -= 4
+            self.fd.write('%s</variable>\n' % (' ' * self.indent))
+        self.indent -= 4
+        self.fd.write('%s</variables>\n' % (' ' * self.indent))
+        
+    def _items(self):
+        """!Write actions/loops/conditions"""
+        for item in self.items:
+            if isinstance(item, ModelAction):
+                self._action(item)
+            elif isinstance(item, ModelLoop):
+                self._loop(item)
+            elif isinstance(item, ModelCondition):
+                self._condition(item)
+        
+    def _action(self, action):
+        """!Write actions"""
+        self.fd.write('%s<action id="%d" name="%s" pos="%d,%d" size="%d,%d">\n' % \
+                          (' ' * self.indent, action.GetId(), action.GetName(), action.GetX(), action.GetY(),
+                           action.GetWidth(), action.GetHeight()))
+        self.indent += 4
+        self.fd.write('%s<task name="%s">\n' % (' ' * self.indent, action.GetLog(string = False)[0]))
+        self.indent += 4
+        if not action.IsEnabled():
+            self.fd.write('%s<disabled />\n' % (' ' * self.indent))
+        for key, val in action.GetParams().iteritems():
+            if key == 'flags':
+                for f in val:
+                    if f.get('value', False) or f.get('parameterized', False):
+                        if f.get('parameterized', False):
+                            if f.get('value', False) == False:
+                                self.fd.write('%s<flag name="%s" value="0" parameterized="1" />\n' %
+                                              (' ' * self.indent, f.get('name', '')))
+                            else:
+                                self.fd.write('%s<flag name="%s" parameterized="1" />\n' %
+                                              (' ' * self.indent, f.get('name', '')))
+                        else:
+                            self.fd.write('%s<flag name="%s" />\n' %
+                                          (' ' * self.indent, f.get('name', '')))
+            else: # parameter
+                for p in val:
+                    if not p.get('value', '') and not p.get('parameterized', False):
+                        continue
+                    self.fd.write('%s<parameter name="%s">\n' %
+                                  (' ' * self.indent, p.get('name', '')))
+                    self.indent += 4
+                    if p.get('parameterized', False):
+                        self.fd.write('%s<parameterized />\n' % (' ' * self.indent))
+                    self.fd.write('%s<value>%s</value>\n' %
+                                  (' ' * self.indent, self._filterValue(p.get('value', ''))))
+                    self.indent -= 4
+                    self.fd.write('%s</parameter>\n' % (' ' * self.indent))
+        self.indent -= 4
+        self.fd.write('%s</task>\n' % (' ' * self.indent))
+        self.indent -= 4
+        self.fd.write('%s</action>\n' % (' ' * self.indent))
+                
+    def _data(self, dataList):
+        """!Write data"""
+        for data in dataList:
+            self.fd.write('%s<data pos="%d,%d" size="%d,%d">\n' % \
+                              (' ' * self.indent, data.GetX(), data.GetY(),
+                               data.GetWidth(), data.GetHeight()))
+            self.indent += 4
+            self.fd.write('%s<data-parameter prompt="%s">\n' % \
+                              (' ' * self.indent, data.GetPrompt()))
+            self.indent += 4
+            self.fd.write('%s<value>%s</value>\n' %
+                          (' ' * self.indent, self._filterValue(data.GetValue())))
+            self.indent -= 4
+            self.fd.write('%s</data-parameter>\n' % (' ' * self.indent))
+            
+            if data.IsIntermediate():
+                self.fd.write('%s<intermediate />\n' % (' ' * self.indent))
+
+            # relations
+            for ft in ('from', 'to'):
+                for rel in data.GetRelations(ft):
+                    if ft == 'from':
+                        aid = rel.GetTo().GetId()
+                    else:
+                        aid  = rel.GetFrom().GetId()
+                    self.fd.write('%s<relation dir="%s" id="%d" name="%s">\n' % \
+                                      (' ' * self.indent, ft, aid, rel.GetName()))
+                    self.indent += 4
+                    for point in rel.GetLineControlPoints()[1:-1]:
+                        self.fd.write('%s<point>\n' % (' ' * self.indent))
+                        self.indent += 4
+                        x, y = point.Get()
+                        self.fd.write('%s<x>%d</x>\n' % (' ' * self.indent, int(x)))
+                        self.fd.write('%s<y>%d</y>\n' % (' ' * self.indent, int(y)))
+                        self.indent -= 4
+                        self.fd.write('%s</point>\n' % (' ' * self.indent))
+                    self.indent -= 4
+                    self.fd.write('%s</relation>\n' % (' ' * self.indent))
+                
+            self.indent -= 4
+            self.fd.write('%s</data>\n' % (' ' * self.indent))
+
+    def _loop(self, loop):
+        """!Write loops"""
+        self.fd.write('%s<loop id="%d" pos="%d,%d" size="%d,%d">\n' % \
+                          (' ' * self.indent, loop.GetId(), loop.GetX(), loop.GetY(),
+                           loop.GetWidth(), loop.GetHeight()))
+        text = loop.GetText()
+        self.indent += 4
+        if text:
+            self.fd.write('%s<condition>%s</condition>\n' %
+                          (' ' * self.indent, self._filterValue(text)))
+        for item in loop.GetItems():
+            self.fd.write('%s<item>%d</item>\n' %
+                          (' ' * self.indent, item.GetId()))
+        self.indent -= 4
+        self.fd.write('%s</loop>\n' % (' ' * self.indent))
+
+    def _condition(self, condition):
+        """!Write conditions"""
+        bbox = condition.GetBoundingBoxMin()
+        self.fd.write('%s<if-else id="%d" pos="%d,%d" size="%d,%d">\n' % \
+                          (' ' * self.indent, condition.GetId(), condition.GetX(), condition.GetY(),
+                           bbox[0], bbox[1]))
+        text = condition.GetText()
+        self.indent += 4
+        if text:
+            self.fd.write('%s<condition>%s</condition>\n' %
+                          (' ' * self.indent, self._filterValue(text)))
+        items = condition.GetItems()
+        for b in items.keys():
+            if len(items[b]) < 1:
+                continue
+            self.fd.write('%s<%s>\n' % (' ' * self.indent, b))
+            self.indent += 4
+            for item in items[b]:
+                self.fd.write('%s<item>%d</item>\n' %
+                              (' ' * self.indent, item.GetId()))
+            self.indent -= 4
+            self.fd.write('%s</%s>\n' % (' ' * self.indent, b))
+        
+        self.indent -= 4
+        self.fd.write('%s</if-else>\n' % (' ' * self.indent))
+        
+class WritePythonFile:
+    def __init__(self, fd, model):
+        """!Class for exporting model to Python script
+
+        @param fd file desciptor
+        """
+        self.fd     = fd
+        self.model  = model
+        self.indent = 4
+
+        self._writePython()
+        
+    def _writePython(self):
+        """!Write model to file"""
+        properties = self.model.GetProperties()
+        
+        self.fd.write(
+r"""#!/usr/bin/env python
+#
+############################################################################
+#
+# MODULE:       %s
+#
+# AUTHOR(S):	%s
+#               
+# PURPOSE:      %s
+#
+# DATE:         %s
+#
+#############################################################################
+""" % (properties['name'],
+       properties['author'],
+       properties['description'],
+       time.asctime()))
+        
+        self.fd.write(
+r"""
+import sys
+import os
+import atexit
+
+import grass.script as grass
+""")
+        
+        # cleanup()
+        rast, vect, rast3d, msg = self.model.GetIntermediateData()
+        self.fd.write(
+r"""
+def cleanup():
+""")
+        if rast:
+            self.fd.write(
+r"""    grass.run_command('g.remove',
+                      rast=%s)
+""" % ','.join(map(lambda x: "'" + x + "'", rast)))
+        if vect:
+            self.fd.write(
+r"""    grass.run_command('g.remove',
+                      vect = %s)
+""" % ','.join(map(lambda x: "'" + x + "'", vect)))
+        if rast3d:
+            self.fd.write(
+r"""    grass.run_command('g.remove',
+                      rast3d = %s)
+""" % ','.join(map(lambda x: "'" + x + "'", rast3d)))
+        if not rast and not vect and not rast3d:
+            self.fd.write('    pass\n')
+        
+        self.fd.write("\ndef main():\n")
+        for item in self.model.GetItems():
+            self._writePythonItem(item)
+        
+        self.fd.write("\n    return 0\n")
+        
+        self.fd.write(
+r"""
+if __name__ == "__main__":
+    options, flags = grass.parser()
+    atexit.register(cleanup)
+    sys.exit(main())
+""")
+        
+    def _writePythonItem(self, item, ignoreBlock = True, variables = []):
+        """!Write model object to Python file"""
+        if isinstance(item, ModelAction):
+            if ignoreBlock and item.GetBlockId(): # ignore items in loops of conditions
+                return
+            self._writePythonAction(item, variables = variables)
+        elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition):
+            # substitute condition
+            variables = self.model.GetVariables()
+            cond = item.GetText()
+            for variable in variables:
+                pattern = re.compile('%' + variable)
+                if pattern.search(cond):
+                    value = variables[variable].get('value', '')
+                    if variables[variable].get('type', 'string') == 'string':
+                        value = '"' + value + '"'
+                    cond = pattern.sub(value, cond)
+            if isinstance(item, ModelLoop):
+                condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
+                cond = "%sfor %s in " % (' ' * self.indent, condVar)
+                if condText[0] == '`' and condText[-1] == '`':
+                    task = GUI(show = None).ParseCommand(cmd = utils.split(condText[1:-1]))
+                    cond += "grass.read_command("
+                    cond += self._getPythonActionCmd(task, len(cond), variables = [condVar]) + ".splitlines()"
+                else:
+                    cond += condText
+                self.fd.write('%s:\n' % cond)
+                self.indent += 4
+                for action in item.GetItems():
+                    self._writePythonItem(action, ignoreBlock = False, variables = [condVar])
+                self.indent -= 4
+            else: # ModelCondition
+                self.fd.write('%sif %s:\n' % (' ' * self.indent, cond))
+                self.indent += 4
+                condItems = item.GetItems()
+                for action in condItems['if']:
+                    self._writePythonItem(action, ignoreBlock = False)
+                if condItems['else']:
+                    self.indent -= 4
+                    self.fd.write('%selse:\n' % (' ' * self.indent))
+                    self.indent += 4
+                    for action in condItems['else']:
+                        self._writePythonItem(action, ignoreBlock = False)
+                self.indent += 4
+        
+    def _writePythonAction(self, item, variables = []):
+        """!Write model action to Python file"""
+        task = GUI(show = None).ParseCommand(cmd = item.GetLog(string = False))
+        strcmd = "%sgrass.run_command(" % (' ' * self.indent)
+        self.fd.write(strcmd + self._getPythonActionCmd(task, len(strcmd), variables) + '\n')
+        
+    def _getPythonActionCmd(self, task, cmdIndent, variables = []):
+        opts = task.get_options()
+        
+        ret = ''
+        flags = ''
+        params = list()
+        
+        for f in opts['flags']:
+            if f.get('value', False):
+                name = f.get('name', '')
+                if len(name) > 1:
+                    params.append('%s = True' % name)
+                else:
+                    flags += name
+            
+        for p in opts['params']:
+            name = p.get('name', None)
+            value = p.get('value', None)
+            if name and value:
+                ptype = p.get('type', 'string')
+                if value[0] == '%':
+                    params.append("%s = %s" % (name, value[1:]))
+                elif ptype == 'string':
+                    params.append('%s = "%s"' % (name, value))
+                else:
+                    params.append("%s = %s" % (name, value))
+        
+        ret += '"%s"' % task.get_name()
+        if flags:
+            ret += ",\n%sflags = '%s'" % (' ' * cmdIndent, flags)
+        if len(params) > 0:
+            ret += ",\n"
+            for opt in params[:-1]:
+                ret += "%s%s,\n" % (' ' * cmdIndent, opt)
+            ret += "%s%s)" % (' ' * cmdIndent, params[-1])
+        else:
+            ret += ")"
+        
+        return ret


Property changes on: grass/trunk/gui/wxpython/gmodeler/model_file.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/gmodeler/preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/preferences.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gmodeler/preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,527 @@
+"""!
+ at package gmodeler.preferences
+
+ at brief wxGUI Graphical Modeler - preferences
+
+Classes:
+ - PreferencesDialog
+ - PropertiesDialog
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import wx
+import wx.lib.colourselect    as csel
+
+from core                 import globalvar
+from gui_core.preferences import PreferencesBaseDialog
+from core.settings        import UserSettings
+
+class PreferencesDialog(PreferencesBaseDialog):
+    """!User preferences dialog"""
+    def __init__(self, parent, settings = UserSettings,
+                 title = _("Modeler settings")):
+        
+        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
+                                       settings = settings)
+        
+        # create notebook pages
+        self._createGeneralPage(self.notebook)
+        self._createActionPage(self.notebook)
+        self._createDataPage(self.notebook)
+        self._createLoopPage(self.notebook)
+        
+        self.SetMinSize(self.GetBestSize())
+        self.SetSize(self.size)
+
+    def _createGeneralPage(self, notebook):
+        """!Create notebook page for action settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("General"))
+        
+        # colors
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Item properties"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Disabled:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='disabled', subkey='color'),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        rColor.SetName('GetColour')
+        self.winId['modeler:disabled:color'] = rColor.GetId()
+        
+        gridSizer.Add(item = rCoxolor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createActionPage(self, notebook):
+        """!Create notebook page for action settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Action"))
+        
+        # colors
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Color"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Valid:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'valid')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        vColor.SetName('GetColour')
+        self.winId['modeler:action:color:valid'] = vColor.GetId()
+        
+        gridSizer.Add(item = vColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Invalid:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        iColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'invalid')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        iColor.SetName('GetColour')
+        self.winId['modeler:action:color:invalid'] = iColor.GetId()
+        
+        gridSizer.Add(item = iColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Running:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'running')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        rColor.SetName('GetColour')
+        self.winId['modeler:action:color:running'] = rColor.GetId()
+        
+        gridSizer.Add(item = rColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        # size
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Shape size"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
+        gridSizer.AddGrowableCol(0)
+
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Width:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        
+        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                            min = 0, max = 500,
+                            initial = self.settings.Get(group='modeler', key='action', subkey=('size', 'width')))
+        width.SetName('GetValue')
+        self.winId['modeler:action:size:width'] = width.GetId()
+        
+        gridSizer.Add(item = width,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                         label=_("Height:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos=(row, 0))
+        
+        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                             min = 0, max = 500,
+                             initial = self.settings.Get(group='modeler', key='action', subkey=('size', 'height')))
+        height.SetName('GetValue')
+        self.winId['modeler:action:size:height'] = height.GetId()
+        
+        gridSizer.Add(item = height,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
+        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
+                
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createDataPage(self, notebook):
+        """!Create notebook page for data settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Data"))
+        
+        # colors
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Type"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Raster:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'raster')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        rColor.SetName('GetColour')
+        self.winId['modeler:data:color:raster'] = rColor.GetId()
+        
+        gridSizer.Add(item = rColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("3D raster:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        r3Color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                    colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'raster3d')),
+                                    size = globalvar.DIALOG_COLOR_SIZE)
+        r3Color.SetName('GetColour')
+        self.winId['modeler:data:color:raster3d'] = r3Color.GetId()
+        
+        gridSizer.Add(item = r3Color,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Vector:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'vector')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        vColor.SetName('GetColour')
+        self.winId['modeler:data:color:vector'] = vColor.GetId()
+        
+        gridSizer.Add(item = vColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+        # size
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Shape size"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Width:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        
+        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                            min = 0, max = 500,
+                            initial = self.settings.Get(group='modeler', key='data', subkey=('size', 'width')))
+        width.SetName('GetValue')
+        self.winId['modeler:data:size:width'] = width.GetId()
+        
+        gridSizer.Add(item = width,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                         label=_("Height:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos=(row, 0))
+        
+        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                             min = 0, max = 500,
+                             initial = self.settings.Get(group='modeler', key='data', subkey=('size', 'height')))
+        height.SetName('GetValue')
+        self.winId['modeler:data:size:height'] = height.GetId()
+        
+        gridSizer.Add(item = height,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
+        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
+        
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createLoopPage(self, notebook):
+        """!Create notebook page for loop settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Loop"))
+        
+        # colors
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Color"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Valid:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                   colour = self.settings.Get(group='modeler', key='loop', subkey=('color', 'valid')),
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        vColor.SetName('GetColour')
+        self.winId['modeler:loop:color:valid'] = vColor.GetId()
+        
+        gridSizer.Add(item = vColor,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        # size
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Shape size"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
+        gridSizer.AddGrowableCol(0)
+
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Width:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        
+        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                            min = 0, max = 500,
+                            initial = self.settings.Get(group='modeler', key='loop', subkey=('size', 'width')))
+        width.SetName('GetValue')
+        self.winId['modeler:loop:size:width'] = width.GetId()
+        
+        gridSizer.Add(item = width,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
+                                         label=_("Height:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos=(row, 0))
+        
+        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                             min = 0, max = 500,
+                             initial = self.settings.Get(group='modeler', key='loop', subkey=('size', 'height')))
+        height.SetName('GetValue')
+        self.winId['modeler:loop:size:height'] = height.GetId()
+        
+        gridSizer.Add(item = height,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
+        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
+                
+        panel.SetSizer(border)
+        
+        return panel
+
+    def OnApply(self, event):
+        """!Button 'Apply' pressed"""
+        PreferencesBaseDialog.OnApply(self, event)
+        
+        self.parent.GetModel().Update()
+        self.parent.GetCanvas().Refresh()
+
+    def OnSave(self, event):
+        """!Button 'Save' pressed"""
+        PreferencesBaseDialog.OnSave(self, event)
+        
+        self.parent.GetModel().Update()
+        self.parent.GetCanvas().Refresh()
+
+class PropertiesDialog(wx.Dialog):
+    """!Model properties dialog
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _('Model properties'),
+                 size = (350, 400),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        wx.Dialog.__init__(self, parent, id, title, size = size,
+                           style = style)
+        
+        self.metaBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                    label=" %s " % _("Metadata"))
+        self.cmdBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                   label=" %s " % _("Commands"))
+        
+        self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+                                size = (300, 25))
+        self.desc = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+                                style = wx.TE_MULTILINE,
+                                size = (300, 50))
+        self.author = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+                                size = (300, 25))
+        
+        # commands
+        self.overwrite = wx.CheckBox(parent = self, id=wx.ID_ANY,
+                                     label=_("Allow output files to overwrite existing files"))
+        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
+        
+        # buttons
+        self.btnOk     = wx.Button(self, wx.ID_OK)
+        self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+        self.btnOk.SetDefault()
+        
+        self.btnOk.SetToolTipString(_("Apply properties"))
+        self.btnOk.SetDefault()
+        self.btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+        
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        
+        self._layout()
+
+    def _layout(self):
+        metaSizer = wx.StaticBoxSizer(self.metaBox, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        gridSizer.AddGrowableRow(1)
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                         label = _("Name:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 0))
+        gridSizer.Add(item = self.name,
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                      pos = (0, 1))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                         label = _("Description:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1, 0))
+        gridSizer.Add(item = self.desc,
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                      pos = (1, 1))
+        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                         label = _("Author(s):")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 0))
+        gridSizer.Add(item = self.author,
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                      pos = (2, 1))
+        metaSizer.Add(item = gridSizer)
+        
+        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
+        cmdSizer.Add(item = self.overwrite,
+                     flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        btnStdSizer = wx.StdDialogButtonSizer()
+        btnStdSizer.AddButton(self.btnCancel)
+        btnStdSizer.AddButton(self.btnOk)
+        btnStdSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item=metaSizer, proportion=1,
+                      flag=wx.EXPAND | wx.ALL, border=5)
+        mainSizer.Add(item=cmdSizer, proportion=0,
+                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
+        mainSizer.Add(item=btnStdSizer, proportion=0,
+                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+    def OnCloseWindow(self, event):
+        self.Hide()
+        
+    def GetValues(self):
+        """!Get values"""
+        return { 'name'        : self.name.GetValue(),
+                 'description' : self.desc.GetValue(),
+                 'author'      : self.author.GetValue(),
+                 'overwrite'   : self.overwrite.IsChecked() }
+    
+    def Init(self, prop):
+        """!Initialize dialog"""
+        self.name.SetValue(prop['name'])
+        self.desc.SetValue(prop['description'])
+        self.author.SetValue(prop['author'])
+        if 'overwrite' in prop:
+            self.overwrite.SetValue(prop['overwrite'])


Property changes on: grass/trunk/gui/wxpython/gmodeler/preferences.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/gui_core/dialogs.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gdialogs.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2403 @@
+"""!
+ at package gui_core.gdialogs
+
+ at brief Various dialogs used in wxGUI.
+
+List of classes:
+ - ElementDialog
+ - LocationDialog
+ - MapsetDialog
+ - NewVectorDialog
+ - SavedRegion
+ - DecorationDialog
+ - TextLayerDialog 
+ - GroupDialog
+ - MapLayersDialog
+ - ImportDialog
+ - GdalImportDialog
+ - GdalOutputDialog
+ - DxfImportDialog
+ - LayersList (used by MultiImport) 
+ - SetOpacityDialog
+ - StaticWrapText
+ - ImageSizeDialog
+ - SqlQueryFrame
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog)
+"""
+
+import os
+import sys
+import re
+from bisect import bisect
+
+import wx
+import wx.lib.filebrowsebutton as filebrowse
+import wx.lib.mixins.listctrl as listmix
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+from core             import globalvar
+from core.gcmd        import GError, RunCommand, GMessage
+from gui_core.gselect import ElementSelect, LocationSelect, MapsetSelect, Select, OgrTypeSelect, GdalSelect
+from core.forms       import GUI
+from core.utils       import GetListOfMapsets, GetLayerNameFromCmd, GetValidLayerName
+from core.settings    import UserSettings
+from core.debug       import Debug
+
+class ElementDialog(wx.Dialog):
+    def __init__(self, parent, title, label, id = wx.ID_ANY,
+                 etype = False, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+                 **kwargs):
+        """!General dialog to choose given element (location, mapset, vector map, etc.)
+        
+        @param parent window
+        @param title window title
+        @param label element label
+        @param etype show also ElementSelect
+        """
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+        
+        self.etype = etype
+        self.label = label
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.btnOK     = wx.Button(parent = self.panel, id = wx.ID_OK)
+        self.btnOK.SetDefault()
+        self.btnOK.Enable(False)
+        
+        if self.etype:
+            self.typeSelect = ElementSelect(parent = self.panel,
+                                            size = globalvar.DIALOG_GSELECT_SIZE)
+            self.typeSelect.Bind(wx.EVT_CHOICE, self.OnType)
+        
+        self.element = None # must be defined 
+        
+        self.__layout()
+        
+    def PostInit(self):
+        self.element.SetFocus()
+        self.element.Bind(wx.EVT_TEXT, self.OnElement)
+        
+    def OnType(self, event):
+        """!Select element type"""
+        if not self.etype:
+            return
+        evalue = self.typeSelect.GetValue(event.GetString())
+        self.element.SetType(evalue)
+        
+    def OnElement(self, event):
+        """!Name for vector map layer given"""
+        if len(event.GetString()) > 0:
+            self.btnOK.Enable(True)
+        else:
+            self.btnOK.Enable(False)
+        
+    def __layout(self):
+        """!Do layout"""
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        self.dataSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        if self.etype:
+            self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                                    label = _("Type of element:")),
+                               proportion = 0, flag = wx.ALL, border = 1)
+            self.dataSizer.Add(item = self.typeSelect,
+                               proportion = 0, flag = wx.ALL, border = 1)
+        
+        self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                                label = self.label),
+                           proportion = 0, flag = wx.ALL, border = 1)
+        
+        # buttons
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.AddButton(self.btnOK)
+        btnSizer.Realize()
+        
+        self.sizer.Add(item = self.dataSizer, proportion = 1,
+                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.sizer.Add(item = btnSizer, proportion = 0,
+                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+    def GetElement(self):
+        """!Return (mapName, overwrite)"""
+        return self.element.GetValue()
+    
+    def GetType(self):
+        """!Get element type"""
+        return self.element.tcp.GetType()
+        
+class LocationDialog(ElementDialog):
+    """!Dialog used to select location"""
+    def __init__(self, parent, title = _("Select GRASS location and mapset"), id =  wx.ID_ANY):
+        ElementDialog.__init__(self, parent, title, label = _("Name of GRASS location:"))
+
+        self.element = LocationSelect(parent = self.panel, id = wx.ID_ANY,
+                                      size = globalvar.DIALOG_GSELECT_SIZE)
+        
+        self.element1 = MapsetSelect(parent = self.panel, id = wx.ID_ANY,
+                                     size = globalvar.DIALOG_GSELECT_SIZE,
+                                     setItems = False)
+        
+        self.PostInit()
+        
+        self.__Layout()
+        self.SetMinSize(self.GetSize())
+
+    def __Layout(self):
+        """!Do layout"""
+        self.dataSizer.Add(self.element, proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+ 
+        self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                         label = _("Name of mapset:")), proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+
+        self.dataSizer.Add(self.element1, proportion = 0,
+                           flag = wx.EXPAND | wx.ALL, border = 1)
+       
+        self.panel.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+    def OnElement(self, event):
+        """!Select mapset given location name"""
+        location = event.GetString()
+        
+        if location:
+            dbase = grass.gisenv()['GISDBASE']
+            self.element1.SetItems(GetListOfMapsets(dbase, location, selectable = True))
+            self.element1.SetSelection(0)
+            mapset = self.element1.GetStringSelection()
+        
+        if location and mapset:
+            self.btnOK.Enable(True)
+        else:
+            self.btnOK.Enable(False)
+
+    def GetValues(self):
+        """!Get location, mapset"""
+        return (self.GetElement(), self.element1.GetStringSelection())
+    
+class MapsetDialog(ElementDialog):
+    """!Dialog used to select mapset"""
+    def __init__(self, parent, title = _("Select mapset in GRASS location"),
+                 location = None, id =  wx.ID_ANY):
+        ElementDialog.__init__(self, parent, title, label = _("Name of mapset:"))
+        if location:
+            self.SetTitle(self.GetTitle() + ' <%s>' % location)
+        else:
+            self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
+        
+        self.element = gselect.MapsetSelect(parent = self.panel, id = wx.ID_ANY,
+                                            size = globalvar.DIALOG_GSELECT_SIZE)
+        
+        self.PostInit()
+        
+        self.__Layout()
+        self.SetMinSize(self.GetSize())
+
+    def __Layout(self):
+        """!Do layout"""
+        self.dataSizer.Add(self.element, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 1)
+        
+        self.panel.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+    def GetMapset(self):
+        return self.GetElement()
+    
+class NewVectorDialog(ElementDialog):
+    def __init__(self, parent, id = wx.ID_ANY, title = _('Create new vector map'),
+                 disableAdd = False, disableTable = False, showType = False,
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
+        """!Dialog for creating new vector map
+
+        @param parent parent window
+        @param id window id
+        @param title window title
+        @param disableAdd disable 'add layer' checkbox
+        @param disableTable disable 'create table' checkbox
+        @param showType True to show feature type selector (used for creating new empty OGR layers)
+        @param style window style
+        @param kwargs other argumentes for ElementDialog
+        
+        @return dialog instance       
+        """
+        ElementDialog.__init__(self, parent, title, label = _("Name for new vector map:"))
+        
+        self.element = Select(parent = self.panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                              type = 'vector', mapsets = [grass.gisenv()['MAPSET'],])
+        
+        # determine output format
+        if showType:
+            self.ftype = OgrTypeSelect(parent = self, panel = self.panel)
+        else:
+            self.ftype = None
+        
+        self.table = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                 label = _("Create attribute table"))
+        self.table.SetValue(True)
+        if disableTable:
+            self.table.Enable(False)
+        
+        if showType:
+            self.keycol = None
+        else:
+            self.keycol = wx.TextCtrl(parent = self.panel, id =  wx.ID_ANY,
+                                      size = globalvar.DIALOG_SPIN_SIZE)
+            self.keycol.SetValue(UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
+            if disableTable:
+                self.keycol.Enable(False)
+        
+        self.addbox = wx.CheckBox(parent = self.panel,
+                                  label = _('Add created map into layer tree'), style = wx.NO_BORDER)
+        if disableAdd:
+            self.addbox.SetValue(True)
+            self.addbox.Enable(False)
+        else:
+            self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
+
+        self.table.Bind(wx.EVT_CHECKBOX, self.OnTable)
+        
+        self.PostInit()
+        
+        self._layout()
+        self.SetMinSize(self.GetSize())
+        
+    def OnMapName(self, event):
+        """!Name for vector map layer given"""
+        self.OnElement(event)
+        
+    def OnTable(self, event):
+        if self.keycol:
+            self.keycol.Enable(event.IsChecked())
+        
+    def _layout(self):
+        """!Do layout"""
+        self.dataSizer.Add(item = self.element, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 1)
+        if self.ftype:
+            self.dataSizer.AddSpacer(1)
+            self.dataSizer.Add(item = self.ftype, proportion = 0,
+                               flag = wx.EXPAND | wx.ALL, border = 1)
+        
+        self.dataSizer.Add(item = self.table, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 1)
+        
+        if self.keycol:
+            keySizer = wx.BoxSizer(wx.HORIZONTAL)
+            keySizer.Add(item = wx.StaticText(parent = self.panel, label = _("Key column:")),
+                         proportion = 0,
+                         flag = wx.ALIGN_CENTER_VERTICAL)
+            keySizer.AddSpacer(10)
+            keySizer.Add(item = self.keycol, proportion = 0,
+                         flag = wx.ALIGN_RIGHT)
+            self.dataSizer.Add(item = keySizer, proportion = 1,
+                               flag = wx.EXPAND | wx.ALL, border = 1)
+            
+        self.dataSizer.AddSpacer(5)
+        
+        self.dataSizer.Add(item = self.addbox, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 1)
+        
+        self.panel.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+    def GetName(self, full = False):
+        """!Get name of vector map to be created
+
+        @param full True to get fully qualified name
+        """
+        name = self.GetElement()
+        if full:
+            if '@' in name:
+                return name
+            else:
+                return name + '@' + grass.gisenv()['MAPSET']
+        
+        return name.split('@', 1)[0]
+
+    def GetKey(self):
+        """!Get key column name"""
+        if self.keycol:
+            return self.keycol.GetValue()
+        return UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value')
+    
+    def IsChecked(self, key):
+        """!Get dialog properties
+
+        @param key window key ('add', 'table')
+
+        @return True/False
+        @return None on error
+        """
+        if key == 'add':
+            return self.addbox.IsChecked()
+        elif key == 'table':
+            return self.table.IsChecked()
+        
+        return None
+    
+    def GetFeatureType(self):
+        """!Get feature type for OGR
+
+        @return feature type as string
+        @return None for native format
+        """
+        if self.ftype:
+            return self.ftype.GetType()
+        
+        return None
+
+def CreateNewVector(parent, cmd, title = _('Create new vector map'),
+                    exceptMap = None, log = None,
+                    disableAdd = False, disableTable = False):
+    """!Create new vector map layer
+    
+    @param cmd (prog, **kwargs)
+    @param title window title
+    @param exceptMap list of maps to be excepted
+    @param log
+    @param disableAdd disable 'add layer' checkbox
+    @param disableTable disable 'create table' checkbox
+    
+    @return dialog instance
+    @return None on error
+    """
+    vExternalOut = grass.parse_command('v.external.out', flags = 'g')
+    isNative = vExternalOut['format'] == 'native'
+    if cmd[0] == 'v.edit' and not isNative:
+        showType = True
+    else:
+        showType = False
+    dlg = NewVectorDialog(parent, title = title,
+                          disableAdd = disableAdd, disableTable = disableTable,
+                          showType = showType)
+    
+    if dlg.ShowModal() != wx.ID_OK:
+        dlg.Destroy()
+        return None
+
+    outmap = dlg.GetName()
+    key    = dlg.GetKey()
+    if outmap == exceptMap:
+        GError(parent = parent,
+               message = _("Unable to create vector map <%s>.") % outmap)
+        dlg.Destroy()
+        return None
+    if dlg.table.IsEnabled() and not key:
+        GError(parent = parent,
+               message = _("Invalid or empty key column.\n"
+                           "Unable to create vector map <%s>.") % outmap)
+        dlg.Destroy()
+        return
+        
+    if outmap == '': # should not happen
+        dlg.Destroy()
+        return None
+
+    # update cmd -> output name defined
+    cmd[1][cmd[2]] = outmap
+    if showType:
+        cmd[1]['type'] = dlg.GetFeatureType()
+        
+    if isNative:
+        listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
+    else:
+        listOfVectors = RunCommand('v.external',
+                                   quiet = True,
+                                   parent = parent,
+                                   read = True,
+                                   flags = 'l',
+                                   dsn = vExternalOut['dsn']).splitlines()
+    
+    overwrite = False
+    if not UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
+            outmap in listOfVectors:
+        dlgOw = wx.MessageDialog(parent, message = _("Vector map <%s> already exists "
+                                                     "in the current mapset. "
+                                                     "Do you want to overwrite it?") % outmap,
+                                 caption = _("Overwrite?"),
+                                 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+        if dlgOw.ShowModal() == wx.ID_YES:
+            overwrite = True
+        else:
+            dlgOw.Destroy()
+            dlg.Destroy()
+            return None
+        
+    if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
+        overwrite = True
+        
+    ret = RunCommand(prog = cmd[0],
+                     parent = parent,
+                     overwrite = overwrite,
+                     **cmd[1])
+    if ret != 0:
+        dlg.Destroy()
+        return None
+    
+    if not isNative:
+        # create link for OGR layers
+        RunCommand('v.external',
+                   overwrite = overwrite,
+                   parent = parent,
+                   dsn = vExternalOut['dsn'],
+                   layer = outmap)
+        
+    # create attribute table
+    if dlg.table.IsEnabled() and dlg.table.IsChecked():
+        if isNative:
+            sql = 'CREATE TABLE %s (%s INTEGER)' % (outmap, key)
+            
+            RunCommand('db.connect',
+                       flags = 'c')
+            
+            Debug.msg(1, "SQL: %s" % sql)
+            RunCommand('db.execute',
+                       quiet = True,
+                       parent = parent,
+                       input = '-',
+                       stdin = sql)
+            
+            RunCommand('v.db.connect',
+                       quiet = True,
+                       parent = parent,
+                       map = outmap,
+                       table = outmap,
+                       key = key,
+                       layer = '1')
+        # TODO: how to deal with attribute tables for OGR layers?
+            
+    # return fully qualified map name
+    if '@' not in outmap:
+        outmap += '@' + grass.gisenv()['MAPSET']
+        
+    if log:
+        log.WriteLog(_("New vector map <%s> created") % outmap)
+        
+    return dlg
+
+class SavedRegion(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, title = "", loadsave = 'load',
+                 **kwargs):
+        """!Loading and saving of display extents to saved region file
+
+        @param loadsave load or save region?
+        """
+        wx.Dialog.__init__(self, parent, id, title, **kwargs)
+
+        self.loadsave = loadsave
+        self.wind = ''
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(parent = self, id = wx.ID_ANY)
+        box.Add(item = label, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
+        if loadsave == 'load':
+            label.SetLabel(_("Load region:"))
+            selection = Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                               type = 'windows')
+        elif loadsave == 'save':
+            label.SetLabel(_("Save region:"))
+            selection = Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                               type = 'windows', mapsets  =  [grass.gisenv()['MAPSET']])
+        
+        box.Add(item = selection, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
+        selection.SetFocus()
+        selection.Bind(wx.EVT_TEXT, self.OnRegion)
+        
+        sizer.Add(item = box, proportion = 0, flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL,
+                  border = 5)
+        
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
+        
+        btnsizer = wx.StdDialogButtonSizer()
+        
+        btn = wx.Button(parent = self, id = wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+        
+        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+        
+        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+        self.Layout()
+        
+    def OnRegion(self, event):
+        self.wind = event.GetString()
+    
+class DecorationDialog(wx.Dialog):
+    """!Controls setting options and displaying/hiding map overlay
+    decorations
+    """
+    def __init__(self, parent, ovlId, title, cmd, name = None,
+                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE,
+                 checktxt = '', ctrltxt = ''):
+        
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
+        
+        self.ovlId   = ovlId   # PseudoDC id
+        self.cmd     = cmd
+        self.name    = name    # overlay name
+        self.parent  = parent  # MapFrame
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY, label = checktxt)
+        if self.parent.Map.GetOverlay(self.ovlId) is None:
+            self.chkbox.SetValue(True)
+        else:
+            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
+        box.Add(item = self.chkbox, proportion = 0,
+                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        optnbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set options"))
+        box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        if self.name == 'legend':
+            box = wx.BoxSizer(wx.HORIZONTAL)
+            resize = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
+            resize.SetToolTipString(_("Click and drag on the map display to set legend"
+                                        " size and position and then press OK"))
+            resize.SetName('resize')
+            if self.parent.IsPaneShown('3d'):
+                resize.Disable()
+            box.Add(item = resize, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
+            sizer.Add(item = box, proportion = 0,
+                      flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(parent = self, id = wx.ID_ANY,
+                              label = _("Drag %s with mouse in pointer mode to position.\n"
+                                      "Double-click to change options." % ctrltxt))
+        if self.name == 'legend':
+            label.SetLabel(label.GetLabel() + _('\nDefine raster map name for legend in '
+                                                'properties dialog.'))
+        box.Add(item = label, proportion = 0,
+                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20,-1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+
+        # buttons
+        btnsizer = wx.StdDialogButtonSizer()
+
+        self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
+        self.btnOK.SetDefault()
+        if self.name == 'legend':
+            self.btnOK.Enable(False)
+        btnsizer.AddButton(self.btnOK)
+
+        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btnCancel)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_BUTTON,   self.OnOptions, optnbtn)
+        if self.name == 'legend':
+            self.Bind(wx.EVT_TOGGLEBUTTON,   self.OnResize, resize)
+        self.Bind(wx.EVT_BUTTON,   self.OnCancel,  btnCancel)
+        self.Bind(wx.EVT_BUTTON,   self.OnOK,      self.btnOK)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+        # create overlay if doesn't exist
+        self._createOverlay()
+        
+        if len(self.parent.MapWindow.overlays[self.ovlId]['cmd']) > 1:
+            if name == 'legend':
+                mapName, found = GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd'])
+                if found:
+                    # enable 'OK' button
+                    self.btnOK.Enable()
+                    # set title
+                    self.SetTitle(_('Legend of raster map <%s>') % \
+                                      mapName)
+            
+        
+    def _createOverlay(self):
+        """!Creates overlay"""
+        if not self.parent.GetMap().GetOverlay(self.ovlId):
+            self.newOverlay = self.parent.Map.AddOverlay(id = self.ovlId, type = self.name,
+                                                         command = self.cmd,
+                                                         l_active = False, l_render = False, l_hidden = True)
+            prop = { 'layer' : self.newOverlay,
+                     'params' : None,
+                     'propwin' : None,
+                     'cmd' : self.cmd,
+                     'coords': (0, 0),
+                     'pdcType': 'image' }
+            self.parent.MapWindow2D.overlays[self.ovlId] = prop
+            if self.parent.MapWindow3D:
+                self.parent.MapWindow3D.overlays[self.ovlId] = prop
+                
+        else:
+            if self.parent.MapWindow.overlays[self.ovlId]['propwin'] == None:
+                return
+            
+            self.parent.MapWindow.overlays[self.ovlId]['propwin'].get_dcmd = self.GetOptData
+        
+    def OnOptions(self, event):
+        """!Sets option for decoration map overlays
+        """
+        if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None:
+            # build properties dialog
+            GUI(parent = self.parent).ParseCommand(cmd = self.cmd,
+                                                   completed = (self.GetOptData, self.name, ''))
+            
+        else:
+            if self.parent.MapWindow.overlays[self.ovlId]['propwin'].IsShown():
+                self.parent.MapWindow.overlays[self.ovlId]['propwin'].SetFocus()
+            else:
+                self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
+        
+    def OnResize(self, event):
+        if self.FindWindowByName('resize').GetValue():
+            self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
+            self.parent.MapWindow.mouse['use'] = 'legend'
+            self.parent.MapWindow.mouse['box'] = 'box'
+            self.parent.MapWindow.pen = wx.Pen(colour = 'Black', width = 2, style = wx.SHORT_DASH)
+        else:
+            self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
+            self.parent.MapWindow.mouse['use'] = 'pointer'
+            
+    def OnCancel(self, event):
+        """!Cancel dialog"""
+        if self.name == 'legend' and self.FindWindowByName('resize').GetValue():
+            self.FindWindowByName('resize').SetValue(False)
+            self.OnResize(None)
+            
+        self.parent.dialogs['barscale'] = None
+        if event and hasattr(self, 'newOverlay'):
+            self.parent.Map.DeleteOverlay(self.newOverlay)
+        self.Destroy()
+
+    def OnOK(self, event):
+        """!Button 'OK' pressed"""
+        # enable or disable overlay
+        self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
+        
+        # update map
+        if self.parent.IsPaneShown('3d'):
+            self.parent.MapWindow.UpdateOverlays()
+        
+        self.parent.MapWindow.UpdateMap()
+        
+        # close dialog
+        self.OnCancel(None)
+        
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """!Process decoration layer data"""
+        # update layer data
+        if params:
+            self.parent.MapWindow.overlays[self.ovlId]['params'] = params
+        if dcmd:
+            self.parent.MapWindow.overlays[self.ovlId]['cmd'] = dcmd
+        self.parent.MapWindow.overlays[self.ovlId]['propwin'] = propwin
+
+        # change parameters for item in layers list in render.Map
+        # "Use mouse..." (-m) flag causes GUI freeze and is pointless here, trac #119
+        
+        try:
+            self.parent.MapWindow.overlays[self.ovlId]['cmd'].remove('-m')
+        except ValueError:
+            pass
+            
+        self.parent.Map.ChangeOverlay(id = self.ovlId, type = self.name,
+                                      command = self.parent.MapWindow.overlays[self.ovlId]['cmd'],
+                                      l_active = self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive(),
+                                      l_render = False, l_hidden = True)
+        if  self.name == 'legend':
+            if params and not self.btnOK.IsEnabled():
+                self.btnOK.Enable()
+            
+class TextLayerDialog(wx.Dialog):
+    """
+    Controls setting options and displaying/hiding map overlay decorations
+    """
+
+    def __init__(self, parent, ovlId, title, name = 'text',
+                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE):
+
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
+        from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
+
+        self.ovlId = ovlId
+        self.parent = parent
+
+        if self.ovlId in self.parent.MapWindow.textdict.keys():
+            self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
+            self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
+            self.currClr  = self.parent.MapWindow.textdict[self.ovlId]['color']
+            self.currRot  = self.parent.MapWindow.textdict[self.ovlId]['rotation']
+            self.currCoords = self.parent.MapWindow.textdict[self.ovlId]['coords']
+            self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
+        else:
+            self.currClr = wx.BLACK
+            self.currText = ''
+            self.currFont = self.GetFont()
+            self.currRot = 0.0
+            self.currCoords = [10, 10]
+            self.currBB = wx.Rect()
+
+        self.sizer = wx.BoxSizer(wx.VERTICAL)
+        box = wx.GridBagSizer(vgap = 5, hgap = 5)
+
+        # show/hide
+        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
+                                  label = _('Show text object'))
+        if self.parent.Map.GetOverlay(self.ovlId) is None:
+            self.chkbox.SetValue(True)
+        else:
+            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
+        box.Add(item = self.chkbox, span = (1,2),
+                flag = wx.ALIGN_LEFT|wx.ALL, border = 5,
+                pos = (0, 0))
+
+        # text entry
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Enter text:"))
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL,
+                pos = (1, 0))
+
+        self.textentry = ExpandoTextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (300,-1))
+        self.textentry.SetFont(self.currFont)
+        self.textentry.SetForegroundColour(self.currClr)
+        self.textentry.SetValue(self.currText)
+        # get rid of unneeded scrollbar when text box first opened
+        self.textentry.SetClientSize((300,-1))
+        
+        box.Add(item = self.textentry,
+                pos = (1, 1))
+
+        # rotation
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Rotation:"))
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL,
+                pos = (2, 0))
+        self.rotation = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
+                                    size = (75,-1), style = wx.SP_ARROW_KEYS)
+        self.rotation.SetRange(-360, 360)
+        self.rotation.SetValue(int(self.currRot))
+        box.Add(item = self.rotation,
+                flag = wx.ALIGN_RIGHT,
+                pos = (2, 1))
+
+        # font
+        fontbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set font"))
+        box.Add(item = fontbtn,
+                flag = wx.ALIGN_RIGHT,
+                pos = (3, 1))
+
+        self.sizer.Add(item = box, proportion = 1,
+                  flag = wx.ALL, border = 10)
+
+        # note
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        label = wx.StaticText(parent = self, id = wx.ID_ANY,
+                              label = _("Drag text with mouse in pointer mode "
+                                      "to position.\nDouble-click to change options"))
+        box.Add(item = label, proportion = 0,
+                flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
+        self.sizer.Add(item = box, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border = 5)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY,
+                             size = (20,-1), style = wx.LI_HORIZONTAL)
+        self.sizer.Add(item = line, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(parent = self, id = wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        self.sizer.Add(item = btnsizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        self.SetSizer(self.sizer)
+        self.sizer.Fit(self)
+
+        # bindings
+        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
+        self.Bind(wx.EVT_BUTTON,     self.OnSelectFont, fontbtn)
+        self.Bind(wx.EVT_TEXT,       self.OnText,       self.textentry)
+        self.Bind(wx.EVT_SPINCTRL,   self.OnRotation,   self.rotation)
+
+    def OnRefit(self, event):
+        """!Resize text entry to match text"""
+        self.sizer.Fit(self)
+
+    def OnText(self, event):
+        """!Change text string"""
+        self.currText = event.GetString()
+
+    def OnRotation(self, event):
+        """!Change rotation"""
+        self.currRot = event.GetInt()
+
+        event.Skip()
+
+    def OnSelectFont(self, event):
+        """!Change font"""
+        data = wx.FontData()
+        data.EnableEffects(True)
+        data.SetColour(self.currClr)         # set colour
+        data.SetInitialFont(self.currFont)
+
+        dlg = wx.FontDialog(self, data)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetFontData()
+            self.currFont = data.GetChosenFont()
+            self.currClr = data.GetColour()
+
+            self.textentry.SetFont(self.currFont)
+            self.textentry.SetForegroundColour(self.currClr)
+
+            self.Layout()
+
+        dlg.Destroy()
+
+    def GetValues(self):
+        """!Get text properties"""
+        return { 'text' : self.currText,
+                 'font' : self.currFont,
+                 'color' : self.currClr,
+                 'rotation' : self.currRot,
+                 'coords' : self.currCoords,
+                 'active' : self.chkbox.IsChecked() }
+
+class GroupDialog(wx.Dialog):
+    """!Dialog for creating/editing groups"""
+    def __init__(self, parent = None, defaultGroup = None, 
+                 title = _("Create or edit imagery groups"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+                     
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
+                            style = style, **kwargs)
+                            
+        self.parent = parent
+        self.defaultGroup = defaultGroup
+        self.currentGroup = self.defaultGroup
+        self.groupChanged = False
+        
+        self.bodySizer = self._createDialogBody()
+        
+        # buttons
+        btnOk = wx.Button(parent = self, id = wx.ID_OK)
+        btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
+        btnClose = wx.Button(parent = self, id = wx.ID_CANCEL)
+        
+        btnOk.SetToolTipString(_("Apply changes to selected group and close dialog"))
+        btnApply.SetToolTipString(_("Apply changes to selected group"))
+        btnClose.SetToolTipString(_("Close dialog, changes are not applied"))
+
+        btnOk.SetDefault()
+        
+        # sizers & do layout
+        # btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        # btnSizer.Add(item = btnClose, proportion = 0,
+        #              flag = wx.RIGHT | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
+        # btnSizer.Add(item = btnApply, proportion = 0,
+        #              flag = wx.LEFT, border = 5)
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnOk)
+        btnSizer.AddButton(btnApply)
+        btnSizer.AddButton(btnClose)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.bodySizer, proportion = 1,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
+        mainSizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
+                      style = wx.LI_HORIZONTAL), proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10) 
+        
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.ALL | wx.ALIGN_RIGHT, border = 10)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+        btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
+
+        # set dialog min size
+        self.SetMinSize(self.GetSize())
+        
+    def _createDialogBody(self):
+        bodySizer = wx.BoxSizer(wx.VERTICAL)
+    
+        # group selection
+        bodySizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = _("Select the group you want to edit or "
+                                                     "enter name of new group:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
+        self.groupSelect = Select(parent = self, type = 'group',
+                                  mapsets = [grass.gisenv()['MAPSET']],
+                                  size = globalvar.DIALOG_GSELECT_SIZE) # searchpath?
+            
+        bodySizer.Add(item = self.groupSelect, flag = wx.TOP | wx.EXPAND, border = 5)
+        
+        bodySizer.AddSpacer(10)
+        # layers in group
+        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Layers in selected group:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM, border = 5)
+        
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        gridSizer.AddGrowableCol(0)
+        
+        self.layerBox = wx.ListBox(parent = self,  id = wx.ID_ANY, size = (-1, 150),
+                                   style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
+        
+        gridSizer.Add(item = self.layerBox, pos = (0, 0), span = (2, 1), flag = wx.EXPAND)
+        
+        self.addLayer = wx.Button(self, id = wx.ID_ADD)
+        self.addLayer.SetToolTipString(_("Select map layers and add them to the list."))
+        gridSizer.Add(item = self.addLayer, pos = (0, 1))
+        
+        self.removeLayer = wx.Button(self, id = wx.ID_REMOVE)
+        self.removeLayer.SetToolTipString(_("Remove selected layer(s) from list."))
+        gridSizer.Add(item = self.removeLayer, pos = (1, 1))
+        
+        bodySizer.Add(item = gridSizer, proportion = 1, flag = wx.EXPAND)
+        
+        self.infoLabel = wx.StaticText(parent = self, id = wx.ID_ANY)
+        bodySizer.Add(item = self.infoLabel, 
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, border = 5)
+        
+        # bindings
+        self.groupSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnGroupSelected)
+        self.addLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
+        self.removeLayer.Bind(wx.EVT_BUTTON, self.OnRemoveLayer)
+        
+        if self.defaultGroup:
+            self.groupSelect.SetValue(self.defaultGroup)
+        
+        return bodySizer
+        
+    def OnAddLayer(self, event):
+        """!Add new layer to listbox"""
+        dlg = MapLayersDialog(parent = self, title = _("Add selected map layers into group"),
+                              mapType = 'raster', selectAll = False,
+                              fullyQualified = True, showFullyQualified = False)
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        
+        layers = dlg.GetMapLayers()
+        for layer in layers:
+            if layer not in self.GetLayers():
+                self.layerBox.Append(layer)
+                self.groupChanged = True
+            
+    
+    def OnRemoveLayer(self, event):
+        """!Remove layer from listbox"""
+        while self.layerBox.GetSelections():
+            sel = self.layerBox.GetSelections()[0]
+            self.layerBox.Delete(sel)
+            self.groupChanged = True
+                
+    def GetLayers(self):
+        """!Get layers"""
+        return self.layerBox.GetItems()
+        
+    def OnGroupSelected(self, event):
+        """!Text changed in group selector"""
+        # callAfter must be called to close popup before other actions
+        wx.CallAfter(self.GroupSelected)
+        
+    def GroupSelected(self):
+        """!Group was selected, check if changes were apllied"""
+        group = self.GetSelectedGroup()
+        if self.groupChanged:
+            dlg = wx.MessageDialog(self, message = _("Group <%s> was changed, "
+                                                     "do you want to apply changes?") % self.currentGroup,
+                                   caption = _("Unapplied changes"),
+                                   style = wx.YES_NO | wx.ICON_QUESTION | wx.YES_DEFAULT)
+            if dlg.ShowModal() == wx.ID_YES:
+                self.ApplyChanges(showResult = True)
+                
+            dlg.Destroy()
+            
+            
+        
+        groups = self.GetExistGroups()
+        if group in groups:
+            self.ShowGroupLayers(self.GetGroupLayers(group))
+            
+        self.currentGroup = group
+        self.groupChanged = False
+        
+        self.ClearNotification()
+        
+    def ShowGroupLayers(self, mapList):
+        """!Show map layers in currently selected group"""
+        self.layerBox.Set(mapList)
+        
+        
+    def EditGroup(self, group):
+        """!Edit selected group"""
+        layersNew = self.GetLayers()
+        layersOld = self.GetGroupLayers(group)
+        
+        add = []
+        remove = []
+        for layerNew in layersNew:
+            if layerNew not in layersOld:
+                add.append(layerNew)
+                
+        for layerOld in layersOld:
+            if layerOld not in layersNew:
+                remove.append(layerOld)
+        
+        ret = None
+        if remove:
+            ret = RunCommand('i.group',
+                             parent = self,
+                             group = group,
+                             flags = 'r',
+                             input = ','.join(remove))
+                        
+        if add:
+            ret = RunCommand('i.group',
+                             parent = self,
+                             group = group,
+                             input = ','.join(add))
+                            
+        return ret
+        
+    def CreateNewGroup(self, group):
+        """!Create new group"""
+        layers = self.GetLayers()
+        ret = RunCommand('i.group',
+                         parent = self,
+                         group = group,
+                         input = layers)
+        return ret
+        
+                        
+    def GetExistGroups(self):
+        """!Returns existing groups in current mapset"""
+        return grass.list_grouped('group')[grass.gisenv()['MAPSET']]
+        
+    def ShowResult(self, group, returnCode, create):
+        """!Show if operation was successfull."""
+        group += '@' + grass.gisenv()['MAPSET']
+        if returnCode is None:
+            label = _("No changes to apply in group <%s>.") % group
+        elif returnCode == 0:
+            if create:
+                label = _("Group <%s> was successfully created.") % group
+            else:
+                label = _("Group <%s> was successfully changed.") % group
+        else:
+            if create:
+                label = _("Creating of new group <%s> failed.") % group
+            else:
+                label = _("Changing of group <%s> failed.") % group
+                
+        self.infoLabel.SetLabel(label)
+        wx.FutureCall(4000, self.ClearNotification)
+        
+    def GetSelectedGroup(self):
+        """!Return currently selected group (without mapset)"""
+        return self.groupSelect.GetValue().split('@')[0]
+        
+    def GetGroupLayers(self, group):
+        """!Get layers in group"""
+        res = RunCommand('i.group',
+                         parent = self,
+                         flags = 'g',
+                         group = group,
+                         read = True).strip()
+        if res.split('\n')[0]:
+            return res.split('\n')
+        return []
+        
+    def ClearNotification(self):
+        """!Clear notification string"""
+        self.infoLabel.SetLabel("")
+       
+    def ApplyChanges(self, showResult):
+        """!Create or edit group"""
+        group = self.currentGroup
+        if not group:
+            GMessage(parent = self,
+                     message = _("No group selected."))
+            return False
+        
+        groups = self.GetExistGroups()
+        if group in groups:
+            ret = self.EditGroup(group)
+            self.ShowResult(group = group, returnCode = ret, create = False)
+            
+        else:
+            ret = self.CreateNewGroup(group)
+            self.ShowResult(group = group, returnCode = ret, create = True)
+            
+        self.groupChanged = False
+        
+        return True
+        
+    def OnApply(self, event):
+        """!Apply changes"""
+        self.ApplyChanges(showResult = True)
+        
+    def OnOk(self, event):
+        """!Apply changes and close dialog"""
+        if self.ApplyChanges(showResult = False):
+            self.OnClose(event)
+        
+    def OnClose(self, event):
+        """!Close dialog"""
+        if not self.IsModal():
+            self.Destroy()
+        event.Skip()
+        
+class MapLayersDialog(wx.Dialog):
+    def __init__(self, parent, title, modeler = False,
+                 mapType = None, selectAll = True, fullyQualified = True, showFullyQualified = True, 
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        """!Dialog for selecting map layers (raster, vector)
+        
+        @param mapType type of map (if None: raster, vector, 3d raster, if one only: selects it and disables selection)
+        @param selectAll all/none maps should be selected by default
+        @param fullyQualified True if dialog should return full map names by default
+        @param showFullyQualified True to show 'fullyQualified' checkbox, otherwise hide it
+        """
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
+                           style = style, **kwargs)
+        
+        self.parent = parent # GMFrame or ?
+        self.mapType = mapType
+        self.selectAll = selectAll
+        
+        # dialog body
+        self.bodySizer = self._createDialogBody()
+        # update list of layer to be loaded
+        self.map_layers = [] # list of map layers (full list type/mapset)
+        self.LoadMapLayers(self.GetLayerType(cmd = True),
+                           self.mapset.GetStringSelection())
+        
+        self.fullyQualified = wx.CheckBox(parent = self, id = wx.ID_ANY,
+                                          label = _("Use fully-qualified map names"))
+        self.fullyQualified.SetValue(fullyQualified)
+        self.fullyQualified.Show(showFullyQualified)
+
+        self.dseries = None
+        if modeler:
+            self.dseries = wx.CheckBox(parent = self, id = wx.ID_ANY,
+                                       label = _("Dynamic series (%s)") % 'g.mlist')
+            self.dseries.SetValue(False)
+        
+        # buttons
+        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+        btnOk = wx.Button(parent = self, id = wx.ID_OK)
+        btnOk.SetDefault()
+        
+        # sizers & do layout
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        btnSizer.AddButton(btnOk)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.bodySizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = self.fullyQualified, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+        if self.dseries:
+            mainSizer.Add(item = self.dseries, proportion = 0,
+                          flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+        
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+        # set dialog min size
+        self.SetMinSize(self.GetSize())
+        
+    def _createDialogBody(self):
+        bodySizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        bodySizer.AddGrowableCol(1)
+        bodySizer.AddGrowableRow(3)
+        
+        # layer type
+        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Map type:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0,0))
+        
+        self.layerType = wx.Choice(parent = self, id = wx.ID_ANY,
+                                   choices = [_('raster'), _('3D raster'), _('vector')], size = (100,-1))
+        
+        if self.mapType:
+            self.layerType.SetStringSelection(self.mapType)
+            self.layerType.Disable()
+        else:
+            self.layerType.SetSelection(0)
+            
+        bodySizer.Add(item = self.layerType,
+                      pos = (0,1))
+        
+        # select toggle
+        self.toggle = wx.CheckBox(parent = self, id = wx.ID_ANY,
+                                  label = _("Select toggle"))
+        self.toggle.SetValue(self.selectAll)
+        bodySizer.Add(item = self.toggle,
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0,2))
+        
+        # mapset filter
+        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Mapset:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1,0))
+        
+        self.mapset = MapsetSelect(parent = self, searchPath = True)
+        self.mapset.SetStringSelection(grass.gisenv()['MAPSET'])
+        bodySizer.Add(item = self.mapset,
+                      pos = (1,1), span = (1, 2))
+        
+        # map name filter
+        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Pattern:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2,0))
+        
+        self.filter = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+                                  value = "",
+                                  size = (250,-1))
+        bodySizer.Add(item = self.filter,
+                      flag = wx.EXPAND,
+                      pos = (2,1), span = (1, 2))
+        
+        # layer list 
+        bodySizer.Add(item = wx.StaticText(parent = self, label = _("List of maps:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
+                      pos = (3,0))
+        self.layers = wx.CheckListBox(parent = self, id = wx.ID_ANY,
+                                      size = (250, 100),
+                                      choices = [])
+        bodySizer.Add(item = self.layers,
+                      flag = wx.EXPAND,
+                      pos = (3,1), span = (1, 2))
+        
+        # bindings
+        self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
+        self.mapset.Bind(wx.EVT_COMBOBOX, self.OnChangeParams)
+        self.layers.Bind(wx.EVT_RIGHT_DOWN, self.OnMenu)
+        self.filter.Bind(wx.EVT_TEXT, self.OnFilter)
+        self.toggle.Bind(wx.EVT_CHECKBOX, self.OnToggle)
+        
+        return bodySizer
+
+    def LoadMapLayers(self, type, mapset):
+        """!Load list of map layers
+
+        @param type layer type ('raster' or 'vector')
+        @param mapset mapset name
+        """
+        self.map_layers = grass.mlist_grouped(type = type)[mapset]
+        self.layers.Set(self.map_layers)
+        
+        # check all items by default
+        for item in range(self.layers.GetCount()):
+            
+            self.layers.Check(item, check = self.selectAll)
+        
+    def OnChangeParams(self, event):
+        """!Filter parameters changed by user"""
+        # update list of layer to be loaded
+        self.LoadMapLayers(self.GetLayerType(cmd = True),
+                           self.mapset.GetStringSelection())
+        
+        event.Skip()
+        
+    def OnMenu(self, event):
+        """!Table description area, context menu"""
+        if not hasattr(self, "popupID1"):
+            self.popupDataID1 = wx.NewId()
+            self.popupDataID2 = wx.NewId()
+            self.popupDataID3 = wx.NewId()
+
+            self.Bind(wx.EVT_MENU, self.OnSelectAll,    id = self.popupDataID1)
+            self.Bind(wx.EVT_MENU, self.OnSelectInvert, id = self.popupDataID2)
+            self.Bind(wx.EVT_MENU, self.OnDeselectAll,  id = self.popupDataID3)
+        
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupDataID1, _("Select all"))
+        menu.Append(self.popupDataID2, _("Invert selection"))
+        menu.Append(self.popupDataID3, _("Deselect all"))
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+        
+    def OnSelectAll(self, event):
+        """!Select all map layer from list"""
+        for item in range(self.layers.GetCount()):
+            self.layers.Check(item, True)
+        
+    def OnSelectInvert(self, event):
+        """!Invert current selection"""
+        for item in range(self.layers.GetCount()):
+            if self.layers.IsChecked(item):
+                self.layers.Check(item, False)
+            else:
+                self.layers.Check(item, True)
+        
+    def OnDeselectAll(self, event):
+        """!Select all map layer from list"""
+        for item in range(self.layers.GetCount()):
+            self.layers.Check(item, False)
+        
+    def OnFilter(self, event):
+        """!Apply filter for map names"""
+        if len(event.GetString()) == 0:
+           self.layers.Set(self.map_layers) 
+           return 
+        
+        list = []
+        for layer in self.map_layers:
+            try:
+                if re.compile('^' + event.GetString()).search(layer):
+                    list.append(layer)
+            except:
+                pass
+        
+        self.layers.Set(list)
+        self.OnSelectAll(None)
+        
+        event.Skip()
+        
+    def OnToggle(self, event):
+        """!Select toggle (check or uncheck all layers)"""
+        check = event.Checked()
+        for item in range(self.layers.GetCount()):
+            self.layers.Check(item, check)
+        
+        event.Skip()
+        
+    def GetMapLayers(self):
+        """!Return list of checked map layers"""
+        layerNames = []
+        for indx in self.layers.GetSelections():
+            # layers.append(self.layers.GetStringSelec(indx))
+            pass
+
+        fullyQualified = self.fullyQualified.IsChecked()
+        mapset = self.mapset.GetStringSelection()
+        for item in range(self.layers.GetCount()):
+            if not self.layers.IsChecked(item):
+                continue
+            if fullyQualified:
+                layerNames.append(self.layers.GetString(item) + '@' + mapset)
+            else:
+                layerNames.append(self.layers.GetString(item))
+        
+        return layerNames
+    
+    def GetLayerType(self, cmd = False):
+        """!Get selected layer type
+
+        @param cmd True for g.mlist
+        """
+        if not cmd:
+            return self.layerType.GetStringSelection()
+        
+        sel = self.layerType.GetSelection()
+        if sel == 0:
+            ltype = 'rast'
+        elif sel == 1:
+            ltype = 'rast3d'
+        else:
+            ltype = 'vect'
+        
+        return ltype
+
+    def GetDSeries(self):
+        """!Used by modeler only
+
+        @return g.mlist command
+        """
+        if not self.dseries or not self.dseries.IsChecked():
+            return ''
+        
+        cond = 'map in `g.mlist type=%s ' % self.GetLayerType(cmd = True)
+        patt = self.filter.GetValue()
+        if patt:
+            cond += 'pattern=%s ' % patt
+        cond += 'mapset=%s`' % self.mapset.GetStringSelection()
+        
+        return cond
+    
+class ImportDialog(wx.Dialog):
+    """!Dialog for bulk import of various data (base class)"""
+    def __init__(self, parent, itype,
+                 id = wx.ID_ANY, title = _("Multiple import"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        self.parent = parent    # GMFrame 
+        self.importType = itype
+        self.options = dict()   # list of options
+        
+        self.commandId = -1  # id of running command
+        
+        wx.Dialog.__init__(self, parent, id, title, style = style,
+                           name = "MultiImportDialog")
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.layerBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                     label = _(" List of %s layers ") % self.importType.upper())
+        
+        #
+        # list of layers
+        #
+        columns = [_('Layer id'),
+                   _('Layer name'),
+                   _('Name for GRASS map (editable)')]
+        if itype == 'ogr':
+            columns.insert(2, _('Feature type'))
+        self.list = LayersList(parent = self.panel, columns = columns)
+        self.list.LoadData()
+
+        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                      label = "%s" % _("Options"))
+        
+        cmd = self._getCommand()
+        task = gtask.parse_interface(cmd)
+        for f in task.get_options()['flags']:
+            name = f.get('name', '')
+            desc = f.get('label', '')
+            if not desc:
+                desc = f.get('description', '')
+            if not name and not desc:
+                continue
+            if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
+                continue
+            elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
+                continue
+            elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
+                continue
+            elif cmd == 'v.external' and name not in ('b'):
+                continue
+            elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
+                continue
+            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                             label = desc)
+        
+        
+        self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                     label = _("Allow output files to overwrite existing files"))
+        self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
+        
+        self.add = wx.CheckBox(parent = self.panel, id = wx.ID_ANY)
+        
+        #
+        # buttons
+        #
+        # cancel
+        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.btn_cancel.SetToolTipString(_("Close dialog"))
+        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        # run
+        self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
+        self.btn_run.SetToolTipString(_("Import selected layers"))
+        self.btn_run.SetDefault()
+        self.btn_run.Enable(False)
+        self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
+        # run command dialog
+        self.btn_cmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                 label = _("Command dialog"))
+        self.btn_cmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+        
+    def doLayout(self):
+        """!Do layout"""
+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # dsn input
+        dialogSizer.Add(item = self.dsnInput, proportion = 0,
+                        flag = wx.EXPAND)
+        
+        #
+        # list of DXF layers
+        #
+        layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
+
+        layerSizer.Add(item = self.list, proportion = 1,
+                      flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        dialogSizer.Add(item = layerSizer, proportion = 1,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        # options
+        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
+        for key in self.options.keys():
+            optionSizer.Add(item = self.options[key], proportion = 0)
+            
+        dialogSizer.Add(item = optionSizer, proportion = 0,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+        
+        dialogSizer.Add(item = self.overwrite, proportion = 0,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        
+        dialogSizer.Add(item = self.add, proportion = 0,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        
+        #
+        # buttons
+        #
+        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+        
+        btnsizer.Add(item = self.btn_cmd, proportion = 0,
+                     flag = wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        btnsizer.Add(item = self.btn_cancel, proportion = 0,
+                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        btnsizer.Add(item = self.btn_run, proportion = 0,
+                     flag = wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        dialogSizer.Add(item = btnsizer, proportion = 0,
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
+                        border = 10)
+        
+        # dialogSizer.SetSizeHints(self.panel)
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(dialogSizer)
+        dialogSizer.Fit(self.panel)
+        
+        # auto-layout seems not work here - FIXME
+        size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, 550)
+        self.SetMinSize(size)
+        self.SetSize((size.width, size.height + 100))
+        # width = self.GetSize()[0]
+        # self.list.SetColumnWidth(col = 1, width = width / 2 - 50)
+        self.Layout()
+
+    def _getCommand(self):
+        """!Get command"""
+        return ''
+    
+    def OnCancel(self, event = None):
+        """!Close dialog"""
+        self.Close()
+
+    def OnRun(self, event):
+        """!Import/Link data (each layes as separate vector map)"""
+        pass
+
+    def OnCmdDialog(self, event):
+        """!Show command dialog"""
+        pass
+    
+    def AddLayers(self, returncode, cmd = None):
+        """!Add imported/linked layers into layer tree"""
+        self.commandId += 1
+        
+        if not self.add.IsChecked() or returncode != 0:
+            return
+        
+        maptree = self.parent.curr_page.maptree
+        
+        layer, output = self.list.GetLayers()[self.commandId]
+        
+        if '@' not in output:
+            name = output + '@' + grass.gisenv()['MAPSET']
+        else:
+            name = output
+        
+        # add imported layers into layer tree
+        if self.importType == 'gdal':
+            cmd = ['d.rast',
+                   'map=%s' % name]
+            if UserSettings.Get(group = 'cmd', key = 'rasterOverlay', subkey = 'enabled'):
+                cmd.append('-o')
+                
+            item = maptree.AddLayer(ltype = 'raster',
+                                    lname = name, lchecked = False,
+                                    lcmd = cmd)
+        else:
+            item = maptree.AddLayer(ltype = 'vector',
+                                    lname = name, lchecked = False,
+                                    lcmd = ['d.vect',
+                                            'map=%s' % name])
+        
+        maptree.mapdisplay.MapWindow.ZoomToMap()
+        
+    def OnAbort(self, event):
+        """!Abort running import
+
+        @todo not yet implemented
+        """
+        pass
+
+class GdalImportDialog(ImportDialog):
+    def __init__(self, parent, ogr = False, link = False):
+        """!Dialog for bulk import of various raster/vector data
+
+        @param parent parent window
+        @param ogr True for OGR (vector) otherwise GDAL (raster)
+        @param link True for linking data otherwise importing data
+        """
+        self.link = link
+        self.ogr  = ogr
+        
+        if ogr:
+            ImportDialog.__init__(self, parent, itype = 'ogr')
+            if link:
+                self.SetTitle(_("Link external vector data"))
+            else:
+                self.SetTitle(_("Import vector data"))
+        else:
+            ImportDialog.__init__(self, parent, itype = 'gdal') 
+            if link:
+                self.SetTitle(_("Link external raster data"))
+            else:
+                self.SetTitle(_("Import raster data"))
+        
+        self.dsnInput = GdalSelect(parent = self, panel = self.panel, ogr = ogr)
+        
+        if link:
+            self.add.SetLabel(_("Add linked layers into layer tree"))
+        else:
+            self.add.SetLabel(_("Add imported layers into layer tree"))
+        
+        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
+
+        if link:
+            self.btn_run.SetLabel(_("&Link"))
+            self.btn_run.SetToolTipString(_("Link selected layers"))
+            if ogr:
+                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'v.external')
+            else:
+                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'r.external')
+        else:
+            self.btn_run.SetLabel(_("&Import"))
+            self.btn_run.SetToolTipString(_("Import selected layers"))
+            if ogr:
+                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'v.in.ogr')
+            else:
+                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'r.in.gdal')
+        
+        self.doLayout()
+
+    def OnRun(self, event):
+        """!Import/Link data (each layes as separate vector map)"""
+        data = self.list.GetLayers()
+        
+        # hide dialog
+        self.Hide()
+        
+        dsn = self.dsnInput.GetDsn()
+        ext = self.dsnInput.GetFormatExt()
+            
+        for layer, output in data:
+            if self.importType == 'ogr':
+                if ext and layer.rfind(ext) > -1:
+                    layer = layer.replace('.' + ext, '')
+                if self.link:
+                    cmd = ['v.external',
+                           'dsn=%s' % dsn,
+                           'output=%s' % output,
+                           'layer=%s' % layer]
+                else:
+                    cmd = ['v.in.ogr',
+                           'dsn=%s' % dsn,
+                           'layer=%s' % layer,
+                           'output=%s' % output]
+            else: # gdal
+                if self.dsnInput.GetType() == 'dir':
+                    idsn = os.path.join(dsn, layer)
+                else:
+                    idsn = dsn
+                
+                if self.link:
+                    cmd = ['r.external',
+                           'input=%s' % idsn,
+                           'output=%s' % output]
+                else:
+                    cmd = ['r.in.gdal',
+                           'input=%s' % idsn,
+                           'output=%s' % output]
+            
+            if self.overwrite.IsChecked():
+                cmd.append('--overwrite')
+            
+            for key in self.options.keys():
+                if self.options[key].IsChecked():
+                    cmd.append('-%s' % key)
+            
+            if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
+                cmd.append('--overwrite')
+            
+            # run in Layer Manager
+            self.parent.goutput.RunCmd(cmd, switchPage = True,
+                                       onDone = self.AddLayers)
+        
+        self.OnCancel()
+
+    def _getCommand(self):
+        """!Get command"""
+        if self.link:
+            if self.ogr:
+                return 'v.external'
+            else:
+                return 'r.external'
+        else:
+            if self.ogr:
+                return 'v.in.ogr'
+            else:
+                return 'r.in.gdal'
+        
+        return ''
+    
+    def OnCmdDialog(self, event):
+        """!Show command dialog"""
+        name = self._getCommand()
+        GUI(parent = self, modal = False).ParseCommand(cmd = [name])
+
+class GdalOutputDialog(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, ogr = False,
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
+        """!Dialog for setting output format for rasters/vectors
+
+        @param parent parent window
+        @param id window id
+        @param ogr True for OGR (vector) otherwise GDAL (raster)
+        @param style window style
+        @param *kwargs other wx.Dialog's arguments
+        """
+        self.parent = parent # GMFrame 
+        self.ogr = ogr
+        wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
+        if self.ogr:
+            self.SetTitle(_("Define output format for vector data"))
+        else:
+            self.SetTitle(_("Define output format for raster data"))
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+        # buttons
+        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                label = _("Command dialog"))
+        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.btnCancel.SetToolTipString(_("Close dialog"))
+        self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
+        self.btnOk.SetToolTipString(_("Set external format and close dialog"))
+        self.btnOk.SetDefault()
+        self.btnOk.Enable(False)
+        
+        self.dsnInput = GdalSelect(parent = self, panel = self.panel,
+                                   ogr = ogr,
+                                   exclude = ['file', 'protocol'], dest = True)
+        
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
+        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
+        
+        self._layout()
+
+    def _layout(self):
+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        dialogSizer.Add(item = self.dsnInput, proportion = 0,
+                        flag = wx.EXPAND)
+
+        btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+        btnSizer.Add(item = self.btnCmd, proportion = 0,
+                     flag = wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        btnSizer.Add(item = self.btnCancel, proportion = 0,
+                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        btnSizer.Add(item = self.btnOk, proportion = 0,
+                     flag = wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        dialogSizer.Add(item = btnSizer, proportion = 0,
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
+                        border = 10)
+        
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(dialogSizer)
+        dialogSizer.Fit(self.panel)
+
+        size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, self.GetBestSize()[1])
+        self.SetMinSize(size)
+        self.SetSize((size.width, size.height))
+        self.Layout()
+        
+    def OnCmdDialog(self, event):
+        GUI(parent = self, modal = True).ParseCommand(cmd = ['v.external.out'])
+    
+    def OnCancel(self, event):
+        self.Destroy()
+        
+    def OnOK(self, event):
+        if self.dsnInput.GetType() == 'native':
+            RunCommand('v.external.out',
+                       parent = self,
+                       flags = 'r')
+        else:
+            dsn = self.dsnInput.GetDsn()
+            frmt = self.dsnInput.GetFormat()
+            options = self.dsnInput.GetOptions()
+            
+            RunCommand('v.external.out',
+                       parent = self,
+                       dsn = dsn, format = frmt,
+                       options = options)
+        self.Close()
+        
+class DxfImportDialog(ImportDialog):
+    """!Dialog for bulk import of DXF layers""" 
+    def __init__(self, parent):
+        ImportDialog.__init__(self, parent, itype = 'dxf',
+                              title = _("Import DXF layers"))
+        
+        self.dsnInput = filebrowse.FileBrowseButton(parent = self.panel, id = wx.ID_ANY, 
+                                                    size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
+                                                    dialogTitle = _('Choose DXF file to import'),
+                                                    buttonText = _('Browse'),
+                                                    startDirectory = os.getcwd(), fileMode = 0,
+                                                    changeCallback = self.OnSetDsn,
+                                                    fileMask = "DXF File (*.dxf)|*.dxf")
+        
+        self.add.SetLabel(_("Add imported layers into layer tree"))
+        
+        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
+        
+        self.doLayout()
+
+    def _getCommand(self):
+        """!Get command"""
+        return 'v.in.dxf'
+    
+    def OnRun(self, event):
+        """!Import/Link data (each layes as separate vector map)"""
+        data = self.list.GetLayers()
+        
+        # hide dialog
+        self.Hide()
+        
+        inputDxf = self.dsnInput.GetValue()
+        
+        for layer, output in data:
+            cmd = ['v.in.dxf',
+                   'input=%s' % inputDxf,
+                   'layers=%s' % layer,
+                   'output=%s' % output]
+
+            for key in self.options.keys():
+                if self.options[key].IsChecked():
+                    cmd.append('-%s' % key)
+            
+            if self.overwrite.IsChecked() or \
+                    UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
+                cmd.append('--overwrite')
+            
+            # run in Layer Manager
+            self.parent.goutput.RunCmd(cmd, switchPage = True,
+                                       onDone = self.AddLayers)
+        
+        self.OnCancel()
+
+    def OnSetDsn(self, event):
+        """!Input DXF file defined, update list of layer widget"""
+        path = event.GetString()
+        if not path:
+            return 
+        
+        data = list()        
+        ret = RunCommand('v.in.dxf',
+                         quiet = True,
+                         parent = self,
+                         read = True,
+                         flags = 'l',
+                         input = path)
+        if not ret:
+            self.list.LoadData()
+            self.btn_run.Enable(False)
+            return
+            
+        for line in ret.splitlines():
+            layerId = line.split(':')[0].split(' ')[1]
+            layerName = line.split(':')[1].strip()
+            grassName = GetValidLayerName(layerName)
+            data.append((layerId, layerName.strip(), grassName.strip()))
+        
+        self.list.LoadData(data)
+        if len(data) > 0:
+            self.btn_run.Enable(True)
+        else:
+            self.btn_run.Enable(False)
+
+    def OnCmdDialog(self, event):
+        """!Show command dialog"""
+        GUI(parent = self, modal = True).ParseCommand(cmd = ['v.in.dxf'])
+                
+class LayersList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,
+                 listmix.CheckListCtrlMixin, listmix.TextEditMixin):
+    """!List of layers to be imported (dxf, shp...)"""
+    def __init__(self, parent, columns, log = None):
+        self.parent = parent
+        
+        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
+                             style = wx.LC_REPORT)
+        listmix.CheckListCtrlMixin.__init__(self)
+        self.log = log
+        
+        # setup mixins
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.TextEditMixin.__init__(self)
+        
+        for i in range(len(columns)):
+            self.InsertColumn(i, columns[i])
+        
+        if len(columns) == 3:
+            width = (65, 200)
+        else:
+            width = (65, 180, 110)
+        
+        for i in range(len(width)):
+            self.SetColumnWidth(col = i, width = width[i])
+        
+        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnPopupMenu) #wxMSW
+        self.Bind(wx.EVT_RIGHT_UP,            self.OnPopupMenu) #wxGTK
+
+    def LoadData(self, data = None):
+        """!Load data into list"""
+        if data is None:
+            return
+        
+        self.DeleteAllItems()
+        for item in data:
+            index = self.InsertStringItem(sys.maxint, str(item[0]))
+            for i in range(1, len(item)):
+                self.SetStringItem(index, i, "%s" % str(item[i]))
+        
+        # check by default only on one item
+        if len(data) == 1:
+            self.CheckItem(index, True)
+        
+    def OnPopupMenu(self, event):
+        """!Show popup menu"""
+        if self.GetItemCount() < 1:
+            return
+        
+        if not hasattr(self, "popupDataID1"):
+            self.popupDataID1 = wx.NewId()
+            self.popupDataID2 = wx.NewId()
+            
+            self.Bind(wx.EVT_MENU, self.OnSelectAll,  id = self.popupDataID1)
+            self.Bind(wx.EVT_MENU, self.OnSelectNone, id = self.popupDataID2)
+        
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupDataID1, _("Select all"))
+        menu.Append(self.popupDataID2, _("Deselect all"))
+        
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def OnSelectAll(self, event):
+        """!Select all items"""
+        item = -1
+        
+        while True:
+            item = self.GetNextItem(item)
+            if item == -1:
+                break
+            self.CheckItem(item, True)
+        
+        event.Skip()
+        
+    def OnSelectNone(self, event):
+        """!Deselect items"""
+        item = -1
+        
+        while True:
+            item = self.GetNextItem(item, wx.LIST_STATE_SELECTED)
+            if item == -1:
+                break
+            self.CheckItem(item, False)
+        
+        event.Skip()
+        
+    def OnLeftDown(self, event):
+        """!Allow editing only output name
+        
+        Code taken from TextEditMixin class.
+        """
+        x, y = event.GetPosition()
+        
+        colLocs = [0]
+        loc = 0
+        for n in range(self.GetColumnCount()):
+            loc = loc + self.GetColumnWidth(n)
+            colLocs.append(loc)
+        
+        col = bisect(colLocs, x + self.GetScrollPos(wx.HORIZONTAL)) - 1
+        
+        if col == self.GetColumnCount() - 1:
+            listmix.TextEditMixin.OnLeftDown(self, event)
+        else:
+            event.Skip()
+        
+    def GetLayers(self):
+        """!Get list of layers (layer name, output name)"""
+        data = []
+        item = -1
+        while True:
+            item = self.GetNextItem(item)
+            if item == -1:
+                break
+            if not self.IsChecked(item):
+                continue
+            # layer / output name
+            data.append((self.GetItem(item, 1).GetText(),
+                         self.GetItem(item, self.GetColumnCount() - 1).GetText()))
+        
+        return data
+
+class SetOpacityDialog(wx.Dialog):
+    """!Set opacity of map layers"""
+    def __init__(self, parent, id = wx.ID_ANY, title = _("Set Map Layer Opacity"),
+                 size = wx.DefaultSize, pos = wx.DefaultPosition,
+                 style = wx.DEFAULT_DIALOG_STYLE, opacity = 100):
+
+        self.parent = parent    # GMFrame
+        self.opacity = opacity  # current opacity
+
+        super(SetOpacityDialog, self).__init__(parent, id = id, pos = pos,
+                                               size = size, style = style, title = title)
+
+        panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.GridBagSizer(vgap = 5, hgap = 5)
+        self.value = wx.Slider(panel, id = wx.ID_ANY, value = self.opacity,
+                               style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
+                                   wx.SL_TOP | wx.SL_LABELS,
+                               minValue = 0, maxValue = 100,
+                               size = (350, -1))
+
+        box.Add(item = self.value,
+                flag = wx.ALIGN_CENTRE, pos = (0, 0), span = (1, 2))
+        box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                   label = _("transparent")),
+                pos = (1, 0))
+        box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                   label = _("opaque")),
+                flag = wx.ALIGN_RIGHT,
+                pos = (1, 1))
+
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+
+        line = wx.StaticLine(parent = panel, id = wx.ID_ANY,
+                             style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+
+        # buttons
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btnOK = wx.Button(parent = panel, id = wx.ID_OK)
+        btnOK.SetDefault()
+        btnsizer.AddButton(btnOK)
+
+        btnCancel = wx.Button(parent = panel, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btnCancel)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+
+        panel.SetSizer(sizer)
+        sizer.Fit(panel)
+
+        self.SetSize(self.GetBestSize())
+
+        self.Layout()
+
+    def GetOpacity(self):
+        """!Button 'OK' pressed"""
+        # return opacity value
+        opacity = float(self.value.GetValue()) / 100
+        return opacity
+
+def GetImageHandlers(image):
+    """!Get list of supported image handlers"""
+    lext = list()
+    ltype = list()
+    for h in image.GetHandlers():
+        lext.append(h.GetExtension())
+        
+    filetype = ''
+    if 'png' in lext:
+        filetype += "PNG file (*.png)|*.png|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
+                       'ext'  : 'png' })
+    filetype +=  "BMP file (*.bmp)|*.bmp|"
+    ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
+                   'ext'  : 'bmp' })
+    if 'gif' in lext:
+        filetype += "GIF file (*.gif)|*.gif|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
+                       'ext'  : 'gif' })
+        
+    if 'jpg' in lext:
+        filetype += "JPG file (*.jpg)|*.jpg|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
+                       'ext'  : 'jpg' })
+
+    if 'pcx' in lext:
+        filetype += "PCX file (*.pcx)|*.pcx|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
+                       'ext'  : 'pcx' })
+        
+    if 'pnm' in lext:
+        filetype += "PNM file (*.pnm)|*.pnm|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
+                       'ext'  : 'pnm' })
+
+    if 'tif' in lext:
+        filetype += "TIF file (*.tif)|*.tif|"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
+                       'ext'  : 'tif' })
+
+    if 'xpm' in lext:
+        filetype += "XPM file (*.xpm)|*.xpm"
+        ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
+                       'ext'  : 'xpm' })
+    
+    return filetype, ltype
+
+class StaticWrapText(wx.StaticText):
+    """!A Static Text field that wraps its text to fit its width,
+    enlarging its height if necessary.
+    """
+    def __init__(self, parent, id = wx.ID_ANY, label = '', *args, **kwds):
+        self.parent        = parent
+        self.originalLabel = label
+        
+        wx.StaticText.__init__(self, parent, id, label = '', *args, **kwds)
+        
+        self.SetLabel(label)
+        self.Bind(wx.EVT_SIZE, self.OnResize)
+    
+    def SetLabel(self, label):
+        self.originalLabel = label
+        self.wrappedSize = None
+        self.OnResize(None)
+
+    def OnResize(self, event):
+        if not getattr(self, "resizing", False):
+            self.resizing = True
+            newSize = wx.Size(self.parent.GetSize().width - 50,
+                              self.GetSize().height)
+            if self.wrappedSize != newSize:
+                wx.StaticText.SetLabel(self, self.originalLabel)
+                self.Wrap(newSize.width)
+                self.wrappedSize = newSize
+                
+                self.SetSize(self.wrappedSize)
+            del self.resizing
+
+class ImageSizeDialog(wx.Dialog):
+    """!Set size for saved graphic file"""
+    def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+        self.parent = parent
+        
+        wx.Dialog.__init__(self, parent, id = id, style = style, title = title, **kwargs)
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                label = ' % s' % _("Image size"))
+        
+        size = self.parent.GetWindow().GetClientSize()
+        self.width = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
+                                 style = wx.SP_ARROW_KEYS)
+        self.width.SetRange(20, 1e6)
+        self.width.SetValue(size.width)
+        wx.CallAfter(self.width.SetFocus)
+        self.height = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
+                                  style = wx.SP_ARROW_KEYS)
+        self.height.SetRange(20, 1e6)
+        self.height.SetValue(size.height)
+        self.template = wx.Choice(parent = self.panel, id = wx.ID_ANY,
+                                  size = (125, -1),
+                                  choices = [ "",
+                                              "640x480",
+                                              "800x600",
+                                              "1024x768",
+                                              "1280x960",
+                                              "1600x1200",
+                                              "1920x1440" ])
+        
+        self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
+        self.btnOK.SetDefault()
+        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        
+        self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
+        
+        self._layout()
+        self.SetSize(self.GetBestSize())
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # body
+        box = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
+        fbox = wx.FlexGridSizer(cols = 2, vgap = 5, hgap = 5)
+        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                      label = _("Width:")),
+                 flag = wx.ALIGN_CENTER_VERTICAL)
+        fbox.Add(item = self.width)
+        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                      label = _("Height:")),
+                 flag = wx.ALIGN_CENTER_VERTICAL)
+        fbox.Add(item = self.height)
+        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                      label = _("Template:")),
+                 flag = wx.ALIGN_CENTER_VERTICAL)
+        fbox.Add(item = self.template)
+        
+        box.Add(item = fbox, proportion = 1,
+                flag = wx.EXPAND | wx.ALL, border = 5)
+        sizer.Add(item = box, proportion = 1,
+                  flag=wx.EXPAND | wx.ALL, border = 3)
+        
+        # buttons
+        btnsizer = wx.StdDialogButtonSizer()
+        btnsizer.AddButton(self.btnOK)
+        btnsizer.AddButton(self.btnCancel)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
+        
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        self.Layout()
+    
+    def GetValues(self):
+        """!Get width/height values"""
+        return self.width.GetValue(), self.height.GetValue()
+    
+    def OnTemplate(self, event):
+        """!Template selected"""
+        sel = event.GetString()
+        if not sel:
+            width, height = self.parent.GetWindow().GetClientSize()
+        else:
+            width, height = map(int, sel.split('x'))
+        self.width.SetValue(width)
+        self.height.SetValue(height)
+        
+class SqlQueryFrame(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _("GRASS GIS SQL Query Utility"),
+                 *kwargs):
+        """!SQL Query Utility window
+        """
+        self.parent = parent
+
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, *kwargs)
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.sqlBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                   label = _(" SQL statement "))
+        self.sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+                               style = wx.TE_MULTILINE)
+        
+        self.btnApply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
+        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, self.btnCancel)
+        
+        self._layout()
+
+        self.SetMinSize(wx.Size(300, 150))
+        self.SetSize(wx.Size(500, 200))
+        
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.HORIZONTAL)
+        sqlSizer.Add(item = self.sql, proportion = 1,
+                     flag = wx.EXPAND)
+
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(self.btnApply)
+        btnSizer.AddButton(self.btnCancel)
+        btnSizer.Realize()
+        
+        sizer.Add(item = sqlSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.ALL, border = 5) 
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+       
+        self.panel.SetSizer(sizer)
+        
+        self.Layout()
+
+    def OnCloseWindow(self, event):
+        """!Close window
+        """
+        self.Close()

Copied: grass/trunk/gui/wxpython/gui_core/forms.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/menuform.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/forms.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2268 @@
+"""
+ at package gui_core.forms
+
+ at brief Construct simple wxPython GUI from a GRASS command interface
+description.
+
+Classes:
+ - helpPanel
+ - mainFrame
+ - cmdPanel
+ - GrassGUIApp
+ - GUI
+ - FloatValidator
+ - GNotebook
+
+This program is just a coarse approach to automatically build a GUI
+from a xml-based GRASS user interface description.
+
+You need to have Python 2.4, wxPython 2.8 and python-xml.
+
+The XML stream is read from executing the command given in the
+command line, thus you may call it for instance this way:
+
+python <this file.py> r.basins.fill
+
+Or you set an alias or wrap the call up in a nice shell script, GUI
+environment ... please contribute your idea.
+
+Updated to wxPython 2.8 syntax and contrib widgets.  Methods added to
+make it callable by gui.  Method added to automatically re-run with
+pythonw on a Mac.
+
+ at todo
+ - verify option value types
+
+Copyright(C) 2000-2011 by the GRASS Development Team
+This program is free software under the GPL(>=v2) Read the file
+COPYING coming with GRASS for details.
+
+ at author Jan-Oliver Wagner <jan at intevation.de>
+ at author Bernhard Reiter <bernhard at intevation.de>
+ at author Michael Barton, Arizona State University
+ at author Daniel Calvelo <dca.gis at gmail.com>
+ at author Martin Landa <landa.martin at gmail.com>
+ at author Luca Delucchi <lucadeluge at gmail.com>
+"""
+
+import sys
+import re
+import string
+import textwrap
+import os
+import time
+import copy
+import locale
+from threading import Thread
+import Queue
+
+from core import globalvar
+import wx
+try:
+    import wx.lib.agw.flatnotebook as FN
+except ImportError:
+    import wx.lib.flatnotebook as FN
+import wx.lib.colourselect     as csel
+import wx.lib.filebrowsebutton as filebrowse
+import wx.lib.scrolledpanel    as scrolled
+from wx.lib.expando  import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
+from wx.lib.newevent import NewEvent
+
+try:
+    import xml.etree.ElementTree as etree
+except ImportError:
+    import elementtree.ElementTree as etree # Python <= 2.4
+
+from gui_core.dialogs import StaticWrapText
+from gui_core.ghelp   import HelpPanel
+
+gisbase = os.getenv("GISBASE")
+if gisbase is None:
+    print >>sys.stderr, "We don't seem to be properly installed, or we are being run outside GRASS. Expect glitches."
+    gisbase = os.path.join(os.path.dirname(sys.argv[0]), os.path.pardir)
+    wxbase = gisbase
+else:
+    wxbase = os.path.join(globalvar.ETCWXDIR)
+
+sys.path.append(wxbase)
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+from gui_core import gselect
+from core import cmd as gcmd
+from gui_core import goutput
+from core import utils
+from core.settings import UserSettings
+try:
+    import subprocess
+except:
+    from compat import subprocess
+
+wxUpdateDialog, EVT_DIALOG_UPDATE = NewEvent()
+
+# From lib/gis/col_str.c, except purple which is mentioned
+# there but not given RGB values
+str2rgb = {'aqua': (100, 128, 255),
+           'black': (0, 0, 0),
+           'blue': (0, 0, 255),
+           'brown': (180, 77, 25),
+           'cyan': (0, 255, 255),
+           'gray': (128, 128, 128),
+           'green': (0, 255, 0),
+           'grey': (128, 128, 128),
+           'indigo': (0, 128, 255),
+           'magenta': (255, 0, 255),
+           'orange': (255, 128, 0),
+           'purple': (128, 0, 128),
+           'red': (255, 0, 0),
+           'violet': (128, 0, 255),
+           'white': (255, 255, 255),
+           'yellow': (255, 255, 0)}
+rgb2str = {}
+for (s,r) in str2rgb.items():
+    rgb2str[ r ] = s
+
+"""!Hide some options in the GUI"""
+#_blackList = { 'enabled' : False,
+#               'items'   : { 'r.buffer' : {'params' : ['input', 'output'],
+#                                           'flags' : ['z', 'overwrite']}}}
+_blackList = { 'enabled' : False,
+               'items'   : {} }
+
+def color_resolve(color):
+    if len(color) > 0 and color[0] in "0123456789":
+        rgb = tuple(map(int, color.split(':')))
+        label = color
+    else:
+        # Convert color names to RGB
+        try:
+            rgb = str2rgb[color]
+            label = color
+        except KeyError:
+            rgb = (200, 200, 200)
+            label = _('Select Color')
+    return (rgb, label)
+
+def text_beautify(someString , width = 70):
+    """!Make really long texts shorter, clean up whitespace and remove
+    trailing punctuation.
+    """
+    if width > 0:
+        return escape_ampersand(string.strip(
+                os.linesep.join(textwrap.wrap(utils.normalize_whitespace(someString), width)),
+                ".,;:"))
+    else:
+        return escape_ampersand(string.strip(utils.normalize_whitespace(someString), ".,;:"))
+    
+def escape_ampersand(text):
+    """!Escapes ampersands with additional ampersand for GUI"""
+    return string.replace(text, "&", "&&")
+
+class UpdateThread(Thread):
+    """!Update dialog widgets in the thread"""
+    def __init__(self, parent, event, eventId, task):
+        Thread.__init__(self)
+        
+        self.parent = parent
+        self.event = event
+        self.eventId = eventId
+        self.task = task
+        self.setDaemon(True)
+        
+        # list of functions which updates the dialog
+        self.data = {}
+        
+    def run(self):
+        # get widget id
+        if not self.eventId:
+            for p in self.task.params:
+                if p.get('gisprompt', False) == False:
+                    continue
+                prompt = p.get('element', '')
+                if prompt == 'vector':
+                    name = p.get('name', '')
+                    if name in ('map', 'input'):
+                        self.eventId = p['wxId'][0]
+            if self.eventId is None:
+                return
+        
+        p = self.task.get_param(self.eventId, element = 'wxId', raiseError = False)
+        if not p or 'wxId-bind' not in p:
+            return
+        
+        # get widget prompt
+        pType = p.get('prompt', '')
+        if not pType:
+            return
+        
+        # check for map/input parameter
+        pMap = self.task.get_param('map', raiseError = False)
+        
+        if not pMap:
+            pMap = self.task.get_param('input', raiseError = False)
+        
+        if pMap:
+            map = pMap.get('value', '')
+        else:
+            map = None
+        
+        # avoid running db.describe several times
+        cparams = dict()
+        cparams[map] = { 'dbInfo' : None,
+                         'layers' : None, }
+        
+        # update reference widgets
+        for uid in p['wxId-bind']:
+            win = self.parent.FindWindowById(uid)
+            if not win:
+                continue
+            
+            name = win.GetName()
+            
+            map = layer = None
+            driver = db = table = None
+            if name in ('LayerSelect', 'ColumnSelect'):
+                if p.get('element', '') == 'vector': # -> vector
+                    # get map name
+                    map = p.get('value', '')
+                    
+                    # get layer
+                    for bid in p['wxId-bind']:
+                        p = self.task.get_param(bid, element = 'wxId', raiseError = False)
+                        if not p:
+                            continue
+                        
+                        if p.get('element', '') == 'layer':
+                            layer = p.get('value', '')
+                            if layer != '':
+                                layer = p.get('value', '')
+                            else:
+                                layer = p.get('default', '')
+                            break
+                        
+                elif p.get('element', '') == 'layer': # -> layer
+                    # get layer
+                    layer = p.get('value', '')
+                    if layer != '':
+                        layer = p.get('value', '')
+                    else:
+                        layer = p.get('default', '')
+                    
+                    # get map name
+                    pMapL = self.task.get_param(p['wxId'][0], element = 'wxId-bind', raiseError = False)
+                    if pMapL:
+                        map = pMapL.get('value', '')
+            
+            if name == 'TableSelect' or \
+                    (name == 'ColumnSelect' and not map):
+                pDriver = self.task.get_param('dbdriver', element = 'prompt', raiseError = False)
+                if pDriver:
+                    driver = pDriver.get('value', '')
+                pDb = self.task.get_param('dbname', element = 'prompt', raiseError = False)
+                if pDb:
+                    db = pDb.get('value', '')
+                if name == 'ColumnSelect':
+                    pTable = self.task.get_param('dbtable', element = 'element', raiseError = False)
+                    if pTable:
+                        table = pTable.get('value', '')
+
+            if name == 'LayerSelect':
+                # determine format
+                native = True
+                
+                for id in pMap['wxId']:
+                    winVec  = self.parent.FindWindowById(id)
+                    if winVec.GetName() == 'VectorFormat' and \
+                            winVec.GetSelection() != 0:
+                        native = False
+                        break
+                # TODO: update only if needed
+                if native:
+                    if map:
+                        self.data[win.InsertLayers] = { 'vector' : map }
+                    else:
+                        self.data[win.InsertLayers] = { }
+                else:
+                    if map:
+                        self.data[win.InsertLayers] = { 'dsn' : map.rstrip('@OGR') }
+                    else:
+                        self.data[win.InsertLayers] = { }
+            
+            elif name == 'TableSelect':
+                self.data[win.InsertTables] = { 'driver' : driver,
+                                                'database' : db }
+                
+            elif name == 'ColumnSelect':
+                if map:
+                    if map in cparams:
+                        if not cparams[map]['dbInfo']:
+                            cparams[map]['dbInfo'] = gselect.VectorDBInfo(map)
+                        self.data[win.InsertColumns] = { 'vector' : map, 'layer' : layer,
+                                                         'dbInfo' : cparams[map]['dbInfo'] }
+                else: # table
+                    if driver and db:
+                        self.data[win.InsertTableColumns] = { 'table' : pTable.get('value'),
+                                                              'driver' : driver,
+                                                              'database' : db }
+                    elif pTable:
+                        self.data[win.InsertTableColumns] = { 'table'  : pTable.get('value') }
+            
+            elif name == 'SubGroupSelect':
+                pGroup = self.task.get_param('group', element = 'element', raiseError = False)
+                if pGroup:
+                    self.data[win.Insert] = { 'group' : pGroup.get('value', '')}
+            
+            elif name == 'LocationSelect':
+                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
+                if pDbase:
+                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', '')}
+
+            elif name == 'MapsetSelect':
+                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
+                pLocation = self.task.get_param('location', element = 'element', raiseError = False)
+                if pDbase and pLocation:
+                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', ''),
+                                                   'location' : pLocation.get('value', '')}
+
+            elif name ==  'ProjSelect':
+                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
+                pLocation = self.task.get_param('location', element = 'element', raiseError = False)
+                pMapset = self.task.get_param('mapset', element = 'element', raiseError = False)
+                if pDbase and pLocation and pMapset:
+                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', ''),
+                                                   'location' : pLocation.get('value', ''),
+                                                   'mapset' : pMapset.get('value', '')}
+            
+def UpdateDialog(parent, event, eventId, task):
+    return UpdateThread(parent, event, eventId, task)
+
+class UpdateQThread(Thread):
+    """!Update dialog widgets in the thread"""
+    requestId = 0
+    def __init__(self, parent, requestQ, resultQ, **kwds):
+        Thread.__init__(self, **kwds)
+        
+        self.parent = parent # cmdPanel
+        self.setDaemon(True)
+        
+        self.requestQ = requestQ
+        self.resultQ = resultQ
+        
+        self.start()
+        
+    def Update(self, callable, *args, **kwds):
+        UpdateQThread.requestId +=  1
+        
+        self.request = None
+        self.requestQ.put((UpdateQThread.requestId, callable, args, kwds))
+        
+        return UpdateQThread.requestId
+    
+    def run(self):
+        while True:
+            requestId, callable, args, kwds = self.requestQ.get()
+            
+            requestTime = time.time()
+            
+            self.request = callable(*args, **kwds)
+
+            self.resultQ.put((requestId, self.request.run()))
+           
+            if self.request:
+                event = wxUpdateDialog(data = self.request.data)
+                wx.PostEvent(self.parent, event)
+
+class mainFrame(wx.Frame):
+    """!This is the Frame containing the dialog for options input.
+
+    The dialog is organized in a notebook according to the guisections
+    defined by each GRASS command.
+
+    If run with a parent, it may Apply, Ok or Cancel; the latter two
+    close the dialog.  The former two trigger a callback.
+
+    If run standalone, it will allow execution of the command.
+
+    The command is checked and sent to the clipboard when clicking
+    'Copy'.
+    """
+    def __init__(self, parent, ID, task_description,
+                 get_dcmd = None, layer = None):
+        self.get_dcmd = get_dcmd
+        self.layer    = layer
+        self.task     = task_description
+        self.parent   = parent            # LayerTree | Modeler | None | ...
+        if parent and parent.GetName() ==  'Modeler':
+            self.modeler = self.parent
+        else:
+            self.modeler = None
+        
+        # module name + keywords
+        if self.task.name.split('.')[-1] in ('py', 'sh'):
+            title = str(self.task.name.rsplit('.',1)[0])
+        else:
+            title = self.task.name
+        try:
+            if self.task.keywords !=  ['']:
+                title +=   " [" + ', '.join(self.task.keywords) + "]"
+        except ValueError:
+            pass
+        
+        wx.Frame.__init__(self, parent = parent, id = ID, title = title,
+                          pos = wx.DefaultPosition, style = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL,
+                          name = "MainFrame")
+        
+        self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        # statusbar
+        self.CreateStatusBar()
+        
+        # icon
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_dialog.ico'), wx.BITMAP_TYPE_ICO))
+        
+        guisizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # set apropriate output window
+        if self.parent:
+            self.standalone = False
+        else:
+            self.standalone = True
+        
+        # logo + description
+        topsizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        # GRASS logo
+        self.logo = wx.StaticBitmap(parent = self.panel,
+                                    bitmap = wx.Bitmap(name = os.path.join(globalvar.ETCIMGDIR,
+                                                                           'grass_form.png'),
+                                                     type = wx.BITMAP_TYPE_PNG))
+        topsizer.Add(item = self.logo, proportion = 0, border = 3,
+                     flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL)
+        
+        # add module description
+        if self.task.label:
+            module_desc = self.task.label + ' ' + self.task.description
+        else:
+            module_desc = self.task.description
+        self.description = StaticWrapText(parent = self.panel,
+                                          label = module_desc)
+        topsizer.Add(item = self.description, proportion = 1, border = 5,
+                     flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+        
+        guisizer.Add(item = topsizer, proportion = 0, flag = wx.EXPAND)
+        
+        self.panel.SetSizerAndFit(guisizer)
+        self.Layout()
+        
+        # notebooks
+        self.notebookpanel = cmdPanel(parent = self.panel, task = self.task,
+                                      mainFrame = self)
+        self.goutput = self.notebookpanel.goutput
+        self.notebookpanel.OnUpdateValues = self.updateValuesHook
+        guisizer.Add(item = self.notebookpanel, proportion = 1, flag = wx.EXPAND)
+        
+        # status bar
+        status_text = _("Enter parameters for '") + self.task.name + "'"
+        try:
+            self.task.get_cmd()
+            self.updateValuesHook()
+        except ValueError:
+            self.SetStatusText(status_text)
+        
+        # buttons
+        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+        # cancel
+        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+        self.btn_cancel.SetToolTipString(_("Close this window without executing the command (Ctrl+Q)"))
+        btnsizer.Add(item = self.btn_cancel, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10)
+        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+
+        if self.get_dcmd is not None: # A callback has been set up
+            btn_apply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
+            btn_ok = wx.Button(parent = self.panel, id = wx.ID_OK)
+            btn_ok.SetDefault()
+
+            btnsizer.Add(item = btn_apply, proportion = 0,
+                         flag = wx.ALL | wx.ALIGN_CENTER,
+                         border = 10)
+            btnsizer.Add(item = btn_ok, proportion = 0,
+                         flag = wx.ALL | wx.ALIGN_CENTER,
+                         border = 10)
+            
+            btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
+            btn_ok.Bind(wx.EVT_BUTTON, self.OnOK)
+        else: # We're standalone
+            # run
+            self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label =  _("&Run"))
+            self.btn_run.SetToolTipString(_("Run the command (Ctrl+R)"))
+            self.btn_run.SetDefault()
+            self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
+            
+            # copy
+            self.btn_clipboard = wx.Button(parent = self.panel, id = wx.ID_COPY)
+            self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
+            
+            btnsizer.Add(item = self.btn_run, proportion = 0,
+                         flag = wx.ALL | wx.ALIGN_CENTER,
+                         border = 10)
+            
+            btnsizer.Add(item = self.btn_clipboard, proportion = 0,
+                         flag = wx.ALL | wx.ALIGN_CENTER,
+                         border = 10)
+            
+            self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
+            self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
+        # help
+        self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
+        self.btn_help.SetToolTipString(_("Show manual page of the command (Ctrl+H)"))
+        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
+        if self.notebookpanel.notebook.GetPageIndexByName('manual') < 0:
+            self.btn_help.Hide()
+        
+        # add help button
+        btnsizer.Add(item = self.btn_help, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10)
+        
+        guisizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT,
+                     border = 30)
+        
+        if self.parent and not self.modeler:
+            addLayer = False
+            for p in self.task.params:
+                if p.get('age', 'old') ==  'new' and \
+                   p.get('prompt', '') in ('raster', 'vector', '3d-raster'):
+                    addLayer = True
+            
+            if addLayer:
+                # add newly created map into layer tree
+                self.addbox = wx.CheckBox(parent = self.panel,
+                                          label = _('Add created map(s) into layer tree'), style = wx.NO_BORDER)
+                self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
+                guisizer.Add(item = self.addbox, proportion = 0,
+                             flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                             border = 5)
+        
+        hasNew = False
+        for p in self.task.params:
+            if p.get('age', 'old') ==  'new':
+                hasNew = True
+                break
+        
+        if self.get_dcmd is None and hasNew:
+            # close dialog when command is terminated
+            self.closebox = wx.CheckBox(parent = self.panel,
+                                        label = _('Close dialog on finish'), style = wx.NO_BORDER)
+            self.closebox.SetValue(UserSettings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
+            self.closebox.SetToolTipString(_("Close dialog when command is successfully finished. "
+                                             "Change this settings in Preferences dialog ('Command' tab)."))
+            guisizer.Add(item = self.closebox, proportion = 0,
+                         flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                         border = 5)
+        
+        self.Bind(wx.EVT_CLOSE,  self.OnCancel)
+        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        
+        # do layout
+        # called automatically by SetSizer()
+        self.panel.SetAutoLayout(True) 
+        self.panel.SetSizerAndFit(guisizer)
+        
+        sizeFrame = self.GetBestSize()
+        self.SetMinSize(sizeFrame)
+        
+        if hasattr(self, "closebox"):
+            scale = 0.33
+        else:
+            scale = 0.50
+        self.SetSize(wx.Size(sizeFrame[0], sizeFrame[1] + scale * max(self.notebookpanel.panelMinHeight,
+                                                                      self.notebookpanel.constrained_size[1])))
+        
+        # thread to update dialog
+        # create queues
+        self.requestQ = Queue.Queue()
+        self.resultQ = Queue.Queue()
+        self.updateThread = UpdateQThread(self.notebookpanel, self.requestQ, self.resultQ)
+        
+        self.Layout()
+        
+        # keep initial window size limited for small screens
+        width, height = self.GetSizeTuple()
+        self.SetSize(wx.Size(min(width, 650),
+                             min(height, 500)))
+        
+        # fix goutput's pane size (required for Mac OSX)
+        if self.goutput:  	 	 
+            self.goutput.SetSashPosition(int(self.GetSize()[1] * .75))
+        
+    def updateValuesHook(self, event = None):
+        """!Update status bar data"""
+        self.SetStatusText(' '.join(self.notebookpanel.createCmd(ignoreErrors = True)))
+        if event:
+            event.Skip()
+        
+    def OnKeyUp(self, event):
+        """!Key released (check hot-keys)"""
+        try:
+            kc = chr(event.GetKeyCode())
+        except ValueError:
+            event.Skip()
+            return
+        
+        if not event.ControlDown():
+            event.Skip()
+            return
+        
+        if kc ==  'Q':
+            self.OnCancel(None)
+        elif kc ==  'S':
+            self.OnAbort(None)
+        elif kc ==  'H':
+            self.OnHelp(None)
+        elif kc ==  'R':
+            self.OnRun(None)
+        elif kc ==  'C':
+            self.OnCopy(None)
+        
+        event.Skip()
+
+    def OnDone(self, cmd, returncode):
+        """!This function is launched from OnRun() when command is
+        finished
+
+        @param returncode command's return code (0 for success)
+        """
+        if not self.parent or returncode !=  0:
+            return
+        if self.parent.GetName() not in ('LayerTree', 'LayerManager'):
+            return
+        
+        if self.parent.GetName() ==  'LayerTree':
+            display = self.parent.GetMapDisplay()
+        else: # Layer Manager
+            display = self.parent.GetLayerTree().GetMapDisplay()
+            
+        if not display or not display.IsAutoRendered():
+            return
+        
+        mapLayers = map(lambda x: x.GetName(),
+                        display.GetMap().GetListOfLayers(l_type = 'raster') +
+                        display.GetMap().GetListOfLayers(l_type = 'vector'))
+        
+        task = GUI(show = None).ParseCommand(cmd)
+        for p in task.get_options()['params']:
+            if p.get('prompt', '') not in ('raster', 'vector'):
+                continue
+            mapName = p.get('value', '')
+            if '@' not in mapName:
+                mapName = mapName + '@' + grass.gisenv()['MAPSET']
+            if mapName in mapLayers:
+                display.GetWindow().UpdateMap(render = True)
+                return
+        
+    def OnOK(self, event):
+        """!OK button pressed"""
+        cmd = self.OnApply(event)
+        if cmd is not None and self.get_dcmd is not None:
+            self.OnCancel(event)
+
+    def OnApply(self, event):
+        """!Apply the command"""
+        if self.modeler:
+            cmd = self.createCmd(ignoreErrors = True, ignoreRequired = True)
+        else:
+            cmd = self.createCmd()
+        
+        if cmd is not None and self.get_dcmd is not None:
+            # return d.* command to layer tree for rendering
+            self.get_dcmd(cmd, self.layer, {"params": self.task.params, 
+                                            "flags" : self.task.flags},
+                          self)
+            # echo d.* command to output console
+            # self.parent.writeDCommand(cmd)
+
+        return cmd
+
+    def OnRun(self, event):
+        """!Run the command"""
+        cmd = self.createCmd()
+        
+        if not cmd or len(cmd) < 1:
+            return
+        
+        ret = 0
+        if self.standalone or cmd[0][0:2] !=  "d.":
+            # Send any non-display command to parent window (probably wxgui.py)
+            # put to parents switch to 'Command output'
+            self.notebookpanel.notebook.SetSelectionByName('output')
+            
+            try:
+                if self.task.path:
+                    cmd[0] = self.task.path # full path
+                
+                ret = self.goutput.RunCmd(cmd, onDone = self.OnDone)
+            except AttributeError, e:
+                print >> sys.stderr, "%s: Probably not running in wxgui.py session?" % (e)
+                print >> sys.stderr, "parent window is: %s" % (str(self.parent))
+        else:
+            gcmd.Command(cmd)
+        
+        if ret != 0:
+            self.notebookpanel.notebook.SetSelection(0)
+            return
+        
+        # update buttons status
+        for btn in (self.btn_run,
+                    self.btn_cancel,
+                    self.btn_clipboard,
+                    self.btn_help):
+            btn.Enable(False)
+        
+    def OnAbort(self, event):
+        """!Abort running command"""
+        event = goutput.wxCmdAbort(aborted = True)
+        wx.PostEvent(self.goutput, event)
+
+    def OnCopy(self, event):
+        """!Copy the command"""
+        cmddata = wx.TextDataObject()
+        # list -> string
+        cmdstring = ' '.join(self.createCmd(ignoreErrors = True))
+        cmddata.SetText(cmdstring)
+        if wx.TheClipboard.Open():
+#            wx.TheClipboard.UsePrimarySelection(True)
+            wx.TheClipboard.SetData(cmddata)
+            wx.TheClipboard.Close()
+            self.SetStatusText(_("'%s' copied to clipboard") % \
+                                    (cmdstring))
+
+    def OnCancel(self, event):
+        """!Cancel button pressed"""
+        self.MakeModal(False)
+        
+        if self.get_dcmd and \
+                self.parent and \
+                self.parent.GetName() in ('LayerTree',
+                                          'MapWindow'):
+            # display decorations and 
+            # pressing OK or cancel after setting layer properties
+            if self.task.name in ['d.barscale','d.legend','d.histogram'] \
+                or len(self.parent.GetPyData(self.layer)[0]['cmd']) >=  1:
+                self.Hide()
+            # canceled layer with nothing set
+            elif len(self.parent.GetPyData(self.layer)[0]['cmd']) < 1:
+                self.parent.Delete(self.layer)
+                self.Destroy()
+        else:
+            # cancel for non-display commands
+            self.Destroy()
+
+    def OnHelp(self, event):
+        """!Show manual page (switch to the 'Manual' notebook page)"""
+        if self.notebookpanel.notebook.GetPageIndexByName('manual') > -1:
+            self.notebookpanel.notebook.SetSelectionByName('manual')
+            self.notebookpanel.OnPageChange(None)
+        
+        if event:    
+            event.Skip()
+        
+    def createCmd(self, ignoreErrors = False, ignoreRequired = False):
+        """!Create command string (python list)"""
+        return self.notebookpanel.createCmd(ignoreErrors = ignoreErrors,
+                                            ignoreRequired = ignoreRequired)
+
+class cmdPanel(wx.Panel):
+    """!A panel containing a notebook dividing in tabs the different
+    guisections of the GRASS cmd.
+    """
+    def __init__(self, parent, task, id = wx.ID_ANY, mainFrame = None, *args, **kwargs):
+        if mainFrame:
+            self.parent = mainFrame
+        else:
+            self.parent = parent
+        self.task = task
+        
+        wx.Panel.__init__(self, parent, id = id, *args, **kwargs)
+        
+        # Determine tab layout
+        sections = []
+        is_section = {}
+        not_hidden = [ p for p in self.task.params + self.task.flags if not p.get('hidden', False) ==  True ]
+
+        self.label_id = [] # wrap titles on resize
+
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+        for task in not_hidden:
+            if task.get('required', False):
+                # All required go into Main, even if they had defined another guisection
+                task['guisection'] = _('Required')
+            if task.get('guisection','') ==  '':
+                # Undefined guisections end up into Options
+                task['guisection'] = _('Optional')
+            if task['guisection'] not in is_section:
+                # We do it like this to keep the original order, except for Main which goes first
+                is_section[task['guisection']] = 1
+                sections.append(task['guisection'])
+            else:
+                is_section[ task['guisection'] ] +=  1
+        del is_section
+
+        # 'Required' tab goes first, 'Optional' as the last one
+        for (newidx,content) in [ (0,_('Required')), (len(sections)-1,_('Optional')) ]:
+            if content in sections:
+                idx = sections.index(content)
+                sections[idx:idx+1] = []
+                sections[newidx:newidx] =  [content]
+
+        panelsizer = wx.BoxSizer(orient = wx.VERTICAL)
+
+        # Build notebook
+        self.notebook = GNotebook(self, style = globalvar.FNPageStyle)
+        self.notebook.SetTabAreaColour(globalvar.FNPageColor)
+        self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChange)
+
+        tab = {}
+        tabsizer = {}
+        for section in sections:
+            tab[section] = scrolled.ScrolledPanel(parent = self.notebook)
+            tab[section].SetScrollRate(10, 10)
+            tabsizer[section] = wx.BoxSizer(orient = wx.VERTICAL)
+            self.notebook.AddPage(page = tab[section], text = section)
+
+        # are we running from command line?
+        ### add 'command output' tab regardless standalone dialog
+        if self.parent.GetName() ==  "MainFrame" and self.parent.get_dcmd is None:
+            self.goutput = goutput.GMConsole(parent = self, margin = False)
+            self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
+        else:
+            self.goutput = None
+        
+        self.manual_tab = HelpPanel(parent = self, grass_command = self.task.name)
+        if not self.manual_tab.IsFile():
+            self.manual_tab.Hide()
+        else:
+            self.notebook.AddPage(page = self.manual_tab, text = _("Manual"), name = 'manual')
+        
+        self.notebook.SetSelection(0)
+
+        panelsizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND)
+
+        #
+        # flags
+        #
+        text_style = wx.FONTWEIGHT_NORMAL
+        visible_flags = [ f for f in self.task.flags if not f.get('hidden', False) ==  True ]
+        for f in visible_flags:
+            which_sizer = tabsizer[ f['guisection'] ]
+            which_panel = tab[ f['guisection'] ]
+            # if label is given: description -> tooltip
+            if f.get('label','') !=  '':
+                title = text_beautify(f['label'])
+                tooltip = text_beautify(f['description'], width = -1)
+            else:
+                title = text_beautify(f['description'])
+                tooltip = None
+            title_sizer = wx.BoxSizer(wx.HORIZONTAL)
+            rtitle_txt = wx.StaticText(parent = which_panel,
+                                       label = '(' + f['name'] + ')')
+            chk = wx.CheckBox(parent = which_panel, label = title, style = wx.NO_BORDER)
+            self.label_id.append(chk.GetId())
+            if tooltip:
+                chk.SetToolTipString(tooltip)
+            chk.SetValue(f.get('value', False))
+            title_sizer.Add(item = chk, proportion = 1,
+                            flag = wx.EXPAND)
+            title_sizer.Add(item = rtitle_txt, proportion = 0,
+                            flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
+            which_sizer.Add(item = title_sizer, proportion = 0,
+                            flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
+            f['wxId'] = [ chk.GetId(), ]
+            chk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
+            
+            if self.parent.GetName() ==  'MainFrame' and self.parent.modeler:
+                parChk = wx.CheckBox(parent = which_panel, id = wx.ID_ANY,
+                                     label = _("Parameterized in model"))
+                parChk.SetName('ModelParam')
+                parChk.SetValue(f.get('parameterized', False))
+                if 'wxId' in f:
+                    f['wxId'].append(parChk.GetId())
+                else:
+                    f['wxId'] = [ parChk.GetId() ]
+                parChk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
+                which_sizer.Add(item = parChk, proportion = 0,
+                                flag = wx.LEFT, border = 20)
+            
+            if f['name'] in ('verbose', 'quiet'):
+                chk.Bind(wx.EVT_CHECKBOX, self.OnVerbosity)
+                vq = UserSettings.Get(group = 'cmd', key = 'verbosity', subkey = 'selection')
+                if f['name'] ==  vq:
+                    chk.SetValue(True)
+                    f['value'] = True
+            elif f['name'] ==  'overwrite' and 'value' not in f:
+                chk.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
+                f['value'] = UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled')
+                
+        #
+        # parameters
+        #
+        visible_params = [ p for p in self.task.params if not p.get('hidden', False) ==  True ]
+        
+        try:
+            first_param = visible_params[0]
+        except IndexError:
+            first_param = None
+        
+        for p in visible_params:
+            which_sizer = tabsizer[ p['guisection'] ]
+            which_panel = tab[ p['guisection'] ]
+            # if label is given -> label and description -> tooltip
+            # otherwise description -> lavel
+            if p.get('label','') !=  '':
+                title = text_beautify(p['label'])
+                tooltip = text_beautify(p['description'], width = -1)
+            else:
+                title = text_beautify(p['description'])
+                tooltip = None
+            txt = None
+
+            # text style (required -> bold)
+            if not p.get('required', False):
+                text_style = wx.FONTWEIGHT_NORMAL
+            else:
+                text_style = wx.FONTWEIGHT_BOLD
+
+            # title sizer (description, name, type)
+            if (len(p.get('values', [])) > 0) and \
+                    p.get('multiple', False) and \
+                    p.get('gisprompt',False) ==  False and \
+                    p.get('type', '') ==  'string':
+                title_txt = wx.StaticBox(parent = which_panel, id = wx.ID_ANY)
+            else:
+                title_sizer = wx.BoxSizer(wx.HORIZONTAL)
+                title_txt = wx.StaticText(parent = which_panel)
+                if p['key_desc']:
+                    ltype = ','.join(p['key_desc'])
+                else:
+                    ltype = p['type']
+                rtitle_txt = wx.StaticText(parent = which_panel,
+                                           label = '(' + p['name'] + '=' + ltype + ')')
+                title_sizer.Add(item = title_txt, proportion = 1,
+                                flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
+                title_sizer.Add(item = rtitle_txt, proportion = 0,
+                                flag = wx.ALIGN_RIGHT | wx.RIGHT | wx.TOP, border = 5)
+                which_sizer.Add(item = title_sizer, proportion = 0,
+                                flag = wx.EXPAND)
+            self.label_id.append(title_txt.GetId())
+
+            # title expansion
+            if p.get('multiple', False) and len(p.get('values','')) ==  0:
+                title = _("[multiple]") + " " + title
+                if p.get('value','') ==   '' :
+                    p['value'] = p.get('default','')
+
+            if (len(p.get('values', [])) > 0):
+                valuelist      = map(str, p.get('values',[]))
+                valuelist_desc = map(unicode, p.get('values_desc',[]))
+
+                if p.get('multiple', False) and \
+                        p.get('gisprompt',False) ==  False and \
+                        p.get('type', '') ==  'string':
+                    title_txt.SetLabel(" %s: (%s, %s) " % (title, p['name'], p['type']))
+                    if valuelist_desc:
+                        hSizer = wx.StaticBoxSizer(box = title_txt, orient = wx.VERTICAL)
+                    else:
+                        hSizer = wx.StaticBoxSizer(box = title_txt, orient = wx.HORIZONTAL)
+                    isEnabled = {}
+                    # copy default values
+                    if p['value'] ==  '':
+                        p['value'] = p.get('default', '')
+                        
+                    for defval in p.get('value', '').split(','):
+                        isEnabled[ defval ] = 'yes'
+                        # for multi checkboxes, this is an array of all wx IDs
+                        # for each individual checkbox
+                        p[ 'wxId' ] = list()
+                    idx = 0
+                    for val in valuelist:
+                        try:
+                            label = valuelist_desc[idx]
+                        except IndexError:
+                            label = val
+                        
+                        chkbox = wx.CheckBox(parent = which_panel,
+                                             label = text_beautify(label))
+                        p[ 'wxId' ].append(chkbox.GetId())
+                        if val in isEnabled:
+                            chkbox.SetValue(True)
+                        hSizer.Add(item = chkbox, proportion = 0,
+                                    flag = wx.ADJUST_MINSIZE | wx.ALL, border = 1)
+                        chkbox.Bind(wx.EVT_CHECKBOX, self.OnCheckBoxMulti)
+                        idx +=  1
+                        
+                    which_sizer.Add(item = hSizer, proportion = 0,
+                                    flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.LEFT, border = 5)
+                elif p.get('gisprompt', False) ==  False:
+                    if len(valuelist) ==  1: # -> textctrl
+                        title_txt.SetLabel("%s (%s %s):" % (title, _('valid range'),
+                                                            str(valuelist[0])))
+                        
+                        if p.get('type', '') ==  'integer' and \
+                                not p.get('multiple', False):
+
+                            # for multiple integers use textctrl instead of spinsctrl
+                            try:
+                                minValue, maxValue = map(int, valuelist[0].split('-'))
+                            except ValueError:
+                                minValue = -1e6
+                                maxValue = 1e6
+                            txt2 = wx.SpinCtrl(parent = which_panel, id = wx.ID_ANY, size = globalvar.DIALOG_SPIN_SIZE,
+                                               min = minValue, max = maxValue)
+                            txt2.SetName("SpinCtrl")
+                            style = wx.BOTTOM | wx.LEFT
+                        else:
+                            txt2 = wx.TextCtrl(parent = which_panel, value = p.get('default',''))
+                            txt2.SetName("TextCtrl")
+                            style = wx.EXPAND | wx.BOTTOM | wx.LEFT
+                        
+                        value = self._getValue(p)
+                        # parameter previously set
+                        if value:
+                            if txt2.GetName() ==  "SpinCtrl":
+                                txt2.SetValue(int(value))
+                            else:
+                                txt2.SetValue(value)
+                        
+                        which_sizer.Add(item = txt2, proportion = 0,
+                                        flag = style, border = 5)
+
+                        p['wxId'] = [ txt2.GetId(), ]
+                        txt2.Bind(wx.EVT_TEXT, self.OnSetValue)
+                    else:
+                        # list of values (combo)
+                        title_txt.SetLabel(title + ':')
+                        cb = wx.ComboBox(parent = which_panel, id = wx.ID_ANY, value = p.get('default',''),
+                                         size = globalvar.DIALOG_COMBOBOX_SIZE,
+                                         choices = valuelist, style = wx.CB_DROPDOWN)
+                        value = self._getValue(p)
+                        if value:
+                            cb.SetValue(value) # parameter previously set
+                        which_sizer.Add(item = cb, proportion = 0,
+                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
+                        p['wxId'] = [cb.GetId(),]
+                        cb.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                        cb.Bind(wx.EVT_TEXT, self.OnSetValue)
+            
+            # text entry
+            if (p.get('type','string') in ('string','integer','float')
+                and len(p.get('values',[])) ==  0
+                and p.get('gisprompt',False) ==  False
+                and p.get('prompt','') !=  'color'):
+
+                title_txt.SetLabel(title + ':')
+                if p.get('multiple', False) or \
+                        p.get('type', 'string') ==  'string' or \
+                        len(p.get('key_desc', [])) > 1:
+                    txt3 = wx.TextCtrl(parent = which_panel, value = p.get('default',''))
+                    
+                    value = self._getValue(p)
+                    if value:
+                        # parameter previously set
+                        txt3.SetValue(str(value))
+                    
+                    txt3.Bind(wx.EVT_TEXT, self.OnSetValue)
+                    style = wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT
+                else:
+                    minValue = -1e9
+                    maxValue = 1e9
+                    if p.get('type', '') ==  'integer':
+                        txt3 = wx.SpinCtrl(parent = which_panel, value = p.get('default',''),
+                                           size = globalvar.DIALOG_SPIN_SIZE,
+                                           min = minValue, max = maxValue)
+                        style = wx.BOTTOM | wx.LEFT | wx.RIGHT
+                        
+                        value = self._getValue(p)
+                        if value:
+                            txt3.SetValue(int(value)) # parameter previously set
+                        
+                        txt3.Bind(wx.EVT_SPINCTRL, self.OnSetValue)
+                    else:
+                        txt3 = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
+                                           validator = FloatValidator())
+                        style = wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT
+                        
+                        value = self._getValue(p)
+                        if value:
+                            txt3.SetValue(str(value)) # parameter previously set
+                    
+                txt3.Bind(wx.EVT_TEXT, self.OnSetValue)
+                
+                which_sizer.Add(item = txt3, proportion = 0,
+                                flag = style, border = 5)
+                p['wxId'] = [ txt3.GetId(), ]
+
+            #
+            # element selection tree combobox (maps, icons, regions, etc.)
+            #
+            if p.get('gisprompt', False) ==  True:
+                title_txt.SetLabel(title + ':')
+                # GIS element entry
+                if p.get('prompt','') not in ('color',
+                                              'color_none',
+                                              'subgroup',
+                                              'dbdriver',
+                                              'dbname',
+                                              'dbtable',
+                                              'dbcolumn',
+                                              'layer',
+                                              'layer_all',
+                                              'location',
+                                              'mapset',
+                                              'dbase') and \
+                                              p.get('element', '') not in ('file', 'dir'):
+                    multiple = p.get('multiple', False)
+                    if p.get('age', '') ==  'new':
+                        mapsets = [grass.gisenv()['MAPSET'],]
+                    else:
+                        mapsets = None
+                    if self.task.name in ('r.proj', 'v.proj') \
+                            and p.get('name', '') ==  'input':
+                        if self.task.name ==  'r.proj':
+                            isRaster = True
+                        else:
+                            isRaster = False
+                        selection = gselect.ProjSelect(parent = which_panel,
+                                                       isRaster = isRaster)
+                        p['wxId'] = [ selection.GetId(), ]
+                        selection.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                        formatSelector = False
+                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                    else:
+                        selection = gselect.Select(parent = which_panel, id = wx.ID_ANY,
+                                                   size = globalvar.DIALOG_GSELECT_SIZE,
+                                                   type = p.get('element', ''),
+                                                   multiple = multiple, mapsets = mapsets,
+                                                   fullyQualified = p.get('age', 'old') == 'old')
+                        
+                        value = self._getValue(p)
+                        if value:
+                            selection.SetValue(value)
+                        
+                        formatSelector = True
+                        # A select.Select is a combobox with two children: a textctl and a popupwindow;
+                        # we target the textctl here
+                        textWin = selection.GetTextCtrl()
+                        p['wxId'] = [ textWin.GetId(), ]
+                        textWin.Bind(wx.EVT_TEXT, self.OnSetValue)
+                    
+                    if p.get('prompt', '') ==  'vector':
+                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                        
+                        # if formatSelector and p.get('age', 'old') ==  'old':
+                        #     # OGR supported (read-only)
+                        #     self.hsizer = wx.BoxSizer(wx.HORIZONTAL)
+                            
+                        #     self.hsizer.Add(item = selection,
+                        #                     flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
+                        #                     border = 5)
+                            
+                        #     # format (native / ogr)
+                        #     rbox = wx.RadioBox(parent = which_panel, id = wx.ID_ANY,
+                        #                        label = " %s " % _("Format"),
+                        #                        style = wx.RA_SPECIFY_ROWS,
+                        #                        choices = [_("Native / Linked OGR"), _("Direct OGR")])
+                        #     if p.get('value', '').lower().rfind('@ogr') > -1:
+                        #         rbox.SetSelection(1)
+                        #     rbox.SetName('VectorFormat')
+                        #     rbox.Bind(wx.EVT_RADIOBOX, self.OnVectorFormat)
+                            
+                        #     self.hsizer.Add(item = rbox,
+                        #                     flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT |
+                        #                     wx.RIGHT | wx.ALIGN_TOP,
+                        #                     border = 5)
+                            
+                        #     ogrSelection = gselect.GdalSelect(parent = self, panel = which_panel, ogr = True,
+                        #                                       default = 'dir',
+                        #                                       exclude = ['file'])
+                        #     self.Bind(gselect.EVT_GDALSELECT, self.OnUpdateSelection)
+                        #     self.Bind(gselect.EVT_GDALSELECT, self.OnSetValue)
+                            
+                        #     ogrSelection.SetName('OgrSelect')
+                        #     ogrSelection.Hide()
+                            
+                        #     which_sizer.Add(item = self.hsizer, proportion = 0)
+                            
+                        #     p['wxId'].append(rbox.GetId())
+                        #     p['wxId'].append(ogrSelection.GetId())
+                        #     for win in ogrSelection.GetDsnWin():
+                        #         p['wxId'].append(win.GetId())
+                        # else:
+                        which_sizer.Add(item = selection, proportion = 0,
+                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
+                                        border = 5)
+                    elif p.get('prompt', '') ==  'group':
+                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                        which_sizer.Add(item = selection, proportion = 0,
+                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
+                                        border = 5)
+                    else:
+                        which_sizer.Add(item = selection, proportion = 0,
+                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
+                                        border = 5)
+                # subgroup
+                elif p.get('prompt', '') ==  'subgroup':
+                    selection = gselect.SubGroupSelect(parent = which_panel)
+                    p['wxId'] = [ selection.GetId() ]
+                    selection.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                    which_sizer.Add(item = selection, proportion = 0,
+                                    flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
+                                    border = 5)
+
+                # layer, dbdriver, dbname, dbcolumn, dbtable entry
+                elif p.get('prompt', '') in ('dbdriver',
+                                             'dbname',
+                                             'dbtable',
+                                             'dbcolumn',
+                                             'layer',
+                                             'layer_all',
+                                             'location',
+                                             'mapset',
+                                             'dbase'):
+                    if p.get('multiple', 'no') ==  'yes':
+                        win = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
+                                          size = globalvar.DIALOG_TEXTCTRL_SIZE)
+                        win.Bind(wx.EVT_TEXT, self.OnSetValue)
+                    else:
+                        value = self._getValue(p)
+                        
+                        if p.get('prompt', '') in ('layer',
+                                                   'layer_all'):
+                            if p.get('prompt', '') ==  'layer_all':
+                                all = True
+                            else:
+                                all = False
+                            if p.get('age', 'old') ==  'old':
+                                win = gselect.LayerSelect(parent = which_panel,
+                                                          all = all,
+                                                          default = p['default'])
+                                win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                                win.Bind(wx.EVT_TEXT, self.OnSetValue)
+                                win.SetValue(str(value))    # default or previously set value
+                            else:
+                                win = wx.SpinCtrl(parent = which_panel, id = wx.ID_ANY,
+                                                  min = 1, max = 100, initial = int(p['default']))
+                                win.Bind(wx.EVT_SPINCTRL, self.OnSetValue)
+                                win.SetValue(int(value))    # default or previously set value
+
+                            p['wxId'] = [ win.GetId() ]
+
+                        elif p.get('prompt', '') ==  'dbdriver':
+                            win = gselect.DriverSelect(parent = which_panel,
+                                                       choices = p.get('values', []),
+                                                       value = value)
+                            win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
+                            win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                        elif p.get('prompt', '') ==  'dbname':
+                            win = gselect.DatabaseSelect(parent = which_panel,
+                                                         value = value)
+                            win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                            win.Bind(wx.EVT_TEXT, self.OnSetValue)
+                        elif p.get('prompt', '') ==  'dbtable':
+                            if p.get('age', 'old') ==  'old':
+                                win = gselect.TableSelect(parent = which_panel)
+                                win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
+                                win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                            else:
+                                win = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
+                                                  size = globalvar.DIALOG_TEXTCTRL_SIZE)
+                                win.Bind(wx.EVT_TEXT, self.OnSetValue)
+                        elif p.get('prompt', '') ==  'dbcolumn':
+                            win = gselect.ColumnSelect(parent = which_panel,
+                                                       value = value,
+                                                       param = p)
+                            win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
+                            win.Bind(wx.EVT_TEXT,     self.OnSetValue)
+
+                        elif p.get('prompt', '') ==  'location':
+                            win = gselect.LocationSelect(parent = which_panel,
+                                                         value = value)
+                            win.Bind(wx.EVT_COMBOBOX,     self.OnUpdateSelection)
+                            win.Bind(wx.EVT_COMBOBOX,     self.OnSetValue)
+                        
+                        elif p.get('prompt', '') == 'mapset':
+                            if p.get('age', 'old') == 'old':
+                                new = False
+                            else:
+                                new = True
+                            win = gselect.MapsetSelect(parent = which_panel,
+                                                       value = value, new = new)
+                            win.Bind(wx.EVT_COMBOBOX,     self.OnUpdateSelection)
+                            win.Bind(wx.EVT_COMBOBOX,     self.OnSetValue) 
+                            win.Bind(wx.EVT_TEXT,         self.OnSetValue)
+                            
+                        elif p.get('prompt', '') ==  'dbase':
+                            win = gselect.DbaseSelect(parent = which_panel,
+                                                      changeCallback = self.OnSetValue)
+                            win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+                            p['wxId'] = [ win.GetChildren()[1].GetId() ]
+                            
+                    if 'wxId' not in p:
+                        try:
+                            p['wxId'] = [ win.GetId(), ]
+                        except AttributeError:
+                            pass
+                    
+                    which_sizer.Add(item = win, proportion = 0,
+                                    flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
+                # color entry
+                elif p.get('prompt', '') in ('color',
+                                             'color_none'):
+                    default_color = (200,200,200)
+                    label_color = _("Select Color")
+                    if p.get('default','') !=  '':
+                        default_color, label_color = color_resolve(p['default'])
+                    if p.get('value','') !=  '': # parameter previously set
+                        default_color, label_color = color_resolve(p['value'])
+                    if p.get('prompt', '') ==  'color_none':
+                        this_sizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+                    else:
+                        this_sizer = which_sizer
+                    btn_colour = csel.ColourSelect(parent = which_panel, id = wx.ID_ANY,
+                                                   label = label_color, colour = default_color,
+                                                   pos = wx.DefaultPosition, size = (150,-1))
+                    this_sizer.Add(item = btn_colour, proportion = 0,
+                                   flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
+                    # For color selectors, this is a two-member array, holding the IDs of
+                    # the selector proper and either a "transparent" button or None
+                    p['wxId'] = [btn_colour.GetId(),]
+                    btn_colour.Bind(csel.EVT_COLOURSELECT,  self.OnColorChange)
+                    if p.get('prompt', '') ==  'color_none':
+                        none_check = wx.CheckBox(which_panel, wx.ID_ANY, _("Transparent"))
+                        if p.get('value','') !=  '' and p.get('value',[''])[0] ==  "none":
+                            none_check.SetValue(True)
+                        else:
+                            none_check.SetValue(False)
+                        this_sizer.Add(item = none_check, proportion = 0,
+                                       flag = wx.ADJUST_MINSIZE | wx.LEFT | wx.RIGHT | wx.TOP, border = 5)
+                        which_sizer.Add(this_sizer)
+                        none_check.Bind(wx.EVT_CHECKBOX, self.OnColorChange)
+                        p['wxId'].append(none_check.GetId())
+                    else:
+                        p['wxId'].append(None)
+                # file selector
+                elif p.get('prompt','') !=  'color' and p.get('element', '') ==  'file':
+                    if p.get('age', 'new') == 'new':
+                        fmode = wx.SAVE
+                    else:
+                        fmode = wx.OPEN
+                    fbb = filebrowse.FileBrowseButton(parent = which_panel, id = wx.ID_ANY, fileMask = '*',
+                                                      size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
+                                                      dialogTitle = _('Choose %s') % \
+                                                          p.get('description',_('File')),
+                                                      buttonText = _('Browse'),
+                                                      startDirectory = os.getcwd(), fileMode = fmode,
+                                                      changeCallback = self.OnSetValue)
+                    value = self._getValue(p)
+                    if value:
+                        fbb.SetValue(value) # parameter previously set
+                    which_sizer.Add(item = fbb, proportion = 0,
+                                    flag = wx.EXPAND | wx.RIGHT, border = 5)
+                    
+                    # A file browse button is a combobox with two children:
+                    # a textctl and a button;
+                    # we have to target the button here
+                    p['wxId'] = [ fbb.GetChildren()[1].GetId() ]
+                    if p.get('age', 'new') == 'old' and \
+                            UserSettings.Get(group = 'cmd', key = 'interactiveInput', subkey = 'enabled'):
+                        # widget for interactive input
+                        ifbb = wx.TextCtrl(parent = which_panel, id = wx.ID_ANY,
+                                           style = wx.TE_MULTILINE,
+                                           size = (-1, 75))
+                        if p.get('value', '') and os.path.isfile(p['value']):
+                            f = open(p['value'])
+                            ifbb.SetValue(''.join(f.readlines()))
+                            f.close()
+                        
+                        ifbb.Bind(wx.EVT_TEXT, self.OnFileText)
+                        
+                        btnLoad = wx.Button(parent = which_panel, id = wx.ID_ANY, label = _("&Load"))
+                        btnLoad.Bind(wx.EVT_BUTTON, self.OnFileLoad)
+                        btnSave = wx.Button(parent = which_panel, id = wx.ID_SAVEAS)
+                        btnSave.Bind(wx.EVT_BUTTON, self.OnFileSave)
+                        
+                        which_sizer.Add(item = wx.StaticText(parent = which_panel, id = wx.ID_ANY,
+                                                             label = _('or enter values interactively')),
+                                        proportion = 0,
+                                        flag = wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, border = 5)
+                        which_sizer.Add(item = ifbb, proportion = 1,
+                                        flag = wx.EXPAND | wx.RIGHT | wx.LEFT, border = 5)
+                        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+                        btnSizer.Add(item = btnLoad, proportion = 0,
+                                     flag = wx.ALIGN_RIGHT | wx.RIGHT, border = 10)
+                        btnSizer.Add(item = btnSave, proportion = 0,
+                                     flag = wx.ALIGN_RIGHT)
+                        which_sizer.Add(item = btnSizer, proportion = 0,
+                                        flag = wx.ALIGN_RIGHT | wx.RIGHT | wx.TOP, border = 5)
+                        
+                        p['wxId'].append(ifbb.GetId())
+                        p['wxId'].append(btnLoad.GetId())
+                        p['wxId'].append(btnSave.GetId())
+                
+                # directory selector
+                elif p.get('prompt','') != 'color' and p.get('element', '') ==  'dir':
+                    fbb = filebrowse.DirBrowseButton(parent = which_panel, id = wx.ID_ANY,
+                                                     size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
+                                                     dialogTitle = _('Choose %s') % \
+                                                         p.get('description', _('Directory')),
+                                                     buttonText = _('Browse'),
+                                                     startDirectory = os.getcwd(),
+                                                     changeCallback = self.OnSetValue)
+                    value = self._getValue(p)
+                    if value:
+                        fbb.SetValue(value) # parameter previously set
+                    which_sizer.Add(item = fbb, proportion = 0,
+                                    flag = wx.EXPAND | wx.RIGHT, border = 5)
+                    
+                    # A file browse button is a combobox with two children:
+                    # a textctl and a button;
+                    # we have to target the button here
+                    p['wxId'] = [ fbb.GetChildren()[1].GetId() ]
+
+            if self.parent.GetName() == 'MainFrame' and self.parent.modeler:
+                parChk = wx.CheckBox(parent = which_panel, id = wx.ID_ANY,
+                                     label = _("Parameterized in model"))
+                parChk.SetName('ModelParam')
+                parChk.SetValue(p.get('parameterized', False))
+                if 'wxId' in p:
+                    p['wxId'].append(parChk.GetId())
+                else:
+                    p['wxId'] = [ parChk.GetId() ]
+                parChk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
+                which_sizer.Add(item = parChk, proportion = 0,
+                                flag = wx.LEFT, border = 20)
+                
+            if title_txt is not None:
+                # create tooltip if given
+                if len(p['values_desc']) > 0:
+                    if tooltip:
+                        tooltip +=  2 * os.linesep
+                    else:
+                        tooltip = ''
+                    if len(p['values']) ==  len(p['values_desc']):
+                        for i in range(len(p['values'])):
+                            tooltip +=  p['values'][i] + ': ' + p['values_desc'][i] + os.linesep
+                    tooltip.strip(os.linesep)
+                if tooltip:
+                    title_txt.SetToolTipString(tooltip)
+
+            if p ==  first_param:
+                if 'wxId' in p and len(p['wxId']) > 0:
+                    win = self.FindWindowById(p['wxId'][0])
+                    win.SetFocus()
+        
+        #
+        # set widget relations for OnUpdateSelection
+        #
+        pMap = None
+        pLayer = []
+        pDriver = None
+        pDatabase = None
+        pTable = None
+        pColumn = []
+        pGroup = None
+        pSubGroup = None
+        pDbase = None
+        pLocation = None
+        pMapset = None
+        for p in self.task.params:
+            if p.get('gisprompt', False) ==  False:
+                continue
+            
+            guidep = p.get('guidependency', '')
+            
+            if guidep:
+                # fixed options dependency defined
+                options = guidep.split(',')
+                for opt in options:
+                    pOpt = self.task.get_param(opt, element = 'name', raiseError = False)
+                    if id:
+                        if 'wxId-bind' not in p:
+                            p['wxId-bind'] = list()
+                        p['wxId-bind'] +=  pOpt['wxId']
+                continue
+            
+            prompt = p.get('element', '')
+            if prompt in ('cell', 'vector'):
+                name = p.get('name', '')
+                if name in ('map', 'input'):
+                    pMap = p
+            elif prompt ==  'layer':
+                pLayer.append(p)
+            elif prompt ==  'dbcolumn':
+                pColumn.append(p)
+            elif prompt ==  'dbdriver':
+                pDriver = p
+            elif prompt ==  'dbname':
+                pDatabase = p
+            elif prompt ==  'dbtable':
+                pTable = p
+            elif prompt ==  'group':
+                pGroup = p
+            elif prompt ==  'subgroup':
+                pSubGroup = p
+            elif prompt ==  'dbase':
+                pDbase = p
+            elif prompt ==  'location':
+                pLocation = p
+            elif prompt ==  'mapset':
+                pMapset = p
+        
+        # collect ids
+        pColumnIds = []
+        for p in pColumn:
+            pColumnIds +=  p['wxId']
+        pLayerIds = []
+        for p in pLayer:
+            pLayerIds +=  p['wxId']
+        
+        # set wxId-bindings
+        if pMap:
+            pMap['wxId-bind'] = copy.copy(pColumnIds)
+            if pLayer:
+                pMap['wxId-bind'] +=  pLayerIds
+        if pLayer:
+            for p in pLayer:
+                p['wxId-bind'] = copy.copy(pColumnIds)
+        
+        if pDriver and pTable:
+            pDriver['wxId-bind'] = pTable['wxId']
+
+        if pDatabase and pTable:
+            pDatabase['wxId-bind'] = pTable['wxId']
+
+        if pTable and pColumnIds:
+            pTable['wxId-bind'] = pColumnIds
+        
+        if pGroup and pSubGroup:
+            pGroup['wxId-bind'] = pSubGroup['wxId']
+
+        if pDbase and pLocation:
+            pDbase['wxId-bind'] = pLocation['wxId']
+
+        if pLocation and pMapset:
+            pLocation['wxId-bind'] = pMapset['wxId']
+        
+        if pLocation and pMapset and pMap:
+            pLocation['wxId-bind'] +=  pMap['wxId']
+            pMapset['wxId-bind'] = pMap['wxId']
+        
+	#
+	# determine panel size
+	#
+        maxsizes = (0, 0)
+        for section in sections:
+            tab[section].SetSizer(tabsizer[section])
+            tabsizer[section].Fit(tab[section])
+            tab[section].Layout()
+            minsecsizes = tabsizer[section].GetSize()
+            maxsizes = map(lambda x: max(maxsizes[x], minsecsizes[x]), (0, 1))
+
+        # TODO: be less arbitrary with these 600
+        self.panelMinHeight = 100
+        self.constrained_size = (min(600, maxsizes[0]) + 25, min(400, maxsizes[1]) + 25)
+        for section in sections:
+            tab[section].SetMinSize((self.constrained_size[0], self.panelMinHeight))
+        
+        if self.manual_tab.IsLoaded():
+            self.manual_tab.SetMinSize((self.constrained_size[0], self.panelMinHeight))
+        
+        self.SetSizer(panelsizer)
+        panelsizer.Fit(self.notebook)
+        
+        self.Bind(EVT_DIALOG_UPDATE, self.OnUpdateDialog)
+
+    def _getValue(self, p):
+        """!Get value or default value of given parameter
+
+        @param p parameter directory
+        """
+        if p.get('value', '') !=  '':
+            return p['value']
+        return p.get('default', '')
+        
+    def OnFileLoad(self, event):
+        """!Load file to interactive input"""
+        me = event.GetId()
+        win = dict()
+        for p in self.task.params:
+            if 'wxId' in p and me in p['wxId']:
+                win['file'] = self.FindWindowById(p['wxId'][0])
+                win['text'] = self.FindWindowById(p['wxId'][1])
+                break
+        
+        if not win:
+            return
+        
+        path = win['file'].GetValue()
+        if not path:
+            gcmd.GMessage(parent = self,
+                          message = _("Nothing to load."))
+            return
+        
+        data = ''
+        f = open(path, "r")
+        try:
+            data = f.read()
+        finally:
+            f.close()
+        
+        win['text'].SetValue(data)
+        
+    def OnFileSave(self, event):
+        """!Save interactive input to the file"""
+        wId = event.GetId()
+        win = {}
+        for p in self.task.params:
+            if wId in p.get('wxId', []):
+                win['file'] = self.FindWindowById(p['wxId'][0])
+                win['text'] = self.FindWindowById(p['wxId'][1])
+                break
+        
+        if not win:
+            return
+
+        text = win['text'].GetValue()
+        if not text:
+            gcmd.GMessage(parent = self,
+                          message = _("Nothing to save."))
+            return
+        
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Save input as..."),
+                            defaultDir = os.getcwd(),
+                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            f = open(path, "w")
+            try:
+                f.write(text + os.linesep)
+            finally:
+                f.close()
+            
+            win['file'].SetValue(path)
+        
+        dlg.Destroy()
+        
+    def OnFileText(self, event):
+        """File input interactively entered"""
+        text = event.GetString()
+        p = self.task.get_param(value = event.GetId(), element = 'wxId', raiseError = False)
+        if not p:
+            return # should not happen
+        win = self.FindWindowById(p['wxId'][0])
+        if text:
+            filename = win.GetValue()
+            if not filename:
+                # outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
+                filename = grass.tempfile()
+                win.SetValue(filename)
+                
+            f = open(filename, "w")
+            try:
+                f.write(text)
+                if text[-1] != os.linesep:
+                    f.write(os.linesep)
+            finally:
+                f.close()
+        else:
+            win.SetValue('')
+        
+    def OnVectorFormat(self, event):
+        """!Change vector format (native / ogr)"""
+        sel = event.GetSelection()
+        idEvent = event.GetId()
+        p = self.task.get_param(value = idEvent, element = 'wxId', raiseError = False)
+        if not p:
+            return # should not happen
+        
+        # detect windows
+        winNative = None
+        winOgr = None
+        for id in p['wxId']:
+            if id ==  idEvent:
+                continue
+            name = self.FindWindowById(id).GetName()
+            if name ==  'Select':
+                winNative = self.FindWindowById(id + 1)  # fix the mystery (also in nviz_tools.py)
+            elif name ==  'OgrSelect':
+                winOgr = self.FindWindowById(id)
+        
+        # enable / disable widgets & update values
+        rbox = self.FindWindowByName('VectorFormat')
+        self.hsizer.Remove(rbox)
+        if sel ==  0:   # -> native
+            winOgr.Hide()
+            self.hsizer.Remove(winOgr)
+            
+            self.hsizer.Add(item = winNative,
+                            flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
+                            border = 5)
+            winNative.Show()
+            p['value'] = winNative.GetValue()
+        
+        elif sel ==  1: # -> OGR
+            sizer = wx.BoxSizer(wx.VERTICAL)
+            
+            winNative.Hide()
+            self.hsizer.Remove(winNative)
+
+            sizer.Add(item = winOgr)
+            winOgr.Show()
+            p['value'] = winOgr.GetDsn()
+            
+            self.hsizer.Add(item = sizer,
+                            flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
+                            border = 5)
+        
+        self.hsizer.Add(item = rbox,
+                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT |
+                        wx.RIGHT | wx.ALIGN_TOP,
+                        border = 5)
+        
+        self.hsizer.Layout()
+        self.Layout()
+        self.OnUpdateValues()
+        self.OnUpdateSelection(event)
+        
+    def OnUpdateDialog(self, event):
+        for fn, kwargs in event.data.iteritems():
+            fn(**kwargs)
+        
+        self.parent.updateValuesHook()
+        
+    def OnVerbosity(self, event):
+        """!Verbosity level changed"""
+        verbose = self.FindWindowById(self.task.get_flag('verbose')['wxId'][0])
+        quiet = self.FindWindowById(self.task.get_flag('quiet')['wxId'][0])
+        if event.IsChecked():
+            if event.GetId() ==  verbose.GetId():
+                if quiet.IsChecked():
+                    quiet.SetValue(False)
+                    self.task.get_flag('quiet')['value'] = False
+            else:
+                if verbose.IsChecked():
+                    verbose.SetValue(False)
+                    self.task.get_flag('verbose')['value'] = False
+
+        event.Skip()
+
+    def OnPageChange(self, event):
+        if not event:
+            sel = self.notebook.GetSelection()
+        else:
+            sel = event.GetSelection()
+        
+        idx = self.notebook.GetPageIndexByName('manual')
+        if idx > -1 and sel ==  idx:
+            # calling LoadPage() is strangely time-consuming (only first call)
+            # FIXME: move to helpPage.__init__()
+            if not self.manual_tab.IsLoaded():
+                wx.Yield()
+                self.manual_tab.LoadPage()
+
+        self.Layout()
+
+    def OnColorChange(self, event):
+        myId = event.GetId()
+        for p in self.task.params:
+            if 'wxId' in p and myId in p['wxId']:
+                has_button = p['wxId'][1] is not None
+                if has_button and wx.FindWindowById(p['wxId'][1]).GetValue() ==  True:
+                    p[ 'value' ] = 'none'
+                else:
+                    colorchooser = wx.FindWindowById(p['wxId'][0])
+                    new_color = colorchooser.GetValue()[:]
+                    # This is weird: new_color is a 4-tuple and new_color[:] is a 3-tuple
+                    # under wx2.8.1
+                    new_label = rgb2str.get(new_color, ':'.join(map(str,new_color)))
+                    colorchooser.SetLabel(new_label)
+                    colorchooser.SetColour(new_color)
+                    colorchooser.Refresh()
+                    p[ 'value' ] = colorchooser.GetLabel()
+        self.OnUpdateValues()
+
+    def OnUpdateValues(self, event = None):
+        """!If we were part of a richer interface, report back the
+        current command being built.
+
+        This method should be set by the parent of this panel if
+        needed. It's a hook, actually.  Beware of what is 'self' in
+        the method def, though. It will be called with no arguments.
+        """
+        pass
+
+    def OnCheckBoxMulti(self, event):
+        """!Fill the values as a ','-separated string according to
+        current status of the checkboxes.
+        """
+        me = event.GetId()
+        theParam = None
+        for p in self.task.params:
+            if 'wxId' in p and me in p['wxId']:
+                theParam = p
+                myIndex = p['wxId'].index(me)
+
+        # Unpack current value list
+        currentValues = {}
+        for isThere in theParam.get('value', '').split(','):
+            currentValues[isThere] = 1
+        theValue = theParam['values'][myIndex]
+
+        if event.Checked():
+            currentValues[ theValue ] = 1
+        else:
+            del currentValues[ theValue ]
+
+        # Keep the original order, so that some defaults may be recovered
+        currentValueList = [] 
+        for v in theParam['values']:
+            if v in currentValues:
+                currentValueList.append(v)
+
+        # Pack it back
+        theParam['value'] = ','.join(currentValueList)
+
+        self.OnUpdateValues()
+
+    def OnSetValue(self, event):
+        """!Retrieve the widget value and set the task value field
+        accordingly.
+
+        Use for widgets that have a proper GetValue() method, i.e. not
+        for selectors.
+        """
+        myId = event.GetId()
+        me = wx.FindWindowById(myId)
+        name = me.GetName()
+
+        found = False
+        for porf in self.task.params + self.task.flags:
+            if 'wxId' not in porf:
+                continue
+            if myId in porf['wxId']:
+                found = True
+                break
+        
+        if not found:
+            return
+        
+        if name ==  'GdalSelect':
+            porf['value'] = event.dsn
+        elif name ==  'ModelParam':
+            porf['parameterized'] = me.IsChecked()
+        else:
+            porf['value'] = me.GetValue()
+
+        self.OnUpdateValues(event)
+        
+        event.Skip()
+        
+    def OnUpdateSelection(self, event):
+        """!Update dialog (layers, tables, columns, etc.)
+        """
+        if not hasattr(self.parent, "updateThread"):
+            if event:
+                event.Skip()
+            return
+        if event:
+            self.parent.updateThread.Update(UpdateDialog,
+                                            self,
+                                            event,
+                                            event.GetId(),
+                                            self.task)
+        else:
+            self.parent.updateThread.Update(UpdateDialog,
+                                            self,
+                                            None,
+                                            None,
+                                            self.task)
+            
+    def createCmd(self, ignoreErrors = False, ignoreRequired = False):
+        """!Produce a command line string (list) or feeding into GRASS.
+
+        @param ignoreErrors True then it will return whatever has been
+        built so far, even though it would not be a correct command
+        for GRASS
+        """
+        try:
+            cmd = self.task.get_cmd(ignoreErrors = ignoreErrors,
+                                   ignoreRequired = ignoreRequired)
+        except ValueError, err:
+            dlg = wx.MessageDialog(parent = self,
+                                   message = unicode(err),
+                                   caption = _("Error in %s") % self.task.name,
+                                   style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            dlg.ShowModal()
+            dlg.Destroy()
+            cmd = None
+        
+        return cmd
+    
+    def OnSize(self, event):
+        width = event.GetSize()[0]
+        fontsize = self.GetFont().GetPointSize()
+        text_width = max(width / (fontsize - 3), 70)
+        
+        for id in self.label_id:
+            win = self.FindWindowById(id)
+            label = win.GetLabel()
+            label_new = '\n'.join(textwrap.wrap(label, text_width))
+            win.SetLabel(label_new)
+            
+        event.Skip()
+        
+class GrassGUIApp(wx.App):
+    """!Stand-alone GRASS command GUI
+    """
+    def __init__(self, grass_task):
+        self.grass_task = grass_task
+        wx.App.__init__(self, False)
+        
+    def OnInit(self):
+        msg = self.grass_task.get_error_msg()
+        if msg:
+            gcmd.GError(msg + '\n\nTry to set up GRASS_ADDON_PATH variable.')
+            return True
+        
+        self.mf = mainFrame(parent = None, ID = wx.ID_ANY, task_description = self.grass_task)
+        self.mf.CentreOnScreen()
+        self.mf.Show(True)
+        self.SetTopWindow(self.mf)
+        
+        return True
+
+class GUI:
+    def __init__(self, parent = None, show = True, modal = False,
+                 centreOnParent = False, checkError = False):
+        """!Parses GRASS commands when module is imported and used from
+        Layer Manager.
+        """
+        self.parent = parent
+        self.show   = show
+        self.modal  = modal
+        self.centreOnParent = centreOnParent
+        self.checkError     = checkError
+        
+        self.grass_task = None
+        self.cmd = list()
+        
+        global _blackList
+        if self.parent:
+            _blackList['enabled'] = True
+        else:
+            _blackList['enabled'] = False
+        
+    def GetCmd(self):
+        """!Get validated command"""
+        return self.cmd
+    
+    def ParseCommand(self, cmd, gmpath = None, completed = None):
+        """!Parse command
+        
+        Note: cmd is given as list
+        
+        If command is given with options, return validated cmd list:
+         - add key name for first parameter if not given
+         - change mapname to mapname at mapset
+        """
+        start = time.time()
+        dcmd_params = {}
+        if completed == None:
+            get_dcmd = None
+            layer = None
+            dcmd_params = None
+        else:
+            get_dcmd = completed[0]
+            layer = completed[1]
+            if completed[2]:
+                dcmd_params.update(completed[2])
+        
+        # parse the interface decription
+        try:
+            global _blackList
+            self.grass_task = gtask.parse_interface(cmd[0],
+                                                    blackList = _blackList)
+        except ValueError, e: #grass.ScriptError, e:
+            gcmd.GError(e.value)
+            return
+        
+        # if layer parameters previously set, re-insert them into dialog
+        if completed is not None:
+            if 'params' in dcmd_params:
+                self.grass_task.params = dcmd_params['params']
+            if 'flags' in dcmd_params:
+                self.grass_task.flags = dcmd_params['flags']
+        
+        err = list()
+        # update parameters if needed && validate command
+        if len(cmd) > 1:
+            i = 0
+            cmd_validated = [cmd[0]]
+            for option in cmd[1:]:
+                if option[0] ==  '-': # flag
+                    if option[1] ==  '-':
+                        self.grass_task.set_flag(option[2:], True)
+                    else:
+                        self.grass_task.set_flag(option[1], True)
+                    cmd_validated.append(option)
+                else: # parameter
+                    try:
+                        key, value = option.split('=', 1)
+                    except:
+                        if self.grass_task.firstParam:
+                            if i == 0: # add key name of first parameter if not given
+                                key = self.grass_task.firstParam
+                                value = option
+                            else:
+                                raise gcmd.GException, _("Unable to parse command '%s'") % ' '.join(cmd)
+                        else:
+                            continue
+                    
+                    element = self.grass_task.get_param(key, raiseError = False)
+                    if not element:
+                        err.append(_("%(cmd)s: parameter '%(key)s' not available") % \
+                                       { 'cmd' : cmd[0],
+                                         'key' : key })
+                        continue
+                    element = element['element']
+                    
+                    if element in ['cell', 'vector']:
+                        # mapname -> mapname at mapset
+                        try:
+                            name, mapset = value.split('@')
+                        except ValueError:
+                            mapset = grass.find_file(value, element)['mapset']
+                            curr_mapset = grass.gisenv()['MAPSET']
+                            if mapset and mapset !=  curr_mapset:
+                                value = value + '@' + mapset
+                    
+                    self.grass_task.set_param(key, value)
+                    cmd_validated.append(key + '=' + value)
+                    i += 1
+            
+            # update original command list
+            cmd = cmd_validated
+        
+        if self.show is not None:
+            self.mf = mainFrame(parent = self.parent, ID = wx.ID_ANY,
+                                task_description = self.grass_task,
+                                get_dcmd = get_dcmd, layer = layer)
+        else:
+            self.mf = None
+        
+        if get_dcmd is not None:
+            # update only propwin reference
+            get_dcmd(dcmd = None, layer = layer, params = None,
+                     propwin = self.mf)
+        
+        if self.show is not None:
+            self.mf.notebookpanel.OnUpdateSelection(None)
+            if self.show is True:
+                if self.parent and self.centreOnParent:
+                    self.mf.CentreOnParent()
+                else:
+                    self.mf.CenterOnScreen()
+                self.mf.Show(self.show)
+                self.mf.MakeModal(self.modal)
+            else:
+                self.mf.OnApply(None)
+        
+        self.cmd = cmd
+        
+        if self.checkError:
+            return self.grass_task, err
+        else:
+            return self.grass_task
+    
+    def GetCommandInputMapParamKey(self, cmd):
+        """!Get parameter key for input raster/vector map
+        
+        @param cmd module name
+        
+        @return parameter key
+        @return None on failure
+        """
+        # parse the interface decription
+        if not self.grass_task:
+            enc = locale.getdefaultlocale()[1]
+            if enc and enc.lower() == "cp932":
+                p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
+                tree = etree.fromstring(p.sub('encoding="utf-8"',
+                                              gtask.get_interface_description(cmd).decode(enc).encode('utf-8')))
+            else:
+                tree = etree.fromstring(gtask.get_interface_description(cmd))
+            self.grass_task = gtask.processTask(tree).get_task()
+            
+            for p in self.grass_task.params:
+                if p.get('name', '') in ('input', 'map'):
+                    age = p.get('age', '')
+                    prompt = p.get('prompt', '')
+                    element = p.get('element', '') 
+                    if age ==  'old' and \
+                            element in ('cell', 'grid3', 'vector') and \
+                            prompt in ('raster', '3d-raster', 'vector'):
+                        return p.get('name', None)
+        return None
+
+class FloatValidator(wx.PyValidator):
+    """!Validator for floating-point input"""
+    def __init__(self):
+        wx.PyValidator.__init__(self)
+        
+        self.Bind(wx.EVT_TEXT, self.OnText) 
+        
+    def Clone(self):
+        """!Clone validator"""
+        return FloatValidator()
+
+    def Validate(self):
+        """Validate input"""
+        textCtrl = self.GetWindow()
+        text = textCtrl.GetValue()
+
+        if text:
+            try:
+                float(text)
+            except ValueError:
+                textCtrl.SetBackgroundColour("grey")
+                textCtrl.SetFocus()
+                textCtrl.Refresh()
+                return False
+        
+        sysColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
+        textCtrl.SetBackgroundColour(sysColor)
+        
+        textCtrl.Refresh()
+        
+        return True
+
+    def OnText(self, event):
+        """!Do validation"""
+        self.Validate()
+        
+        event.Skip()
+        
+    def TransferToWindow(self):
+        return True # Prevent wxDialog from complaining.
+    
+    def TransferFromWindow(self):
+        return True # Prevent wxDialog from complaining.
+
+if __name__ ==  "__main__":
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    if len(sys.argv) ==  1:
+        sys.exit(_("usage: %s <grass command>") % sys.argv[0])
+    
+    if sys.argv[1] !=  'test':
+        q = wx.LogNull()
+        cmd = utils.split(sys.argv[1])
+        task = gtask.grassTask(cmd[0], blackList = _blackList)
+        task.set_options(cmd[1:])
+        app = GrassGUIApp(task)
+        app.MainLoop()
+    else: #Test
+        # Test grassTask from within a GRASS session
+        if os.getenv("GISBASE") is not None:
+            task = gtask.grassTask("d.vect")
+            task.get_param('map')['value'] = "map_name"
+            task.get_flag('v')['value'] = True
+            task.get_param('layer')['value'] = 1
+            task.get_param('bcolor')['value'] = "red"
+            assert ' '.join(task.get_cmd()) ==  "d.vect -v map = map_name layer = 1 bcolor = red"
+        # Test interface building with handmade grassTask,
+        # possibly outside of a GRASS session.
+        task = gtask.grassTask()
+        task.name = "TestTask"
+        task.description = "This is an artificial grassTask() object intended for testing purposes."
+        task.keywords = ["grass","test","task"]
+        task.params = [
+            {
+            "name" : "text",
+            "description" : "Descriptions go into tooltips if labels are present, like this one",
+            "label" : "Enter some text",
+            },{
+            "name" : "hidden_text",
+            "description" : "This text should not appear in the form",
+            "hidden" : True
+            },{
+            "name" : "text_default",
+            "description" : "Enter text to override the default",
+            "default" : "default text"
+            },{
+            "name" : "text_prefilled",
+            "description" : "You should see a friendly welcome message here",
+            "value" : "hello, world"
+            },{
+            "name" : "plain_color",
+            "description" : "This is a plain color, and it is a compulsory parameter",
+            "required" : False,
+            "gisprompt" : True,
+            "prompt" : "color"
+            },{
+            "name" : "transparent_color",
+            "description" : "This color becomes transparent when set to none",
+            "guisection" : "tab",
+            "gisprompt" : True,
+            "prompt" : "color"
+            },{
+            "name" : "multi",
+            "description" : "A multiple selection",
+            'default': u'red,green,blue',
+            'gisprompt': False,
+            'guisection': 'tab',
+            'multiple': u'yes',
+            'type': u'string',
+            'value': '',
+            'values': ['red', 'green', u'yellow', u'blue', u'purple', u'other']
+            },{
+            "name" : "single",
+            "description" : "A single multiple-choice selection",
+            'values': ['red', 'green', u'yellow', u'blue', u'purple', u'other'],
+            "guisection" : "tab"
+            },{
+            "name" : "large_multi",
+            "description" : "A large multiple selection",
+            "gisprompt" : False,
+            "multiple" : "yes",
+            # values must be an array of strings
+            "values" : str2rgb.keys() + map(str, str2rgb.values())
+            },{
+            "name" : "a_file",
+            "description" : "A file selector",
+            "gisprompt" : True,
+            "element" : "file"
+            }
+            ]
+        task.flags = [
+            {
+            "name" : "a",
+            "description" : "Some flag, will appear in Main since it is required",
+            "required" : True
+            },{
+            "name" : "b",
+            "description" : "pre-filled flag, will appear in options since it is not required",
+            "value" : True
+            },{
+            "name" : "hidden_flag",
+            "description" : "hidden flag, should not be changeable",
+            "hidden" : "yes",
+            "value" : True
+            }
+            ]
+        q = wx.LogNull()
+        GrassGUIApp(task).MainLoop()
+

Copied: grass/trunk/gui/wxpython/gui_core/ghelp.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/ghelp.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/ghelp.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/ghelp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1299 @@
+"""!
+ at package gui_core.ghelp
+
+ at brief Help window
+
+Classes:
+ - SearchModuleWindow
+ - ItemTree
+ - MenuTreeWindow
+ - MenuTree
+ - AboutWindow
+ - InstallExtensionWindow
+ - ExtensionTree
+ - HelpFrame
+ - HelpWindow
+ - HelpPanel
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import codecs
+
+import wx
+try:
+    import wx.lib.agw.customtreectrl as CT
+    from wx.lib.agw.hyperlink import HyperLinkCtrl
+except ImportError:
+    import wx.lib.customtreectrl as CT
+    from wx.lib.hyperlink import HyperLinkCtrl
+import wx.lib.flatnotebook as FN
+import  wx.lib.scrolledpanel as scrolled
+
+import grass.script as grass
+from grass.script import task as gtask
+
+from core             import globalvar
+from core             import utils
+from lmgr.menudata    import ManagerData
+from core.gcmd        import GError, RunCommand, DecodeString
+from gui_core.widgets import GNotebook
+from core.forms       import GUI
+from gui_core.dialogs import StaticWrapText
+
+class HelpFrame(wx.Frame):
+    """!GRASS Quickstart help window"""
+    def __init__(self, parent, id, title, size, file):
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, size = size)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # text
+        content = HelpPanel(parent = self)
+        content.LoadPage(file)
+        
+        sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
+        
+        self.SetAutoLayout(True)
+        self.SetSizer(sizer)
+        self.Layout()
+
+class SearchModuleWindow(wx.Panel):
+    """!Search module window (used in MenuTreeWindow)"""
+    def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
+                 showChoice = True, showTip = False, **kwargs):
+        self.showTip    = showTip
+        self.showChoice = showChoice
+        self.cmdPrompt  = cmdPrompt
+        
+        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+        
+        self._searchDict = { _('description') : 'description',
+                             _('command')     : 'command',
+                             _('keywords')    : 'keywords' }
+        
+        self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                label = " %s " % _("Find module(s)"))
+        
+        self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
+                                  choices = [_('description'),
+                                             _('keywords'),
+                                             _('command')])
+        self.searchBy.SetSelection(0)
+        
+        self.search = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+                                  value = "", size = (-1, 25),
+                                  style = wx.TE_PROCESS_ENTER)
+        self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
+        
+        if self.showTip:
+            self.searchTip = StaticWrapText(parent = self, id = wx.ID_ANY,
+                                            size = (-1, 35))
+        
+        if self.showChoice:
+            self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
+            if self.cmdPrompt:
+                self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
+            self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
+        
+        self._layout()
+
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
+        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(1)
+        
+        gridSizer.Add(item = self.searchBy,
+                      flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        gridSizer.Add(item = self.search,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (0, 1))
+        row = 1
+        if self.showTip:
+            gridSizer.Add(item = self.searchTip,
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
+            row += 1
+        
+        if self.showChoice:
+            gridSizer.Add(item = self.searchChoice,
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
+        
+        sizer.Add(item = gridSizer, proportion = 1)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def GetSelection(self):
+        """!Get selected element"""
+        selection = self.searchBy.GetStringSelection()
+        
+        return self._searchDict[selection]
+
+    def SetSelection(self, i):
+        """!Set selection element"""
+        self.searchBy.SetSelection(i)
+
+    def OnSearchModule(self, event):
+        """!Search module by keywords or description"""
+        if not self.cmdPrompt:
+            event.Skip()
+            return
+        
+        text = event.GetString()
+        if not text:
+            self.cmdPrompt.SetFilter(None)
+            mList = self.cmdPrompt.GetCommandItems()
+            self.searchChoice.SetItems(mList)
+            if self.showTip:
+                self.searchTip.SetLabel(_("%d modules found") % len(mList))
+            event.Skip()
+            return
+        
+        modules = dict()
+        iFound = 0
+        for module, data in self.cmdPrompt.moduleDesc.iteritems():
+            found = False
+            sel = self.searchBy.GetSelection()
+            if sel == 0: # -> description
+                if text in data['desc']:
+                    found = True
+            elif sel == 1: # keywords
+                if text in ','.join(data['keywords']):
+                    found = True
+            else: # command
+                if module[:len(text)] == text:
+                    found = True
+            
+            if found:
+                iFound += 1
+                try:
+                    group, name = module.split('.')
+                except ValueError:
+                    continue # TODO
+                
+                if group not in modules:
+                    modules[group] = list()
+                modules[group].append(name)
+                
+        self.cmdPrompt.SetFilter(modules)
+        self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
+        if self.showTip:
+            self.searchTip.SetLabel(_("%d modules found") % iFound)
+        
+        event.Skip()
+        
+    def OnSelectModule(self, event):
+        """!Module selected from choice, update command prompt"""
+        cmd  = event.GetString().split(' ', 1)[0]
+        text = cmd + ' '
+        pos = len(text)
+
+        if self.cmdPrompt:
+            self.cmdPrompt.SetText(text)
+            self.cmdPrompt.SetSelectionStart(pos)
+            self.cmdPrompt.SetCurrentPos(pos)
+            self.cmdPrompt.SetFocus()
+        
+        desc = self.cmdPrompt.GetCommandDesc(cmd)
+        if self.showTip:
+            self.searchTip.SetLabel(desc)
+    
+    def Reset(self):
+        """!Reset widget"""
+        self.searchBy.SetSelection(0)
+        self.search.SetValue('')
+        if self.showTip:
+            self.searchTip.SetLabel('')
+        
+class MenuTreeWindow(wx.Panel):
+    """!Show menu tree"""
+    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
+        self.parent = parent # LayerManager
+        
+        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+        
+        self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                    label = " %s " % _("Menu tree (double-click to run command)"))
+        # tree
+        self.tree = MenuTree(parent = self, data = ManagerData())
+        self.tree.Load()
+
+        # search widget
+        self.search = SearchModuleWindow(parent = self, showChoice = False)
+        
+        # buttons
+        self.btnRun   = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
+        self.btnRun.SetToolTipString(_("Run selected command"))
+        self.btnRun.Enable(False)
+        
+        # bindings
+        self.btnRun.Bind(wx.EVT_BUTTON,            self.OnRun)
+        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
+        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
+        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
+        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
+        
+        self._layout()
+        
+        self.search.SetFocus()
+        
+    def _layout(self):
+        """!Do dialog layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # body
+        dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
+        dataSizer.Add(item = self.tree, proportion =1,
+                      flag = wx.EXPAND)
+        
+        # buttons
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = self.btnRun, proportion = 0)
+        
+        sizer.Add(item = dataSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.ALL, border = 5)
+
+        sizer.Add(item = self.search, proportion = 0,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
+        
+        sizer.Fit(self)
+        sizer.SetSizeHints(self)
+        
+        self.SetSizer(sizer)
+        
+        self.Fit()
+        self.SetAutoLayout(True)        
+        self.Layout()
+        
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        self.Destroy()
+        
+    def OnRun(self, event):
+        """!Run selected command"""
+        if not self.tree.GetSelected():
+            return # should not happen
+        
+        data = self.tree.GetPyData(self.tree.GetSelected())
+        if not data:
+            return
+
+        handler = 'self.parent.' + data['handler'].lstrip('self.')
+        if data['handler'] == 'self.OnXTerm':
+            wx.MessageBox(parent = self,
+                          message = _('You must run this command from the menu or command line',
+                                      'This command require an XTerm'),
+                          caption = _('Message'), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+        elif data['command']:
+            eval(handler)(event = None, cmd = data['command'].split())
+        else:
+            eval(handler)(None)
+
+    def OnShowItem(self, event):
+        """!Show selected item"""
+        self.tree.OnShowItem(event)
+        if self.tree.GetSelected():
+            self.btnRun.Enable()
+        else:
+            self.btnRun.Enable(False)
+        
+    def OnItemActivated(self, event):
+        """!Item activated (double-click)"""
+        item = event.GetItem()
+        if not item or not item.IsOk():
+            return
+        
+        data = self.tree.GetPyData(item)
+        if not data or 'command' not in data:
+            return
+        
+        self.tree.itemSelected = item
+        
+        self.OnRun(None)
+        
+    def OnItemSelected(self, event):
+        """!Item selected"""
+        item = event.GetItem()
+        if not item or not item.IsOk():
+            return
+        
+        data = self.tree.GetPyData(item)
+        if not data or 'command' not in data:
+            return
+        
+        if data['command']:
+            label = data['command'] + ' -- ' + data['description']
+        else:
+            label = data['description']
+        
+        self.parent.SetStatusText(label, 0)
+        
+    def OnUpdateStatusBar(self, event):
+        """!Update statusbar text"""
+        element = self.search.GetSelection()
+        self.tree.SearchItems(element = element,
+                              value = event.GetString())
+        
+        nItems = len(self.tree.itemsMarked)
+        if event.GetString():
+            self.parent.SetStatusText(_("%d modules match") % nItems, 0)
+        else:
+            self.parent.SetStatusText("", 0)
+        
+        event.Skip()
+        
+class ItemTree(CT.CustomTreeCtrl):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
+                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE, **kwargs):
+        if globalvar.hasAgw:
+            super(ItemTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
+        else:
+            super(ItemTree, self).__init__(parent, id, style = ctstyle, **kwargs)
+        
+        self.root = self.AddRoot(_("Menu tree"))
+        self.itemsMarked = [] # list of marked items
+        self.itemSelected = None
+
+    def SearchItems(self, element, value):
+        """!Search item 
+
+        @param element element index (see self.searchBy)
+        @param value
+
+        @return list of found tree items
+        """
+        items = list()
+        if not value:
+            return items
+        
+        item = self.GetFirstChild(self.root)[0]
+        self._processItem(item, element, value, items)
+        
+        self.itemsMarked  = items
+        self.itemSelected = None
+        
+        return items
+    
+    def _processItem(self, item, element, value, listOfItems):
+        """!Search items (used by SearchItems)
+        
+        @param item reference item
+        @param listOfItems list of found items
+        """
+        while item and item.IsOk():
+            subItem = self.GetFirstChild(item)[0]
+            if subItem:
+                self._processItem(subItem, element, value, listOfItems)
+            data = self.GetPyData(item)
+            
+            if data and element in data and \
+                    value.lower() in data[element].lower():
+                listOfItems.append(item)
+            
+            item = self.GetNextSibling(item)
+            
+    def GetSelected(self):
+        """!Get selected item"""
+        return self.itemSelected
+
+    def OnShowItem(self, event):
+        """!Highlight first found item in menu tree"""
+        if len(self.itemsMarked) > 0:
+            if self.GetSelected():
+                self.ToggleItemSelection(self.GetSelected())
+                idx = self.itemsMarked.index(self.GetSelected()) + 1
+            else:
+                idx = 0
+            try:
+                self.ToggleItemSelection(self.itemsMarked[idx])
+                self.itemSelected = self.itemsMarked[idx]
+                self.EnsureVisible(self.itemsMarked[idx])
+            except IndexError:
+                self.ToggleItemSelection(self.itemsMarked[0]) # reselect first item
+                self.EnsureVisible(self.itemsMarked[0])
+                self.itemSelected = self.itemsMarked[0]
+        else:
+            for item in self.root.GetChildren():
+                self.Collapse(item)
+            itemSelected = self.GetSelection()
+            if itemSelected:
+                self.ToggleItemSelection(itemSelected)
+            self.itemSelected = None
+    
+class MenuTree(ItemTree):
+    """!Menu tree class"""
+    def __init__(self, parent, data, **kwargs):
+        self.parent   = parent
+        self.menudata = data
+
+        super(MenuTree, self).__init__(parent, **kwargs)
+        
+    def Load(self, data = None):
+        """!Load menu data tree
+
+        @param data menu data (None to use self.menudata)
+        """
+        if not data:
+            data = self.menudata
+        
+        self.itemsMarked = [] # list of marked items
+        for eachMenuData in data.GetMenu():
+            for label, items in eachMenuData:
+                item = self.AppendItem(parentId = self.root,
+                                       text = label.replace('&', ''))
+                self.__AppendItems(item, items)
+        
+    def __AppendItems(self, item, data):
+        """!Append items into tree (used by Load()
+        
+        @param item tree item (parent)
+        @parent data menu data"""
+        for eachItem in data:
+            if len(eachItem) == 2:
+                if eachItem[0]:
+                    itemSub = self.AppendItem(parentId = item,
+                                    text = eachItem[0])
+                self.__AppendItems(itemSub, eachItem[1])
+            else:
+                if eachItem[0]:
+                    itemNew = self.AppendItem(parentId = item,
+                                              text = eachItem[0])
+                    
+                    data = { 'item'        : eachItem[0],
+                             'description' : eachItem[1],
+                             'handler'  : eachItem[2],
+                             'command'  : eachItem[3],
+                             'keywords' : eachItem[4] }
+                    
+                    self.SetPyData(itemNew, data)
+        
+class AboutWindow(wx.Frame):
+    """!Create custom About Window
+
+    @todo improve styling
+    """
+    def __init__(self, parent, size = (750, 400), 
+                 title = _('About GRASS GIS'), **kwargs):
+        wx.Frame.__init__(self, parent = parent, id = wx.ID_ANY, size = size, **kwargs)
+        
+        panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        # icon
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+        # get version and web site
+        vInfo = grass.version()
+        
+        infoTxt = wx.Panel(parent = panel, id = wx.ID_ANY)
+        infoSizer = wx.BoxSizer(wx.VERTICAL)
+        infoGridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        infoGridSizer.AddGrowableCol(0)
+        infoGridSizer.AddGrowableCol(1)
+        logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass.ico")
+        logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
+                                     bitmap = wx.Bitmap(name = logo,
+                                                        type = wx.BITMAP_TYPE_ICO))
+        infoSizer.Add(item = logoBitmap, proportion = 0,
+                      flag = wx.ALL | wx.ALIGN_CENTER, border = 25)
+        
+        info = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                             label = 'GRASS GIS ' + vInfo['version'] + '\n\n')
+        info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+        infoSizer.Add(item = info, proportion = 0,
+                          flag = wx.BOTTOM | wx.ALIGN_CENTER, border = 15)
+
+        row = 0
+        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                                               label = _('Official GRASS site:')),
+                          pos = (row, 0),
+                          flag = wx.ALIGN_RIGHT)
+
+        infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
+                                               label = 'http://grass.osgeo.org'),
+                          pos = (row, 1),
+                          flag = wx.ALIGN_LEFT)
+
+        row += 2
+        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                                               label = _('SVN Revision:')),
+                          pos = (row, 0),
+                          flag = wx.ALIGN_RIGHT)
+        
+        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                                               label = vInfo['revision']),
+                          pos = (row, 1),
+                          flag = wx.ALIGN_LEFT)
+        
+        row += 1
+        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                                               label = _('GIS Library Revision:')),
+                          pos = (row, 0),
+                          flag = wx.ALIGN_RIGHT)
+        
+        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+                                               label = vInfo['libgis_revision'] + ' (' +
+                                               vInfo['libgis_date'].split(' ')[0] + ')'),
+                          pos = (row, 1),
+                          flag = wx.ALIGN_LEFT)
+
+        infoSizer.Add(item = infoGridSizer,
+                      proportion = 1,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL,
+                      border = 25)
+        
+        # create a flat notebook for displaying information about GRASS
+        aboutNotebook = GNotebook(panel, style = globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON) 
+        aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
+        
+        for title, win in ((_("Info"), infoTxt),
+                           (_("Copyright"), self._pageCopyright()),
+                           (_("License"), self._pageLicense()),
+                           (_("Authors"), self._pageCredit()),
+                           (_("Contributors"), self._pageContributors()),
+                           (_("Extra contributors"), self._pageContributors(extra = True)),
+                           (_("Translators"), self._pageTranslators())):
+            aboutNotebook.AddPage(page = win, text = title)
+        wx.CallAfter(aboutNotebook.SetSelection, 0)
+        
+        # buttons
+        btnClose = wx.Button(parent = panel, id = wx.ID_CLOSE)
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = btnClose, proportion = 0,
+                     flag = wx.ALL | wx.ALIGN_RIGHT,
+                     border = 5)
+        # bindings
+        btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+        
+        infoTxt.SetSizer(infoSizer)
+        infoSizer.Fit(infoTxt)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(item = aboutNotebook, proportion = 1,
+                  flag = wx.EXPAND | wx.ALL, border = 1)
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALL | wx.ALIGN_RIGHT, border = 1)
+        panel.SetSizer(sizer)
+        self.Layout()
+    
+    def _pageCopyright(self):
+        """Copyright information"""
+        copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
+        if os.path.exists(copyfile):
+            copyrightFile = open(copyfile, 'r')
+            copytext = copyrightFile.read()
+            copyrightFile.close()
+        else:
+            copytext = _('%s file missing') % 'COPYING'
+        
+        # put text into a scrolling panel
+        copyrightwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
+                                              size = wx.DefaultSize,
+                                              style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+        copyrighttxt = wx.StaticText(copyrightwin, id = wx.ID_ANY, label = copytext)
+        copyrightwin.SetAutoLayout(True)
+        copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
+        copyrightwin.sizer.Add(item = copyrighttxt, proportion = 1,
+                               flag = wx.EXPAND | wx.ALL, border = 3)
+        copyrightwin.SetSizer(copyrightwin.sizer)
+        copyrightwin.Layout()
+        copyrightwin.SetupScrolling()
+        
+        return copyrightwin
+    
+    def _pageLicense(self):
+        """Licence about"""
+        licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
+        if os.path.exists(licfile):
+            licenceFile = open(licfile, 'r')
+            license = ''.join(licenceFile.readlines())
+            licenceFile.close()
+        else:
+            license = _('%s file missing') % 'GPL.TXT'
+        # put text into a scrolling panel
+        licensewin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
+                                            style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+        licensetxt = wx.StaticText(licensewin, id = wx.ID_ANY, label = license)
+        licensewin.SetAutoLayout(True)
+        licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
+        licensewin.sizer.Add(item = licensetxt, proportion = 1,
+                flag = wx.EXPAND | wx.ALL, border = 3)
+        licensewin.SetSizer(licensewin.sizer)
+        licensewin.Layout()
+        licensewin.SetupScrolling()
+        
+        return licensewin
+    
+    def _pageCredit(self):
+        """Credit about"""
+                # credits
+        authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
+        if os.path.exists(authfile):
+            authorsFile = open(authfile, 'r')
+            authors = unicode(''.join(authorsFile.readlines()), "utf-8")
+            authorsFile.close()
+        else:
+            authors = _('%s file missing') % 'AUTHORS'
+        authorwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
+                                           style  =  wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+        authortxt = wx.StaticText(authorwin, id = wx.ID_ANY, label = authors)
+        authorwin.SetAutoLayout(1)
+        authorwin.SetupScrolling()
+        authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
+        authorwin.sizer.Add(item = authortxt, proportion = 1,
+                flag = wx.EXPAND | wx.ALL, border = 3)
+        authorwin.SetSizer(authorwin.sizer)
+        authorwin.Layout()      
+        
+        return authorwin
+
+    def _pageContributors(self, extra = False):
+        """Contributors info"""
+        if extra:
+            contribfile = os.path.join(os.getenv("GISBASE"), "contributors_extra.csv")
+        else:
+            contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
+        if os.path.exists(contribfile):
+            contribFile = codecs.open(contribfile, encoding = 'utf-8', mode = 'r')
+            contribs = list()
+            errLines = list()
+            for line in contribFile.readlines()[1:]:
+                line = line.rstrip('\n')
+                try:
+                    if extra:
+                        name, email, rfc2_agreed = line.split(',')
+                    else:
+                        cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
+                except ValueError:
+                    errLines.append(line)
+                    continue
+                if extra:
+                    contribs.append((name, email))
+                else:
+                    contribs.append((name, email, country, osgeo_id))
+            
+            contribFile.close()
+            
+            if errLines:
+                GError(parent = self,
+                       message = _("Error when reading file '%s'.") % contribfile + \
+                           "\n\n" + _("Lines:") + " %s" % \
+                           os.linesep.join(map(utils.DecodeString, errLines)))
+        else:
+            contribs = None
+        
+        contribwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
+                                           style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+        contribwin.SetAutoLayout(True)
+        contribwin.SetupScrolling()
+        contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        if not contribs:
+            contribtxt = wx.StaticText(contribwin, id = wx.ID_ANY,
+                                       label = _('%s file missing') % contribfile)
+            contribwin.sizer.Add(item = contribtxt, proportion = 1,
+                                 flag = wx.EXPAND | wx.ALL, border = 3)
+        else:
+            if extra:
+                items = (_('Name'), _('E-mail'))
+            else:
+                items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
+            contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
+            for item in items:
+                contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
+                                                    label = item))
+            for vals in sorted(contribs, key = lambda x: x[0]):
+                for item in vals:
+                    contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
+                                                        label = item))
+            contribwin.sizer.Add(item = contribBox, proportion = 1,
+                                 flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        contribwin.SetSizer(contribwin.sizer)
+        contribwin.Layout()      
+        
+        return contribwin
+
+    def _pageTranslators(self):
+        """Translators info"""
+        translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
+        if os.path.exists(translatorsfile):
+            translatorsFile = open(translatorsfile, 'r')
+            translators = dict()
+            errLines = list()
+            for line in translatorsFile.readlines()[1:]:
+                line = line.rstrip('\n')
+                try:
+                    name, email, languages = line.split(',')
+                except ValueError:
+                    errLines.append(line)
+                    continue
+                for language in languages.split(' '):
+                    if language not in translators:
+                        translators[language] = list()
+                    translators[language].append((name, email))
+            translatorsFile.close()
+            
+            if errLines:
+                GError(parent = self,
+                       message = _("Error when reading file '%s'.") % translatorsfile + \
+                           "\n\n" + _("Lines:") + " %s" % \
+                           os.linesep.join(map(utils.DecodeString, errLines)))
+        else:
+            translators = None
+        
+        translatorswin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
+                                           style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+        translatorswin.SetAutoLayout(1)
+        translatorswin.SetupScrolling()
+        translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        if not translators:
+            translatorstxt = wx.StaticText(translatorswin, id = wx.ID_ANY,
+                                           label = _('%s file missing') % 'translators.csv')
+            translatorswin.sizer.Add(item = translatorstxt, proportion = 1,
+                                 flag = wx.EXPAND | wx.ALL, border = 3)
+        else:
+            translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
+            languages = translators.keys()
+            languages.sort()
+            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                    label = _('Name')))
+            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                    label = _('E-mail')))
+            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                    label = _('Language')))
+            for lang in languages:
+                for translator in translators[lang]:
+                    name, email = translator
+                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                            label =  unicode(name, "utf-8")))
+                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                            label = email))
+                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+                                                            label = lang))
+            
+            translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
+                                 flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        translatorswin.SetSizer(translatorswin.sizer)
+        translatorswin.Layout()      
+        
+        return translatorswin
+    
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        self.Close()
+
+class InstallExtensionWindow(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _("Fetch & install extension from GRASS Addons"), **kwargs):
+        self.parent = parent
+        self.options = dict() # list of options
+        
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+        self.repoBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Repository"))
+        self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = " %s " % _("List of extensions"))
+        
+        self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
+        self.fullDesc = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("Fetch full info including description and keywords (takes time)"))
+        self.fullDesc.SetValue(True)
+        
+        self.search = SearchModuleWindow(parent = self.panel)
+        self.search.SetSelection(0) 
+        
+        self.tree   = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
+        
+        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                      label = " %s " % _("Options"))
+        task = gtask.parse_interface('g.extension')
+        for f in task.get_options()['flags']:
+            name = f.get('name', '')
+            desc = f.get('label', '')
+            if not desc:
+                desc = f.get('description', '')
+            if not name and not desc:
+                continue
+            if name in ('l', 'c', 'g', 'quiet', 'verbose'):
+                continue
+            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                             label = desc)
+        self.repo.SetValue(task.get_param(value = 'svnurl').get('default',
+                                                                'http://svn.osgeo.org/grass/grass-addons/grass7'))
+        
+        self.statusbar = self.CreateStatusBar(number = 1)
+        
+        self.btnFetch = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                  label = _("&Fetch"))
+        self.btnFetch.SetToolTipString(_("Fetch list of available modules from GRASS Addons SVN repository"))
+        self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+        self.btnInstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                    label = _("&Install"))
+        self.btnInstall.SetToolTipString(_("Install selected add-ons GRASS module"))
+        self.btnInstall.Enable(False)
+        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                label = _("Command dialog"))
+        self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
+
+        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+        self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
+        self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
+        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
+        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
+        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
+        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
+
+        self._layout()
+
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        repoSizer = wx.StaticBoxSizer(self.repoBox, wx.VERTICAL)
+        repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
+        repo1Sizer.Add(item = self.repo, proportion = 1,
+                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
+        repo1Sizer.Add(item = self.btnFetch, proportion = 0,
+                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
+        repoSizer.Add(item = repo1Sizer,
+                      flag = wx.EXPAND)
+        repoSizer.Add(item = self.fullDesc)
+        
+        findSizer = wx.BoxSizer(wx.HORIZONTAL)
+        findSizer.Add(item = self.search, proportion = 1)
+        
+        treeSizer = wx.StaticBoxSizer(self.treeBox, wx.HORIZONTAL)
+        treeSizer.Add(item = self.tree, proportion = 1,
+                      flag = wx.ALL | wx.EXPAND, border = 1)
+
+        # options
+        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
+        for key in self.options.keys():
+            optionSizer.Add(item = self.options[key], proportion = 0)
+        
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = self.btnCmd, proportion = 0,
+                     flag = wx.RIGHT, border = 5)
+        btnSizer.AddSpacer(10)
+        btnSizer.Add(item = self.btnClose, proportion = 0,
+                     flag = wx.RIGHT, border = 5)
+        btnSizer.Add(item = self.btnInstall, proportion = 0)
+        
+        sizer.Add(item = repoSizer, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        sizer.Add(item = findSizer, proportion = 0,
+                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        sizer.Add(item = treeSizer, proportion = 1,
+                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        sizer.Add(item = optionSizer, proportion = 0,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        
+        self.Layout()
+
+    def _getCmd(self):
+        item = self.tree.GetSelected()
+        if not item or not item.IsOk():
+            return ['g.extension']
+        
+        name = self.tree.GetItemText(item)
+        if not name:
+            GError(_("Extension not defined"), parent = self)
+            return
+        
+        flags = list()
+        for key in self.options.keys():
+            if self.options[key].IsChecked():
+                flags.append('-%s' % key)
+        
+        return ['g.extension'] + flags + ['extension=' + name,
+                                          'svnurl=' + self.repo.GetValue().strip()]
+    
+    def OnUpdateStatusBar(self, event):
+        """!Update statusbar text"""
+        element = self.search.GetSelection()
+        if not self.tree.IsLoaded():
+            self.SetStatusText(_("Fetch list of available extensions by clicking on 'Fetch' button"), 0)
+            return
+        
+        self.tree.SearchItems(element = element,
+                              value = event.GetString())
+        
+        nItems = len(self.tree.itemsMarked)
+        if event.GetString():
+            self.SetStatusText(_("%d items match") % nItems, 0)
+        else:
+            self.SetStatusText("", 0)
+        
+        event.Skip()
+    
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        self.Destroy()
+
+    def OnFetch(self, event):
+        """!Fetch list of available extensions"""
+        wx.BeginBusyCursor()
+        self.SetStatusText(_("Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
+        self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
+        self.SetStatusText("", 0)
+        wx.EndBusyCursor()
+
+    def OnItemActivated(self, event):
+        item = event.GetItem()
+        data = self.tree.GetPyData(item)
+        if data and 'command' in data:
+            self.OnInstall(event = None)
+        
+    def OnInstall(self, event):
+        """!Install selected extension"""
+        log = self.parent.GetLogWindow()
+        log.RunCmd(self._getCmd(), onDone = self.OnDone)
+        
+    def OnDone(self, cmd, returncode):
+        item = self.tree.GetSelected()
+        if not item or not item.IsOk() or \
+                returncode != 0 or \
+                not os.getenv('GRASS_ADDON_PATH'):
+            return
+        
+        name = self.tree.GetItemText(item)
+        globalvar.grassCmd['all'].append(name)
+        
+    def OnItemSelected(self, event):
+        """!Item selected"""
+        item = event.GetItem()
+        self.tree.itemSelected = item
+        data = self.tree.GetPyData(item)
+        if not data:
+            self.SetStatusText('', 0)
+            self.btnInstall.Enable(False)
+        else:
+            self.SetStatusText(data.get('description', ''), 0)
+            self.btnInstall.Enable(True)
+
+    def OnShowItem(self, event):
+        """!Show selected item"""
+        self.tree.OnShowItem(event)
+        if self.tree.GetSelected():
+            self.btnInstall.Enable()
+        else:
+            self.btnInstall.Enable(False)
+
+    def OnCmdDialog(self, event):
+        """!Shows command dialog"""
+        GUI(parent = self).ParseCommand(cmd = self._getCmd())
+        
+class ExtensionTree(ItemTree):
+    """!List of available extensions"""
+    def __init__(self, parent, log, id = wx.ID_ANY,
+                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
+                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
+                 **kwargs):
+        self.parent = parent # GMFrame
+        self.log    = log
+        
+        super(ExtensionTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
+        
+        self._initTree()
+        
+    def _initTree(self):
+        for prefix in ('display', 'database',
+                       'general', 'imagery',
+                       'misc', 'postscript', 'paint',
+                       'raster', 'raster3D', 'sites', 'vector', 'wxGUI', 'other'):
+            self.AppendItem(parentId = self.root,
+                            text = prefix)
+        self._loaded = False
+        
+    def _expandPrefix(self, c):
+        name = { 'd'  : 'display',
+                 'db' : 'database',
+                 'g'  : 'general',
+                 'i'  : 'imagery',
+                 'm'  : 'misc',
+                 'ps' : 'postscript',
+                 'p'  : 'paint',
+                 'r'  : 'raster',
+                 'r3' : 'raster3D',
+                 's'  : 'sites',
+                 'v'  : 'vector',
+                 'wx' : 'wxGUI',
+                 'u'  : 'other' }
+        
+        if c in name:
+            return name[c]
+        
+        return c
+    
+    def _findItem(self, text):
+        """!Find item"""
+        item = self.GetFirstChild(self.root)[0]
+        while item and item.IsOk():
+            if text == self.GetItemText(item):
+                return item
+            
+            item = self.GetNextSibling(item)
+        
+        return None
+    
+    def Load(self, url, full = False):
+        """!Load list of extensions"""
+        self.DeleteAllItems()
+        self.root = self.AddRoot(_("Menu tree"))
+        self._initTree()
+        
+        if full:
+            flags = 'g'
+        else:
+            flags = 'l'
+        ret = RunCommand('g.extension', read = True,
+                         svnurl = url,
+                         flags = flags, quiet = True)
+        if not ret:
+            return
+        
+        mdict = dict()
+        for line in ret.splitlines():
+            if full:
+                key, value = line.split('=', 1)
+                if key == 'name':
+                    try:
+                        prefix, name = value.split('.', 1)
+                    except ValueError:
+                        prefix = 'u'
+                        name = value
+                    if prefix not in mdict:
+                        mdict[prefix] = dict()
+                    mdict[prefix][name] = dict()
+                else:
+                    mdict[prefix][name][key] = value
+            else:
+                try:
+                    prefix, name = line.strip().split('.', 1)
+                except:
+                    prefix = 'unknown'
+                    name = line.strip()
+                
+                if self._expandPrefix(prefix) == prefix:
+                    prefix = 'unknown'
+                    
+                if prefix not in mdict:
+                    mdict[prefix] = dict()
+                    
+                mdict[prefix][name] = { 'command' : prefix + '.' + name }
+        
+        for prefix in mdict.keys():
+            prefixName = self._expandPrefix(prefix)
+            item = self._findItem(prefixName)
+            names = mdict[prefix].keys()
+            names.sort()
+            for name in names:
+                new = self.AppendItem(parentId = item,
+                                      text = prefix + '.' + name)
+                data = dict()
+                for key in mdict[prefix][name].keys():
+                    data[key] = mdict[prefix][name][key]
+                
+                self.SetPyData(new, data)
+        
+        self._loaded = True
+
+    def IsLoaded(self):
+        """Check if items are loaded"""
+        return self._loaded
+
+class HelpWindow(wx.html.HtmlWindow):
+    """!This panel holds the text from GRASS docs.
+    
+    GISBASE must be set in the environment to find the html docs dir.
+    The SYNOPSIS section is skipped, since this Panel is supposed to
+    be integrated into the cmdPanel and options are obvious there.
+    """
+    def __init__(self, parent, grass_command, text, skip_description,
+                 **kwargs):
+        """!If grass_command is given, the corresponding HTML help
+        file will be presented, with all links pointing to absolute
+        paths of local files.
+
+        If 'skip_description' is True, the HTML corresponding to
+        SYNOPSIS will be skipped, thus only presenting the help file
+        from the DESCRIPTION section onwards.
+
+        If 'text' is given, it must be the HTML text to be presented
+        in the Panel.
+        """
+        self.parent = parent
+        wx.InitAllImageHandlers()
+        wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
+        
+        gisbase = os.getenv("GISBASE")
+        self.loaded = False
+        self.history = list()
+        self.historyIdx = 0
+        self.fspath = os.path.join(gisbase, "docs", "html")
+        
+        self.SetStandardFonts (size = 10)
+        self.SetBorders(10)
+        
+        if text is None:
+            if skip_description:
+                url = os.path.join(self.fspath, grass_command + ".html")
+                self.fillContentsFromFile(url,
+                                          skip_description = skip_description)
+                self.history.append(url)
+                self.loaded = True
+            else:
+                ### FIXME: calling LoadPage() is strangely time-consuming (only first call)
+                # self.LoadPage(self.fspath + grass_command + ".html")
+                self.loaded = False
+        else:
+            self.SetPage(text)
+            self.loaded = True
+        
+    def OnLinkClicked(self, linkinfo):
+        url = linkinfo.GetHref()
+        if url[:4] != 'http':
+            url = os.path.join(self.fspath, url)
+        self.history.append(url)
+        self.historyIdx += 1
+        self.parent.OnHistory()
+        
+        super(HelpWindow, self).OnLinkClicked(linkinfo)
+        
+    def fillContentsFromFile(self, htmlFile, skip_description = True):
+        """!Load content from file"""
+        aLink = re.compile(r'(<a href="?)(.+\.html?["\s]*>)', re.IGNORECASE)
+        imgLink = re.compile(r'(<img src="?)(.+\.[png|gif])', re.IGNORECASE)
+        try:
+            contents = []
+            skip = False
+            for l in file(htmlFile, "rb").readlines():
+                if "DESCRIPTION" in l:
+                    skip = False
+                if not skip:
+                    # do skip the options description if requested
+                    if "SYNOPSIS" in l:
+                        skip = skip_description
+                    else:
+                        # FIXME: find only first item
+                        findALink = aLink.search(l)
+                        if findALink is not None: 
+                            contents.append(aLink.sub(findALink.group(1)+
+                                                      self.fspath+findALink.group(2),l))
+                        findImgLink = imgLink.search(l)
+                        if findImgLink is not None: 
+                            contents.append(imgLink.sub(findImgLink.group(1)+
+                                                        self.fspath+findImgLink.group(2),l))
+                        
+                        if findALink is None and findImgLink is None:
+                            contents.append(l)
+            self.SetPage("".join(contents))
+            self.loaded = True
+        except: # The Manual file was not found
+            self.loaded = False
+        
+class HelpPanel(wx.Panel):
+    def __init__(self, parent, grass_command = "index", text = None,
+                 skip_description = False, **kwargs):
+        self.grass_command = grass_command
+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
+        
+        self.content = HelpWindow(self, grass_command, text,
+                                  skip_description)
+        
+        self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
+                                 label = _("&Next"))
+        self.btnNext.Enable(False)
+        self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
+                                 label = _("&Previous"))
+        self.btnPrev.Enable(False)
+        
+        self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
+        self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
+        
+        self._layout()
+
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        btnSizer.Add(item = self.btnPrev, proportion = 0,
+                     flag = wx.ALL, border = 5)
+        btnSizer.Add(item = wx.Size(1, 1), proportion = 1)
+        btnSizer.Add(item = self.btnNext, proportion = 0,
+                     flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        
+        sizer.Add(item = self.content, proportion = 1,
+                  flag = wx.EXPAND)
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.EXPAND)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def LoadPage(self, path = None):
+        """!Load page"""
+        if not path:
+            path = os.path.join(self.content.fspath, self.grass_command + ".html")
+        self.content.history.append(path)
+        self.content.LoadPage(path)
+        
+    def IsFile(self):
+        """!Check if file exists"""
+        return os.path.isfile(os.path.join(self.content.fspath, self.grass_command + ".html"))
+
+    def IsLoaded(self):
+        return self.content.loaded
+
+    def OnHistory(self):
+        """!Update buttons"""
+        nH = len(self.content.history)
+        iH = self.content.historyIdx
+        if iH == nH - 1:
+            self.btnNext.Enable(False)
+        elif iH > -1:
+            self.btnNext.Enable(True)
+        if iH < 1:
+            self.btnPrev.Enable(False)
+        else:
+            self.btnPrev.Enable(True)
+
+    def OnNext(self, event):
+        """Load next page"""
+        self.content.historyIdx += 1
+        idx = self.content.historyIdx
+        path = self.content.history[idx]
+        self.content.LoadPage(path)
+        self.OnHistory()
+        
+        event.Skip()
+        
+    def OnPrev(self, event):
+        """Load previous page"""
+        self.content.historyIdx -= 1
+        idx = self.content.historyIdx
+        path = self.content.history[idx]
+        self.content.LoadPage(path)
+        self.OnHistory()
+        
+        event.Skip()

Copied: grass/trunk/gui/wxpython/gui_core/goutput.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/goutput.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/goutput.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/goutput.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1154 @@
+"""!
+ at package gui_core.goutput
+
+ at brief Command output widgets
+
+Classes:
+ - CmdThread
+ - GMConsole
+ - GMStc
+ - GMStdout
+ - GMStderr
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
+"""
+
+import os
+import sys
+import textwrap
+import time
+import threading
+import Queue
+import codecs
+import locale
+
+import wx
+import wx.stc
+from wx.lib.newevent import NewEvent
+
+import grass.script as grass
+from   grass.script import task as gtask
+
+from core            import globalvar
+from core            import utils
+from core.gcmd       import CommandThread, GMessage, GError, GException, EncodeString
+from gui_core.forms  import GUI
+from gui_core.prompt import GPromptSTC
+from core.debug      import Debug
+from core.settings   import UserSettings, Settings
+from gui_core.ghelp  import SearchModuleWindow
+
+wxCmdOutput,   EVT_CMD_OUTPUT   = NewEvent()
+wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
+wxCmdRun,      EVT_CMD_RUN      = NewEvent()
+wxCmdDone,     EVT_CMD_DONE     = NewEvent()
+wxCmdAbort,    EVT_CMD_ABORT    = NewEvent()
+wxCmdPrepare,  EVT_CMD_PREPARE  = NewEvent()
+
+def GrassCmd(cmd, stdout = None, stderr = None):
+    """!Return GRASS command thread"""
+    return CommandThread(cmd,
+                         stdout = stdout, stderr = stderr)
+
+class CmdThread(threading.Thread):
+    """!Thread for GRASS commands"""
+    requestId = 0
+    def __init__(self, parent, requestQ, resultQ, **kwds):
+        threading.Thread.__init__(self, **kwds)
+
+        self.setDaemon(True)
+
+        self.parent = parent # GMConsole
+        self._want_abort_all = False
+        
+        self.requestQ = requestQ
+        self.resultQ = resultQ
+
+        self.start()
+
+    def RunCmd(self, *args, **kwds):
+        CmdThread.requestId += 1
+        
+        self.requestCmd = None
+        self.requestQ.put((CmdThread.requestId, args, kwds))
+        
+        return CmdThread.requestId
+
+    def SetId(self, id):
+        """!Set starting id"""
+        CmdThread.requestId = id
+        
+    def run(self):
+        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
+        while True:
+            requestId, args, kwds = self.requestQ.get()
+            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
+                if key in kwds:
+                    vars()[key] = kwds[key]
+                    del kwds[key]
+                else:
+                    vars()[key] = None
+            
+            if not vars()['callable']:
+                vars()['callable'] = GrassCmd
+            
+            requestTime = time.time()
+            
+            # prepare
+            event = wxCmdPrepare(cmd = args[0],
+                                 time = requestTime,
+                                 pid = requestId,
+                                 onPrepare = vars()['onPrepare'],
+                                 userData = vars()['userData'])
+            wx.PostEvent(self.parent, event)
+            
+            # run command
+            event = wxCmdRun(cmd = args[0],
+                             pid = requestId)
+            
+            wx.PostEvent(self.parent, event)
+            
+            time.sleep(.1)
+            self.requestCmd = vars()['callable'](*args, **kwds)
+            if self._want_abort_all:
+                self.requestCmd.abort()
+                if self.requestQ.empty():
+                    self._want_abort_all = False
+            
+            self.resultQ.put((requestId, self.requestCmd.run()))
+            
+            try:
+                returncode = self.requestCmd.module.returncode
+            except AttributeError:
+                returncode = 0 # being optimistic
+            
+            try:
+                aborted = self.requestCmd.aborted
+            except AttributeError:
+                aborted = False
+            
+            time.sleep(.1)
+
+            # set default color table for raster data
+            if UserSettings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'enabled') and \
+                    args[0][0][:2] == 'r.':
+                colorTable = UserSettings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'selection')
+                mapName = None
+                if args[0][0] == 'r.mapcalc':
+                    try:
+                        mapName = args[0][1].split('=', 1)[0].strip()
+                    except KeyError:
+                        pass
+                else:
+                    moduleInterface = GUI(show = None).ParseCommand(args[0])
+                    outputParam = moduleInterface.get_param(value = 'output', raiseError = False)
+                    if outputParam and outputParam['prompt'] == 'raster':
+                        mapName = outputParam['value']
+                
+                if mapName:
+                    argsColor = list(args)
+                    argsColor[0] = [ 'r.colors',
+                                     'map=%s' % mapName,
+                                     'color=%s' % colorTable ]
+                    self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
+                    self.resultQ.put((requestId, self.requestCmdColor.run()))
+            
+            event = wxCmdDone(cmd = args[0],
+                              aborted = aborted,
+                              returncode = returncode,
+                              time = requestTime,
+                              pid = requestId,
+                              onDone = vars()['onDone'],
+                              userData = vars()['userData'])
+            
+            # send event
+            wx.PostEvent(self.parent, event)
+            
+    def abort(self, abortall = True):
+        """!Abort command(s)"""
+        if abortall:
+            self._want_abort_all = True
+        self.requestCmd.abort()
+        if self.requestQ.empty():
+            self._want_abort_all = False
+        
+class GMConsole(wx.SplitterWindow):
+    """!Create and manage output console for commands run by GUI.
+    """
+    def __init__(self, parent, id = wx.ID_ANY, margin = False,
+                 notebook = None,
+                 style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
+                 **kwargs):
+        wx.SplitterWindow.__init__(self, parent, id, style = style, *kwargs)
+        self.SetName("GMConsole")
+        
+        self.panelOutput = wx.Panel(parent = self, id = wx.ID_ANY)
+        self.panelPrompt = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        # initialize variables
+        self.parent          = parent # GMFrame | CmdPanel | ?
+        if notebook:
+            self._notebook = notebook
+        else:
+            self._notebook = self.parent.notebook
+        self.lineWidth       = 80
+        
+        # remember position of line begining (used for '\r')
+        self.linePos         = -1
+        
+        # create queues
+        self.requestQ = Queue.Queue()
+        self.resultQ = Queue.Queue()
+        
+        # progress bar
+        self.progressbar = wx.Gauge(parent = self.panelOutput, id = wx.ID_ANY,
+                                    range = 100, pos = (110, 50), size = (-1, 25),
+                                    style = wx.GA_HORIZONTAL)
+        self.progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
+        
+        # text control for command output
+        self.cmdOutput = GMStc(parent = self.panelOutput, id = wx.ID_ANY, margin = margin,
+                               wrap = None) 
+        self.cmdOutputTimer = wx.Timer(self.cmdOutput, id = wx.ID_ANY)
+        self.cmdOutput.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
+        self.cmdOutput.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
+        self.Bind(EVT_CMD_RUN,     self.OnCmdRun)
+        self.Bind(EVT_CMD_DONE,    self.OnCmdDone)
+        self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
+        
+        # search & command prompt
+        self.cmdPrompt = GPromptSTC(parent = self)
+        
+        if self.parent.GetName() != 'LayerManager':
+            self.search = None
+            self.cmdPrompt.Hide()
+        else:
+            self.infoCollapseLabelExp = _("Click here to show search module engine")
+            self.infoCollapseLabelCol = _("Click here to hide search module engine")
+            self.searchPane = wx.CollapsiblePane(parent = self.panelOutput,
+                                                 label = self.infoCollapseLabelExp,
+                                                 style = wx.CP_DEFAULT_STYLE |
+                                                 wx.CP_NO_TLW_RESIZE | wx.EXPAND)
+            self.MakeSearchPaneContent(self.searchPane.GetPane())
+            self.searchPane.Collapse(True)
+            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSearchPaneChanged, self.searchPane) 
+            self.search.Bind(wx.EVT_TEXT,             self.OnUpdateStatusBar)
+        
+        # stream redirection
+        self.cmdStdOut = GMStdout(self)
+        self.cmdStdErr = GMStderr(self)
+        
+        # thread
+        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
+        
+        self.outputBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
+                                      label = " %s " % _("Output window"))
+        self.cmdBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
+                                   label = " %s " % _("Command prompt"))
+        
+        # buttons
+        self.btnOutputClear = wx.Button(parent = self.panelOutput, id = wx.ID_CLEAR)
+        self.btnOutputClear.SetToolTipString(_("Clear output window content"))
+        self.btnCmdClear = wx.Button(parent = self.panelOutput, id = wx.ID_CLEAR)
+        self.btnCmdClear.SetToolTipString(_("Clear command prompt content"))
+        if self.parent.GetName() != 'LayerManager':
+            self.btnCmdClear.Hide()
+        self.btnOutputSave  = wx.Button(parent = self.panelOutput, id = wx.ID_SAVE)
+        self.btnOutputSave.SetToolTipString(_("Save output window content to the file"))
+        # abort
+        self.btnCmdAbort = wx.Button(parent = self.panelOutput, id = wx.ID_STOP)
+        self.btnCmdAbort.SetToolTipString(_("Abort running command"))
+        self.btnCmdAbort.Enable(False)
+        
+        self.btnCmdClear.Bind(wx.EVT_BUTTON,     self.cmdPrompt.OnCmdErase)
+        self.btnOutputClear.Bind(wx.EVT_BUTTON,  self.ClearHistory)
+        self.btnOutputSave.Bind(wx.EVT_BUTTON,   self.SaveHistory)
+        self.btnCmdAbort.Bind(wx.EVT_BUTTON,     self.OnCmdAbort)
+        self.btnCmdAbort.Bind(EVT_CMD_ABORT,     self.OnCmdAbort)
+        
+        self._layout()
+        
+    def _layout(self):
+        """!Do layout"""
+        outputSizer = wx.BoxSizer(wx.VERTICAL)
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        outBtnSizer = wx.StaticBoxSizer(self.outputBox, wx.HORIZONTAL)
+        cmdBtnSizer = wx.StaticBoxSizer(self.cmdBox, wx.HORIZONTAL)
+        
+        if self.cmdPrompt.IsShown():
+            promptSizer = wx.BoxSizer(wx.VERTICAL)
+            promptSizer.Add(item = self.cmdPrompt, proportion = 1,
+                        flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
+        
+        if self.search and self.search.IsShown():
+            outputSizer.Add(item = self.searchPane, proportion = 0,
+                            flag = wx.EXPAND | wx.ALL, border = 3)
+        outputSizer.Add(item = self.cmdOutput, proportion = 1,
+                        flag = wx.EXPAND | wx.ALL, border = 3)
+        outputSizer.Add(item = self.progressbar, proportion = 0,
+                        flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+        outBtnSizer.Add(item = self.btnOutputClear, proportion = 1,
+                        flag = wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, border = 5)
+        outBtnSizer.Add(item = self.btnOutputSave, proportion = 1,
+                        flag = wx.ALIGN_RIGHT | wx.RIGHT, border = 5)
+        
+        cmdBtnSizer.Add(item = self.btnCmdClear, proportion = 1,
+                        flag = wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border = 5)
+        cmdBtnSizer.Add(item = self.btnCmdAbort, proportion = 1,
+                        flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
+        
+        btnSizer.Add(item = outBtnSizer, proportion = 1,
+                     flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
+        btnSizer.Add(item = cmdBtnSizer, proportion = 1,
+                     flag = wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
+        outputSizer.Add(item = btnSizer, proportion = 0,
+                        flag = wx.EXPAND)
+        
+        outputSizer.Fit(self)
+        outputSizer.SetSizeHints(self)
+        self.panelOutput.SetSizer(outputSizer)
+        
+        if self.cmdPrompt.IsShown():
+            promptSizer.Fit(self)
+            promptSizer.SetSizeHints(self)
+            self.panelPrompt.SetSizer(promptSizer)
+        
+        # split window
+        if self.cmdPrompt.IsShown():
+            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -50)
+        else:
+            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -45)
+            self.Unsplit()
+        self.SetMinimumPaneSize(self.btnCmdClear.GetSize()[1] + 25)
+        
+        self.SetSashGravity(1.0)
+        
+        # layout
+        self.SetAutoLayout(True)
+        self.Layout()
+
+    def MakeSearchPaneContent(self, pane):
+        """!Create search pane"""
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        self.search = SearchModuleWindow(parent = pane, cmdPrompt = self.cmdPrompt)
+        
+        border.Add(item = self.search, proportion = 0,
+                   flag = wx.EXPAND | wx.ALL, border = 1)
+        
+        pane.SetSizer(border)
+        border.Fit(pane)
+        
+    def OnSearchPaneChanged(self, event):
+        """!Collapse search module box"""
+        if self.searchPane.IsExpanded():
+            self.searchPane.SetLabel(self.infoCollapseLabelCol)
+        else:
+            self.searchPane.SetLabel(self.infoCollapseLabelExp)
+        
+        self.panelOutput.Layout()
+        self.panelOutput.SendSizeEvent()
+        
+    def GetPanel(self, prompt = True):
+        """!Get panel
+
+        @param prompt get prompt / output panel
+
+        @return wx.Panel reference
+        """
+        if prompt:
+            return self.panelPrompt
+
+        return self.panelOutput
+    
+    def Redirect(self):
+        """!Redirect stdout/stderr
+        """
+        if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
+            # don't redirect when debugging is enabled
+            sys.stdout = self.cmdStdOut
+            sys.stderr = self.cmdStdErr
+        else:
+            enc = locale.getdefaultlocale()[1]
+            if enc:
+                sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
+                sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
+            else:
+                sys.stdout = sys.__stdout__
+                sys.stderr = sys.__stderr__
+        
+    def WriteLog(self, text, style = None, wrap = None,
+                 switchPage = False):
+        """!Generic method for writing log message in 
+        given style
+
+        @param line text line
+        @param style text style (see GMStc)
+        @param stdout write to stdout or stderr
+        """
+
+        self.cmdOutput.SetStyle()
+
+        if switchPage:
+            self._notebook.SetSelectionByName('output')
+        
+        if not style:
+            style = self.cmdOutput.StyleDefault
+        
+        # p1 = self.cmdOutput.GetCurrentPos()
+        p1 = self.cmdOutput.GetEndStyled()
+        # self.cmdOutput.GotoPos(p1)
+        self.cmdOutput.DocumentEnd()
+        
+        for line in text.splitlines():
+            # fill space
+            if len(line) < self.lineWidth:
+                diff = self.lineWidth - len(line) 
+                line += diff * ' '
+            
+            self.cmdOutput.AddTextWrapped(line, wrap = wrap) # adds '\n'
+            
+            p2 = self.cmdOutput.GetCurrentPos()
+            
+            self.cmdOutput.StartStyling(p1, 0xff)
+            self.cmdOutput.SetStyling(p2 - p1, style)
+        
+        self.cmdOutput.EnsureCaretVisible()
+        
+    def WriteCmdLog(self, line, pid = None, switchPage = True):
+        """!Write message in selected style
+        
+        @param line message to be printed
+        @param pid process pid or None
+        @param switchPage True to switch page
+        """
+        if pid:
+            line = '(' + str(pid) + ') ' + line
+        self.WriteLog(line, style = self.cmdOutput.StyleCommand, switchPage = switchPage)
+
+    def WriteWarning(self, line):
+        """!Write message in warning style"""
+        self.WriteLog(line, style = self.cmdOutput.StyleWarning, switchPage = True)
+
+    def WriteError(self, line):
+        """!Write message in error style"""
+        self.WriteLog(line, style = self.cmdOutput.StyleError, switchPage = True)
+
+    def RunCmd(self, command, compReg = True, switchPage = False,
+               onDone = None, onPrepare = None, userData = None):
+        """!Run command typed into console command prompt (GPrompt).
+        
+        @todo Display commands (*.d) are captured and processed
+        separately by mapdisp.py. Display commands are rendered in map
+        display widget that currently has the focus (as indicted by
+        mdidx).
+        
+        @param command command given as a list (produced e.g. by utils.split())
+        @param compReg True use computation region
+        @param switchPage switch to output page
+        @param onDone function to be called when command is finished
+        @param onPrepare function to be called before command is launched
+        @param userData data defined for the command
+        """
+        if len(command) == 0:
+            Debug.msg(2, "GPrompt:RunCmd(): empty command")
+            return 0
+        
+        # update history file
+        env = grass.gisenv()
+        try:
+            fileHistory = codecs.open(os.path.join(env['GISDBASE'],
+                                                   env['LOCATION_NAME'],
+                                                   env['MAPSET'],
+                                                   '.bash_history'),
+                                      encoding = 'utf-8', mode = 'a')
+        except IOError, e:
+            self.WriteError(e)
+            fileHistory = None
+        
+        if fileHistory:
+            try:
+                fileHistory.write(' '.join(command) + os.linesep)
+            finally:
+                fileHistory.close()
+        
+        # update history items
+        if self.parent.GetName() == 'LayerManager':
+            try:
+                self.parent.cmdinput.SetHistoryItems()
+            except AttributeError:
+                pass
+        
+        if command[0] in globalvar.grassCmd['all']:
+            # send GRASS command without arguments to GUI command interface
+            # except display commands (they are handled differently)
+            if self.parent.GetName() == "LayerManager" and \
+                    command[0][0:2] == "d." and \
+                    'help' not in ' '.join(command[1:]):
+                # display GRASS commands
+                try:
+                    layertype = {'d.rast'         : 'raster',
+                                 'd.rast3d'       : '3d-raster',
+                                 'd.rgb'          : 'rgb',
+                                 'd.his'          : 'his',
+                                 'd.shaded'       : 'shaded',
+                                 'd.legend'       : 'rastleg',
+                                 'd.rast.arrow'   : 'rastarrow',
+                                 'd.rast.num'     : 'rastnum',
+                                 'd.rast.leg'     : 'maplegend',
+                                 'd.vect'         : 'vector',
+                                 'd.thematic.area': 'thememap',
+                                 'd.vect.chart'   : 'themechart',
+                                 'd.grid'         : 'grid',
+                                 'd.geodesic'     : 'geodesic',
+                                 'd.rhumbline'    : 'rhumb',
+                                 'd.labels'       : 'labels',
+                                 'd.barscale'     : 'barscale',
+                                 'd.redraw'       : 'redraw'}[command[0]]
+                except KeyError:
+                    GMessage(parent = self.parent,
+                             message = _("Command '%s' not yet implemented in the WxGUI. "
+                                         "Try adding it as a command layer instead.") % command[0])
+                    return 1
+                
+                if layertype == 'barscale':
+                    self.parent.curr_page.maptree.GetMapDisplay().OnAddBarscale(None)
+                elif layertype == 'rastleg':
+                    self.parent.curr_page.maptree.GetMapDisplay().OnAddLegend(None)
+                elif layertype == 'redraw':
+                    self.parent.curr_page.maptree.GetMapDisplay().OnRender(None)
+                else:
+                    # add layer into layer tree
+                    lname, found = utils.GetLayerNameFromCmd(command, fullyQualified = True,
+                                                             layerType = layertype)
+                    if self.parent.GetName() == "LayerManager":
+                        self.parent.curr_page.maptree.AddLayer(ltype = layertype,
+                                                               lname = lname,
+                                                               lcmd = command)
+            
+            else:
+                # other GRASS commands (r|v|g|...)
+                if len(command) == 1 and command[0] != 'v.krige':
+                    # no arguments given
+                    GUI(parent = self).ParseCommand(command)
+                    return 0
+                
+                task = GUI(show = None).ParseCommand(command)
+                if task:
+                    # check for <input>=-
+                    for p in task.get_options()['params']:
+                        if p.get('prompt', '') == 'input' and \
+                                p.get('element', '') == 'file' and \
+                                p.get('age', 'new') == 'old' and \
+                                p.get('value', '') == '-':
+                            GError(parent = self,
+                                   message = _("Unable to run command:\n%(cmd)s\n\n"
+                                               "Option <%(opt)s>: read from standard input is not "
+                                               "supported by wxGUI") % { 'cmd': ' '.join(command),
+                                                                         'opt': p.get('name', '') })
+                            return 1
+                
+                # switch to 'Command output' if required
+                if switchPage:
+                    self._notebook.SetSelectionByName('output')
+                    
+                    self.parent.SetFocus()
+                    self.parent.Raise()
+                
+                # activate computational region (set with g.region)
+                # for all non-display commands.
+                if compReg:
+                    tmpreg = os.getenv("GRASS_REGION")
+                    if "GRASS_REGION" in os.environ:
+                        del os.environ["GRASS_REGION"]
+                
+                # process GRASS command with argument
+                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
+                                      onDone = onDone, onPrepare = onPrepare, userData = userData)
+                self.cmdOutputTimer.Start(50)
+                
+                # deactivate computational region and return to display settings
+                if compReg and tmpreg:
+                    os.environ["GRASS_REGION"] = tmpreg
+        else:
+            # Send any other command to the shell. Send output to
+            # console output window
+            if len(command) == 1:
+                try:
+                    task = gtask.parse_interface(command[0])
+                except:
+                    task = None
+            else:
+                task = None
+                
+            if task:
+                # process GRASS command without argument
+                GUI(parent = self).ParseCommand(command)
+            else:
+                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
+                                      onDone = onDone, onPrepare = onPrepare, userData = userData)
+            self.cmdOutputTimer.Start(50)
+        
+        return 0
+
+    def ClearHistory(self, event):
+        """!Clear history of commands"""
+        self.cmdOutput.SetReadOnly(False)
+        self.cmdOutput.ClearAll()
+        self.cmdOutput.SetReadOnly(True)
+        self.progressbar.SetValue(0)
+
+    def GetProgressBar(self):
+        """!Return progress bar widget"""
+        return self.progressbar
+    
+    def GetLog(self, err = False):
+        """!Get widget used for logging
+
+        @param err True to get stderr widget
+        """
+        if err:
+            return self.cmdStdErr
+        
+        return self.cmdStdOut
+    
+    def SaveHistory(self, event):
+        """!Save history of commands"""
+        self.history = self.cmdOutput.GetSelectedText()
+        if self.history == '':
+            self.history = self.cmdOutput.GetText()
+
+        # add newline if needed
+        if len(self.history) > 0 and self.history[-1] != '\n':
+            self.history += '\n'
+
+        wildcard = "Text file (*.txt)|*.txt"
+        dlg = wx.FileDialog(self, message = _("Save file as..."), defaultDir = os.getcwd(),
+                            defaultFile = "grass_cmd_history.txt", wildcard = wildcard,
+                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
+
+        # Show the dialog and retrieve the user response. If it is the OK response,
+        # process the data.
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+
+            output = open(path, "w")
+            output.write(self.history)
+            output.close()
+
+        dlg.Destroy()
+
+    def GetCmd(self):
+        """!Get running command or None"""
+        return self.requestQ.get()
+    
+    def SetCopyingOfSelectedText(self, copy):
+        """!Enable or disable copying of selected text in to clipboard.
+        Effects prompt and output.
+        
+        @param copy True for enable, False for disable
+        """
+        if copy:
+            self.cmdPrompt.Bind(wx.stc.EVT_STC_PAINTED, self.cmdPrompt.OnTextSelectionChanged)
+            self.cmdOutput.Bind(wx.stc.EVT_STC_PAINTED, self.cmdOutput.OnTextSelectionChanged)
+        else:
+            self.cmdPrompt.Unbind(wx.stc.EVT_STC_PAINTED)
+            self.cmdOutput.Unbind(wx.stc.EVT_STC_PAINTED)
+        
+    def OnUpdateStatusBar(self, event):
+        """!Update statusbar text"""
+        if event.GetString():
+            nItems = len(self.cmdPrompt.GetCommandItems())
+            self.parent.SetStatusText(_('%d modules match') % nItems, 0)
+        else:
+            self.parent.SetStatusText('', 0)
+        
+        event.Skip()
+
+    def OnCmdOutput(self, event):
+        """!Print command output"""
+        message = event.text
+        type  = event.type
+        if self._notebook.GetSelection() != self._notebook.GetPageIndexByName('output'):
+            page = self._notebook.GetPageIndexByName('output')
+            textP = self._notebook.GetPageText(page)
+            if textP[-1] != ')':
+                textP += ' (...)'
+            self._notebook.SetPageText(page, textP)
+        
+        # message prefix
+        if type == 'warning':
+            messege = 'WARNING: ' + message
+        elif type == 'error':
+            message = 'ERROR: ' + message
+        
+        p1 = self.cmdOutput.GetEndStyled()
+        self.cmdOutput.GotoPos(p1)
+        
+        if '\b' in message:
+            if self.linepos < 0:
+                self.linepos = p1
+            last_c = ''
+            for c in message:
+                if c == '\b':
+                    self.linepos -= 1
+                else:
+                    if c == '\r':
+                        pos = self.cmdOutput.GetCurLine()[1]
+                        # self.cmdOutput.SetCurrentPos(pos)
+                    else:
+                        self.cmdOutput.SetCurrentPos(self.linepos)
+                    self.cmdOutput.ReplaceSelection(c)
+                    self.linepos = self.cmdOutput.GetCurrentPos()
+                    if c != ' ':
+                        last_c = c
+            if last_c not in ('0123456789'):
+                self.cmdOutput.AddTextWrapped('\n', wrap = None)
+                self.linepos = -1
+        else:
+            self.linepos = -1 # don't force position
+            if '\n' not in message:
+                self.cmdOutput.AddTextWrapped(message, wrap = 60)
+            else:
+                self.cmdOutput.AddTextWrapped(message, wrap = None)
+
+        p2 = self.cmdOutput.GetCurrentPos()
+        
+        if p2 >= p1:
+            self.cmdOutput.StartStyling(p1, 0xff)
+        
+            if type == 'error':
+                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleError)
+            elif type == 'warning':
+                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleWarning)
+            elif type == 'message':
+                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleMessage)
+            else: # unknown
+                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleUnknown)
+        
+        self.cmdOutput.EnsureCaretVisible()
+        
+    def OnCmdProgress(self, event):
+        """!Update progress message info"""
+        self.progressbar.SetValue(event.value)
+
+    def OnCmdAbort(self, event):
+        """!Abort running command"""
+        self.cmdThread.abort()
+        
+    def OnCmdRun(self, event):
+        """!Run command"""
+        if self.parent.GetName() == 'Modeler':
+            self.parent.OnCmdRun(event)
+        
+        self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
+        self.btnCmdAbort.Enable()
+
+    def OnCmdPrepare(self, event):
+        """!Prepare for running command"""
+        if self.parent.GetName() == 'Modeler':
+            self.parent.OnCmdPrepare(event)
+        
+        event.Skip()
+        
+    def OnCmdDone(self, event):
+        """!Command done (or aborted)"""
+        if self.parent.GetName() == 'Modeler':
+            self.parent.OnCmdDone(event)
+        
+        if event.aborted:
+            # Thread aborted (using our convention of None return)
+            self.WriteLog(_('Please note that the data are left in inconsistent state '
+                            'and may be corrupted'), self.cmdOutput.StyleWarning)
+            self.WriteCmdLog('(%s) %s (%d sec)' % (str(time.ctime()),
+                                                   _('Command aborted'),
+                                                   (time.time() - event.time)))
+            # pid=self.cmdThread.requestId)
+            self.btnCmdAbort.Enable(False)
+        else:
+            try:
+                # Process results here
+                ctime = time.time() - event.time
+                if ctime < 60:
+                    stime = _("%d sec") % int(ctime)
+                else:
+                    mtime = int(ctime / 60)
+                    stime = _("%d min %d sec") % (mtime, 
+                                                  int(ctime - (mtime * 60)))
+                
+                self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()),
+                                                   _('Command finished'),
+                                                   (stime)))
+            except KeyError:
+                # stopped deamon
+                pass
+
+            self.btnCmdAbort.Enable(False)
+        
+        if event.onDone:
+            event.onDone(cmd = event.cmd, returncode = event.returncode)
+        
+        self.progressbar.SetValue(0) # reset progress bar on '0%'
+
+        self.cmdOutputTimer.Stop()
+
+        if event.cmd[0] == 'g.gisenv':
+            Debug.SetLevel()
+            self.Redirect()
+        
+        if self.parent.GetName() == "LayerManager":
+            self.btnCmdAbort.Enable(False)
+            if event.cmd[0] not in globalvar.grassCmd['all'] or \
+                    event.cmd[0] == 'r.mapcalc':
+                return
+            
+            display = self.parent.GetLayerTree().GetMapDisplay()
+            if not display or not display.IsAutoRendered():
+                return
+            mapLayers = map(lambda x: x.GetName(),
+                            display.GetMap().GetListOfLayers(l_type = 'raster') +
+                            display.GetMap().GetListOfLayers(l_type = 'vector'))
+            
+            try:
+                task = GUI(show = None).ParseCommand(event.cmd)
+            except GException:
+                task = None
+                return
+            
+            for p in task.get_options()['params']:
+                if p.get('prompt', '') not in ('raster', 'vector'):
+                    continue
+                mapName = p.get('value', '')
+                if '@' not in mapName:
+                    mapName = mapName + '@' + grass.gisenv()['MAPSET']
+                if mapName in mapLayers:
+                    display.GetWindow().UpdateMap(render = True)
+                    return
+        elif self.parent.GetName() == 'Modeler':
+            pass
+        else: # standalone dialogs
+            dialog = self.parent.parent
+            if hasattr(self.parent.parent, "btn_abort"):
+                dialog.btn_abort.Enable(False)
+            
+            if hasattr(self.parent.parent, "btn_cancel"):
+                dialog.btn_cancel.Enable(True)
+            
+            if hasattr(self.parent.parent, "btn_clipboard"):
+                dialog.btn_clipboard.Enable(True)
+            
+            if hasattr(self.parent.parent, "btn_help"):
+                dialog.btn_help.Enable(True)
+            
+            if hasattr(self.parent.parent, "btn_run"):
+                dialog.btn_run.Enable(True)
+            
+            if event.returncode == 0 and not event.aborted:
+                try:
+                    winName = self.parent.parent.parent.GetName()
+                except AttributeError:
+                    winName = ''
+                
+                if winName == 'LayerManager':
+                    mapTree = self.parent.parent.parent.GetLayerTree()
+                elif winName == 'LayerTree':
+                    mapTree = self.parent.parent.parent
+                elif winName: # GMConsole
+                    mapTree = self.parent.parent.parent.parent.GetLayerTree()
+                else:
+                    mapTree = None
+                
+                cmd = dialog.notebookpanel.createCmd(ignoreErrors = True)
+                if hasattr(dialog, "addbox") and dialog.addbox.IsChecked():
+                    # add created maps into layer tree
+                    for p in dialog.task.get_options()['params']:
+                        prompt = p.get('prompt', '')
+                        if prompt in ('raster', 'vector', '3d-raster') and \
+                                p.get('age', 'old') == 'new' and \
+                                p.get('value', None):
+                            name, found = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
+                                                                    param = p.get('name', ''))
+                            
+                            if mapTree.GetMap().GetListOfLayers(l_name = name):
+                                continue
+                            
+                            if prompt == 'raster':
+                                lcmd = ['d.rast',
+                                        'map=%s' % name]
+                            else:
+                                lcmd = ['d.vect',
+                                        'map=%s' % name]
+                            mapTree.AddLayer(ltype = prompt,
+                                             lcmd = lcmd,
+                                             lname = name)
+            
+            if hasattr(dialog, "get_dcmd") and \
+                    dialog.get_dcmd is None and \
+                    hasattr(dialog, "closebox") and \
+                    dialog.closebox.IsChecked() and \
+                    (event.returncode == 0 or event.aborted):
+                self.cmdOutput.Update()
+                time.sleep(2)
+                dialog.Close()
+        
+    def OnProcessPendingOutputWindowEvents(self, event):
+        self.ProcessPendingEvents()
+
+    def ResetFocus(self):
+        """!Reset focus"""
+        self.cmdPrompt.SetFocus()
+        
+class GMStdout:
+    """!GMConsole standard output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, parent):
+        self.parent = parent # GMConsole
+
+    def write(self, s):
+        if len(s) == 0 or s == '\n':
+            return
+
+        for line in s.splitlines():
+            if len(line) == 0:
+                continue
+            
+            evt = wxCmdOutput(text = line + '\n',
+                              type = '')
+            wx.PostEvent(self.parent.cmdOutput, evt)
+        
+class GMStderr:
+    """!GMConsole standard error output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, parent):
+        self.parent = parent # GMConsole
+        
+        self.type = ''
+        self.message = ''
+        self.printMessage = False
+        
+    def flush(self):
+        pass
+    
+    def write(self, s):
+        if "GtkPizza" in s:
+            return
+        
+        # remove/replace escape sequences '\b' or '\r' from stream
+        progressValue = -1
+        
+        for line in s.splitlines():
+            if len(line) == 0:
+                continue
+            
+            if 'GRASS_INFO_PERCENT' in line:
+                value = int(line.rsplit(':', 1)[1].strip())
+                if value >= 0 and value < 100:
+                    progressValue = value
+                else:
+                    progressValue = 0
+            elif 'GRASS_INFO_MESSAGE' in line:
+                self.type = 'message'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_WARNING' in line:
+                self.type = 'warning'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_ERROR' in line:
+                self.type = 'error'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_END' in line:
+                self.printMessage = True
+            elif self.type == '':
+                if len(line) == 0:
+                    continue
+                evt = wxCmdOutput(text = line,
+                                  type = '')
+                wx.PostEvent(self.parent.cmdOutput, evt)
+            elif len(line) > 0:
+                self.message += line.strip() + '\n'
+
+            if self.printMessage and len(self.message) > 0:
+                evt = wxCmdOutput(text = self.message,
+                                  type = self.type)
+                wx.PostEvent(self.parent.cmdOutput, evt)
+
+                self.type = ''
+                self.message = ''
+                self.printMessage = False
+
+        # update progress message
+        if progressValue > -1:
+            # self.gmgauge.SetValue(progressValue)
+            evt = wxCmdProgress(value = progressValue)
+            wx.PostEvent(self.parent.progressbar, evt)
+            
+class GMStc(wx.stc.StyledTextCtrl):
+    """!Styled GMConsole
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """    
+    def __init__(self, parent, id, margin = False, wrap = None):
+        wx.stc.StyledTextCtrl.__init__(self, parent, id)
+        self.parent = parent
+        self.SetUndoCollection(True)
+        self.SetReadOnly(True)
+
+        #
+        # styles
+        #                
+        self.SetStyle()
+        
+        #
+        # line margins
+        #
+        # TODO print number only from cmdlog
+        self.SetMarginWidth(1, 0)
+        self.SetMarginWidth(2, 0)
+        if margin:
+            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+            self.SetMarginWidth(0, 30)
+        else:
+            self.SetMarginWidth(0, 0)
+
+        #
+        # miscellaneous
+        #
+        self.SetViewWhiteSpace(False)
+        self.SetTabWidth(4)
+        self.SetUseTabs(False)
+        self.UsePopUp(True)
+        self.SetSelBackground(True, "#FFFF00")
+        self.SetUseHorizontalScrollBar(True)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+        
+    def OnTextSelectionChanged(self, event):
+        """!Copy selected text to clipboard and skip event.
+        The same function is in TextCtrlAutoComplete class (prompt.py).
+        """
+        self.Copy()
+        event.Skip()
+        
+    def SetStyle(self):
+        """!Set styles for styled text output windows with type face 
+        and point size selected by user (Courier New 10 is default)"""
+
+        settings = Settings()
+        
+        typeface = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'type')   
+        if typeface == "":
+            typeface = "Courier New"
+        
+        typesize = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'size')
+        if typesize == None or typesize <= 0:
+            typesize = 10
+        typesize = float(typesize)
+        
+        self.StyleDefault     = 0
+        self.StyleDefaultSpec = "face:%s,size:%d,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+        self.StyleCommand     = 1
+        self.StyleCommandSpec = "face:%s,size:%d,,fore:#000000,back:#bcbcbc" % (typeface, typesize)
+        self.StyleOutput      = 2
+        self.StyleOutputSpec  = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+        # fatal error
+        self.StyleError       = 3
+        self.StyleErrorSpec   = "face:%s,size:%d,,fore:#7F0000,back:#FFFFFF" % (typeface, typesize)
+        # warning
+        self.StyleWarning     = 4
+        self.StyleWarningSpec = "face:%s,size:%d,,fore:#0000FF,back:#FFFFFF" % (typeface, typesize)
+        # message
+        self.StyleMessage     = 5
+        self.StyleMessageSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+        # unknown
+        self.StyleUnknown     = 6
+        self.StyleUnknownSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+        
+        # default and clear => init
+        self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.StyleDefaultSpec)
+        self.StyleClearAll()
+        self.StyleSetSpec(self.StyleCommand, self.StyleCommandSpec)
+        self.StyleSetSpec(self.StyleOutput,  self.StyleOutputSpec)
+        self.StyleSetSpec(self.StyleError,   self.StyleErrorSpec)
+        self.StyleSetSpec(self.StyleWarning, self.StyleWarningSpec)
+        self.StyleSetSpec(self.StyleMessage, self.StyleMessageSpec)
+        self.StyleSetSpec(self.StyleUnknown, self.StyleUnknownSpec)        
+
+    def OnDestroy(self, evt):
+        """!The clipboard contents can be preserved after
+        the app has exited"""
+        
+        wx.TheClipboard.Flush()
+        evt.Skip()
+
+    def AddTextWrapped(self, txt, wrap = None):
+        """!Add string to text area.
+
+        String is wrapped and linesep is also added to the end
+        of the string"""
+        # allow writing to output window
+        self.SetReadOnly(False)
+        
+        if wrap:
+            txt = textwrap.fill(txt, wrap) + '\n'
+        else:
+            if txt[-1] != '\n':
+                txt += '\n'
+        
+        if '\r' in txt:
+            self.parent.linePos = -1
+            for seg in txt.split('\r'):
+                if self.parent.linePos > -1:
+                    self.SetCurrentPos(self.parent.linePos)
+                    self.ReplaceSelection(seg)
+                else:
+                    self.parent.linePos = self.GetCurrentPos()
+                    self.AddText(seg)
+        else:
+            self.parent.linePos = self.GetCurrentPos()
+            try:
+                self.AddText(txt)
+            except UnicodeDecodeError:
+                enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
+                if enc:
+                    txt = unicode(txt, enc)
+                elif 'GRASS_DB_ENCODING' in os.environ:
+                    txt = unicode(txt, os.environ['GRASS_DB_ENCODING'])
+                else:
+                    txt = utils.EncodeString(txt)
+                
+                self.AddText(txt)
+        
+        # reset output window to read only
+        self.SetReadOnly(True)
+    

Copied: grass/trunk/gui/wxpython/gui_core/gselect.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gselect.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/gselect.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/gselect.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1840 @@
+"""!
+ at package gui_core.gselect
+
+ at brief Custom control that selects elements
+
+Classes:
+ - Select
+ - VectorSelect
+ - TreeCrtlComboPopup
+ - VectorDBInfo
+ - LayerSelect
+ - DriverSelect
+ - DatabaseSelect
+ - ColumnSelect
+ - DbaseSelect
+ - LocationSelect
+ - MapsetSelect
+ - SubGroupSelect
+ - FormatSelect
+ - GdalSelect
+ - ProjSelect
+ - ElementSelect
+ - OgrTypeSelect
+
+(C) 2007-2011 by the GRASS Development Team This program is free
+software under the GNU General Public License (>=v2). Read the file
+COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
+"""
+
+import os
+import sys
+import glob
+
+import wx
+import wx.combo
+import wx.lib.filebrowsebutton as filebrowse
+from wx.lib.newevent import NewEvent
+
+from core import globalvar
+
+import grass.script as grass
+from   grass.script import task as gtask
+
+from core.gcmd     import RunCommand, GError, GMessage
+from core.utils    import GetListOfLocations, GetListOfMapsets, GetFormats
+from core.utils    import GetSettingsPath, GetValidLayerName, ListSortLower
+from core.settings import UserSettings
+from core.debug    import Debug
+
+wxGdalSelect, EVT_GDALSELECT = NewEvent()
+
+class Select(wx.combo.ComboCtrl):
+    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                 type = None, multiple = False, mapsets = None,
+                 updateOnPopup = True, onPopup = None,
+                 fullyQualified = True):
+        """!Custom control to create a ComboBox with a tree control to
+        display and select GIS elements within acessible mapsets.
+        Elements can be selected with mouse. Can allow multiple
+        selections, when argument multiple=True. Multiple selections
+        are separated by commas.
+
+        @param type type of GIS elements ('raster, 'vector', ...)
+        @param multiple multiple input allowed?
+        @param mapsets force list of mapsets (otherwise search path)
+        @param updateOnPopup True for updating list of elements on popup
+        @param onPopup function to be called on Popup
+        @param fullyQualified True to provide fully qualified names (map at mapset)
+        """
+        wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
+        self.GetChildren()[0].SetName("Select")
+        self.GetChildren()[0].type = type
+        
+        self.tcp = TreeCtrlComboPopup()
+        self.SetPopupControl(self.tcp)
+        self.SetPopupExtents(0, 100)
+        if type:
+            self.tcp.SetData(type = type, mapsets = mapsets,
+                             multiple = multiple,
+                             updateOnPopup = updateOnPopup, onPopup = onPopup,
+                             fullyQualified = fullyQualified)
+        self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+     
+    def OnKeyUp(self, event):
+        """!Shows popupwindow if down arrow key is released"""
+        if event.GetKeyCode() == wx.WXK_DOWN:
+            self.ShowPopup() 
+        else:
+            event.Skip()
+        
+    def SetElementList(self, type, mapsets = None):
+        """!Set element list
+
+        @param type GIS element type
+        @param mapsets list of acceptable mapsets (None for all in search path)
+        """
+        self.tcp.SetData(type = type, mapsets = mapsets)
+        
+    def GetElementList(self):
+        """!Load elements"""
+        self.tcp.GetElementList()
+    
+    def SetType(self, etype, multiple = False, mapsets = None,
+                updateOnPopup = True, onPopup = None):
+        """!Param set element type for widget
+
+        @param etype element type, see gselect.ElementSelect
+        """
+        self.tcp.SetData(type = etype, mapsets = mapsets,
+                         multiple = multiple,
+                         updateOnPopup = updateOnPopup, onPopup = onPopup)
+        
+class VectorSelect(Select):
+    def __init__(self, parent, ftype, **kwargs):
+        """!Custom to create a ComboBox with a tree control to display and
+        select vector maps. Control allows to filter vector maps. If you
+        don't need this feature use Select class instead
+        
+        @ftype filter vector maps based on feature type
+        """
+        Select.__init__(self, parent = parent, id = wx.ID_ANY,
+                        type = 'vector', **kwargs)
+        
+        self.ftype = ftype
+        
+        # remove vector maps which do not contain given feature type
+        self.tcp.SetFilter(self._isElement)
+        
+    def _isElement(self, vectorName):
+        """!Check if element should be filtered out"""
+        try:
+            if int(grass.vector_info_topo(vectorName)[self.ftype]) < 1:
+                return False
+        except KeyError:
+            return False
+        
+        return True
+
+class TreeCtrlComboPopup(wx.combo.ComboPopup):
+    """!Create a tree ComboBox for selecting maps and other GIS elements
+    in accessible mapsets within the current location
+    """
+    # overridden ComboPopup methods
+    def Init(self):
+        self.value = [] # for multiple is False -> len(self.value) in [0,1]
+        self.curitem = None
+        self.multiple = False
+        self.type = None
+        self.mapsets = None
+        self.updateOnPopup = True
+        self.onPopup = None
+        self.fullyQualified = True
+        
+        self.SetFilter(None)
+        
+    def Create(self, parent):
+        self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
+                                   |wx.TR_HAS_BUTTONS
+                                   |wx.TR_SINGLE
+                                   |wx.TR_LINES_AT_ROOT
+                                   |wx.SIMPLE_BORDER
+                                   |wx.TR_FULL_ROW_HIGHLIGHT)
+        self.seltree.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+        self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
+        self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
+        self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
+        self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
+        self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
+        
+    # the following dummy handler are needed to keep tree events from propagating up to
+    # the parent GIS Manager layer tree
+    def mapsetExpanded(self, event):
+        pass
+
+    def mapsetCollapsed(self, event):
+        pass
+
+    def mapsetActivated(self, event):
+        pass
+
+    def mapsetSelected(self, event):
+        pass
+    # end of dummy events
+
+    def GetControl(self):
+        return self.seltree
+
+    def GetStringValue(self):
+        """!Get value as a string separated by commas"""
+        return ','.join(self.value)
+    
+    def SetFilter(self, filter):
+        """!Set filter for GIS elements, see e.g. VectorSelect"""
+        self.filterElements = filter
+    
+    def OnPopup(self, force = False):
+        """!Limited only for first selected"""
+        if not force and not self.updateOnPopup:
+            return
+        if self.onPopup:
+            selected, exclude = self.onPopup(self.type)
+        else:
+            selected = None
+            exclude  = False
+ 
+        self.GetElementList(selected, exclude)
+        
+        # selects map starting according to written text
+        inputText = self.GetCombo().GetValue().strip()
+        if inputText:
+            root = self.seltree.GetRootItem()
+            match = self.FindItem(root, inputText, startLetters = True)
+            self.seltree.EnsureVisible(match)
+            self.seltree.SelectItem(match)
+            
+      
+    def GetElementList(self, elements = None, exclude = False):
+        """!Get filtered list of GIS elements in accessible mapsets
+        and display as tree with all relevant elements displayed
+        beneath each mapset branch
+        """
+        # update list
+        self.seltree.DeleteAllItems()
+        self._getElementList(self.type, self.mapsets, elements, exclude)
+        
+        if len(self.value) > 0:
+            root = self.seltree.GetRootItem()
+            if not root:
+                return
+            item = self.FindItem(root, self.value[0])
+            try:
+                self.seltree.EnsureVisible(item)
+                self.seltree.SelectItem(item)
+            except:
+                pass
+            
+    def SetStringValue(self, value):
+        # this assumes that item strings are unique...
+        root = self.seltree.GetRootItem()
+        if not root:
+            return
+        found = self.FindItem(root, value)
+        winValue = self.GetCombo().GetValue().strip(',')
+        self.value = []
+        if winValue:
+            self.value = winValue.split(',')
+        
+        if found:
+            self.value.append(found)
+            self.seltree.SelectItem(found)
+        
+    def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
+        """!Reads UserSettings to get height (which was 200 in old implementation).
+        """
+        height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
+        return wx.Size(minWidth, min(height, maxHeight))
+
+    def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
+        """!Get list of GIS elements in accessible mapsets and display as tree
+        with all relevant elements displayed beneath each mapset branch
+
+        @param element GIS element
+        @param mapsets list of acceptable mapsets (None for all mapsets in search path)
+        @param elements list of forced GIS elements
+        @param exclude True to exclude, False for forcing the list (elements)
+        """
+        # get current mapset
+        curr_mapset = grass.gisenv()['MAPSET']
+        
+        # map element types to g.mlist types
+        elementdict = {'cell':'rast',
+                       'raster':'rast',
+                       'rast':'rast',
+                       'raster files':'rast',
+                       'grid3':'rast3d',
+                       'rast3d':'rast3d',
+                       '3d-raster':'rast3d',
+                       'raster3D':'rast3d',
+                       'raster3D files':'rast3d',
+                       'vector':'vect',
+                       'vect':'vect',
+                       'binary vector files':'vect',
+                       'dig':'oldvect',
+                       'oldvect':'oldvect',
+                       'old vector':'oldvect',
+                       'dig_ascii':'asciivect',
+                       'asciivect':'asciivect',
+                       'asciivector':'asciivect',
+                       'ascii vector files':'asciivect',
+                       'icons':'icon',
+                       'icon':'icon',
+                       'paint icon files':'icon',
+                       'paint/labels':'labels',
+                       'labels':'labels',
+                       'label':'labels',
+                       'paint label files':'labels',
+                       'site_lists':'sites',
+                       'sites':'sites',
+                       'site list':'sites',
+                       'site list files':'sites',
+                       'windows':'region',
+                       'region':'region',
+                       'region definition':'region',
+                       'region definition files':'region',
+                       'windows3d':'region3d',
+                       'region3d':'region3d',
+                       'region3D definition':'region3d',
+                       'region3D definition files':'region3d',
+                       'group':'group',
+                       'imagery group':'group',
+                       'imagery group files':'group',
+                       '3d.view':'3dview',
+                       '3dview':'3dview',
+                       '3D viewing parameters':'3dview',
+                       '3D view parameters':'3dview'}
+        
+        if element not in elementdict:
+            self.AddItem(_('Not selectable element'))
+            return
+        
+        if globalvar.have_mlist:
+            filesdict = grass.mlist_grouped(elementdict[element],
+                                            check_search_path = False)
+        else:
+            filesdict = grass.list_grouped(elementdict[element],
+                                           check_search_path = False)
+        
+        # list of mapsets in current location
+        if mapsets is None:
+            mapsets = grass.mapsets(search_path = True)
+        
+        # current mapset first
+        if curr_mapset in mapsets and mapsets[0] != curr_mapset:
+            mapsets.remove(curr_mapset)
+            mapsets.insert(0, curr_mapset)
+        
+        first_mapset = None
+        for mapset in mapsets:
+            mapset_node = self.AddItem(_('Mapset') + ': ' + mapset)
+            if not first_mapset:
+                first_mapset = mapset_node
+            
+            self.seltree.SetItemTextColour(mapset_node, wx.Colour(50, 50, 200))
+            if mapset not in filesdict:
+                continue
+            try:
+                elem_list = filesdict[mapset]
+                elem_list.sort()
+                for elem in elem_list:
+                    if elem != '':
+                        fullqElem = elem + '@' + mapset
+                        if elements is not None:
+                            if (exclude and fullqElem in elements) or \
+                                    (not exclude and fullqElem not in elements):
+                                continue
+                        
+                        if self.filterElements:
+                            if self.filterElements(fullqElem):
+                                self.AddItem(elem, parent = mapset_node)
+                        else:
+                            self.AddItem(elem, parent = mapset_node)
+            except StandardError, e:
+                sys.stderr.write(_("GSelect: invalid item: %s") % e)
+                continue
+            
+            if self.seltree.ItemHasChildren(mapset_node):
+                sel = UserSettings.Get(group='appearance', key='elementListExpand',
+                                       subkey='selection')
+                collapse = True
+
+                if sel == 0: # collapse all except PERMANENT and current
+                    if mapset in ('PERMANENT', curr_mapset):
+                        collapse = False
+                elif sel == 1: # collapse all except PERMANENT
+                    if mapset == 'PERMANENT':
+                        collapse = False
+                elif sel == 2: # collapse all except current
+                    if mapset == curr_mapset:
+                        collapse = False
+                elif sel == 3: # collapse all
+                    pass
+                elif sel == 4: # expand all
+                    collapse = False
+                
+                if collapse:
+                    self.seltree.Collapse(mapset_node)
+                else:
+                    self.seltree.Expand(mapset_node)
+        
+        if first_mapset:
+            # select first mapset (MSW hack)
+            self.seltree.SelectItem(first_mapset)
+    
+    # helpers
+    def FindItem(self, parentItem, text, startLetters = False):
+        """!Finds item with given name or starting with given text"""
+        startletters = startLetters
+        item, cookie = self.seltree.GetFirstChild(parentItem)
+        while wx.TreeItemId.IsOk(item):
+            if self.seltree.GetItemText(item) == text:
+                return item
+            if self.seltree.ItemHasChildren(item):
+                item = self.FindItem(item, text, startLetters = startletters)
+                if wx.TreeItemId.IsOk(item):
+                    return item
+            elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
+                return item
+            item, cookie = self.seltree.GetNextChild(parentItem, cookie)
+        return wx.TreeItemId()
+    
+    def AddItem(self, value, parent=None):
+        if not parent:
+            root = self.seltree.GetRootItem()
+            if not root:
+                root = self.seltree.AddRoot("<hidden root>")
+            parent = root
+
+        item = self.seltree.AppendItem(parent, text=value)
+        return item
+    
+    # able to recieve only wx.EVT_KEY_UP
+    def OnKeyUp(self, event):
+        """!Enables to select items using keyboard"""
+        
+        item = self.seltree.GetSelection()
+        if event.GetKeyCode() == wx.WXK_DOWN:
+            self.seltree.SelectItem(self.seltree.GetNextVisible(item))
+            
+        # problem with GetPrevVisible   
+        elif event.GetKeyCode() == wx.WXK_UP: 
+            if self.seltree.ItemHasChildren(item) and self.seltree.IsExpanded(self.seltree.GetPrevSibling(item)):
+                itemPrev = self.seltree.GetLastChild(self.seltree.GetPrevSibling(item))
+            else:
+                itemPrev = self.seltree.GetPrevSibling(item)
+                if not wx.TreeItemId.IsOk(itemPrev):
+                    itemPrev = self.seltree.GetItemParent(item)
+                    if item == self.seltree.GetFirstChild(self.seltree.GetRootItem())[0]:
+                        itemPrev = item
+            self.seltree.SelectItem(itemPrev)
+        
+        # selects first item starting with the written text in next mapset
+        elif event.GetKeyCode() == wx.WXK_TAB:
+            selected = self.seltree.GetSelection()
+            if self.seltree.ItemHasChildren(selected):
+                parent = selected
+            else:
+                parent = self.seltree.GetItemParent(selected)
+            nextSibling = self.seltree.GetNextSibling(parent)
+            if wx.TreeItemId.IsOk(nextSibling):
+                match = self.FindItem(nextSibling, self.GetCombo().GetValue().strip(), True) 
+            else: 
+                match = self.FindItem(self.seltree.GetFirstChild(self.seltree.GetItemParent(parent))[0],
+                                        self.GetCombo().GetValue().strip(), True) 
+            self.seltree.SelectItem(match)
+            
+        elif event.GetKeyCode() == wx.WXK_RIGHT:
+            if self.seltree.ItemHasChildren(item):
+                self.seltree.Expand(item)
+        
+        elif event.GetKeyCode() == wx.WXK_LEFT:
+            if self.seltree.ItemHasChildren(item):
+                self.seltree.Collapse(item)
+                
+        elif event.GetKeyCode() == wx.WXK_ESCAPE:
+            self.Dismiss()
+            
+        elif event.GetKeyCode() == wx.WXK_RETURN:
+            if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
+                self.value = [] 
+            else:
+                mapsetItem = self.seltree.GetItemParent(item)
+                fullName = self.seltree.GetItemText(item)
+                if self.fullyQualified:
+                    fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
+                
+                if self.multiple is True:
+                    # text item should be unique
+                    self.value.append(fullName)
+                else:
+                    self.value = [fullName]
+            
+            self.Dismiss()
+        
+    def OnMotion(self, evt):
+        """!Have the selection follow the mouse, like in a real combobox
+        """
+        item, flags = self.seltree.HitTest(evt.GetPosition())
+        if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
+            self.seltree.SelectItem(item)
+            self.curitem = item
+        evt.Skip()
+
+    def OnLeftDown(self, evt):
+        """!Do the combobox selection
+        """
+        item, flags = self.seltree.HitTest(evt.GetPosition())
+        if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
+            self.curitem = item
+            
+            if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
+                self.value = [] # cannot select mapset item
+            else:
+                mapsetItem = self.seltree.GetItemParent(item)
+                fullName = self.seltree.GetItemText(item)
+                if self.fullyQualified:
+                    fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
+                
+                if self.multiple is True:
+                    # text item should be unique
+                    self.value.append(fullName)
+                else:
+                    self.value = [fullName]
+            
+            self.Dismiss()
+        
+        evt.Skip()
+
+    def SetData(self, **kargs):
+        """!Set object properties"""
+        if 'type' in kargs:
+            self.type = kargs['type']
+        if 'mapsets' in kargs:
+            self.mapsets = kargs['mapsets']
+        if 'multiple' in kargs:
+            self.multiple = kargs['multiple']
+        if 'updateOnPopup' in kargs:
+            self.updateOnPopup = kargs['updateOnPopup']
+        if 'onPopup' in kargs:
+            self.onPopup = kargs['onPopup']
+        if 'fullyQualified' in kargs:
+            self.fullyQualified = kargs['fullyQualified']
+        
+    def GetType(self):
+        """!Get element type
+        """
+        return self.type
+    
+class VectorDBInfo:
+    """!Class providing information about attribute tables
+    linked to a vector map"""
+    def __init__(self, map):
+        self.map = map
+
+        # dictionary of layer number and associated (driver, database, table)
+        self.layers = {}
+         # dictionary of table and associated columns (type, length, values, ids)
+        self.tables = {}
+        
+        if not self._CheckDBConnection(): # -> self.layers
+            return
+
+        self._DescribeTables() # -> self.tables
+
+    def _CheckDBConnection(self):
+        """!Check DB connection"""
+        nuldev = file(os.devnull, 'w+')
+        self.layers = grass.vector_db(map = self.map, stderr = nuldev)
+        nuldev.close()
+        
+        return bool(len(self.layers.keys()) > 0)
+        
+    def _DescribeTables(self):
+        """!Describe linked tables"""
+        for layer in self.layers.keys():
+            # determine column names and types
+            table = self.layers[layer]["table"]
+            columns = {} # {name: {type, length, [values], [ids]}}
+            i = 0
+            Debug.msg(1, "gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
+                          (self.layers[layer]["table"], self.layers[layer]["driver"],
+                           self.layers[layer]["database"]))
+            for item in grass.db_describe(table = self.layers[layer]["table"],
+                                          driver = self.layers[layer]["driver"],
+                                          database = self.layers[layer]["database"])['cols']:
+                name, type, length = item
+                # FIXME: support more datatypes
+                if type.lower() == "integer":
+                    ctype = int
+                elif type.lower() == "double precision":
+                    ctype = float
+                else:
+                    ctype = str
+
+                columns[name.strip()] = { 'index'  : i,
+                                          'type'   : type.lower(),
+                                          'ctype'  : ctype,
+                                          'length' : int(length),
+                                          'values' : [],
+                                          'ids'    : []}
+                i += 1
+            
+            # check for key column
+            # v.db.connect -g/p returns always key column name lowercase
+            if self.layers[layer]["key"] not in columns.keys():
+                for col in columns.keys():
+                    if col.lower() == self.layers[layer]["key"]:
+                        self.layers[layer]["key"] = col.upper()
+                        break
+            
+            self.tables[table] = columns
+            
+        return True
+    
+    def Reset(self):
+        """!Reset"""
+        for layer in self.layers:
+            table = self.layers[layer]["table"] # get table desc
+            columns = self.tables[table]
+            for name in self.tables[table].keys():
+                self.tables[table][name]['values'] = []
+                self.tables[table][name]['ids']    = []
+    
+    def GetName(self):
+        """!Get vector name"""
+        return self.map
+    
+    def GetKeyColumn(self, layer):
+        """!Get key column of given layer
+        
+        @param layer vector layer number
+        """
+        return str(self.layers[layer]['key'])
+    
+    def GetTable(self, layer):
+        """!Get table name of given layer
+        
+        @param layer vector layer number
+        """
+        return self.layers[layer]['table']
+    
+    def GetDbSettings(self, layer):
+        """!Get database settins
+
+        @param layer layer number
+        
+        @return (driver, database)
+        """
+        return self.layers[layer]['driver'], self.layers[layer]['database']
+    
+    def GetTableDesc(self, table):
+        """!Get table columns
+
+        @param table table name
+        """
+        return self.tables[table]
+
+class LayerSelect(wx.ComboBox):
+    def __init__(self, parent, id = wx.ID_ANY,
+                 size = globalvar.DIALOG_COMBOBOX_SIZE,
+                 vector = None, dsn = None, choices = [], all = False, default = None):
+        """!Creates combo box for selecting vector map layer names
+
+        @param vector vector map name (native or connected via v.external)
+        @param dsn    OGR data source name
+        """
+        super(LayerSelect, self).__init__(parent, id, size = size, choices = choices)
+
+        self.all = all
+        
+        self.SetName("LayerSelect")
+
+        # default value
+        self.default = default
+
+        self.InsertLayers(vector = vector, dsn = dsn)
+        
+    def InsertLayers(self, vector = None, dsn = None):
+        """!Insert layers for a vector into the layer combobox
+
+        @param vector vector map name (native or connected via v.external)
+        @param dsn    OGR data source name
+        """
+        layers = list()
+        if self.all:
+            layers.append('-1')
+
+        if vector:
+            # TODO: use Vect_get_field2() in C modules where possible
+            # currently the following is identical to
+            # layers = utils.GetVectorNumberOfLayers(self, vector)
+
+            ret = RunCommand('v.db.connect',
+                             read = True,
+                             quiet = True,
+                             fs = '|',
+                             flags = 'g',
+                             map = vector)
+            if ret:
+                for line in ret.splitlines():
+                    layerinfo = line.split('|')
+                    layername = layerinfo[0].split('/')
+                    # use this to get layer names
+                    # but only when all modules use Vect_get_field2()
+                    # which is not the case right now
+                    ### layers.append(layername[len(layername) - 1])
+                    layers.append(layername[0])
+
+        elif dsn:
+            ret = RunCommand('v.in.ogr',
+                             read = True,
+                             quiet = True,
+                             flags = 'l',
+                             dsn = dsn)
+            if ret:
+                layers = ret.splitlines()
+    
+        if self.default:
+            if len(layers) == 0:
+                layers.insert(0, str(self.default))
+            elif self.default not in layers:
+                layers.append(self.default)
+
+        if len(layers) > 0:
+            self.SetItems(layers)
+        
+class DriverSelect(wx.ComboBox):
+    """!Creates combo box for selecting database driver.
+    """
+    def __init__(self, parent, choices, value,
+                 id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=globalvar.DIALOG_LAYER_SIZE, **kargs):
+
+        super(DriverSelect, self).__init__(parent, id, value, pos, size,
+                                           choices, style=wx.CB_READONLY)
+        
+        self.SetName("DriverSelect")
+        
+        self.SetStringSelection(value)
+
+class DatabaseSelect(wx.TextCtrl):
+    """!Creates combo box for selecting database driver.
+    """
+    def __init__(self, parent, value='',
+                 id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
+        
+        super(DatabaseSelect, self).__init__(parent, id, value, pos, size)
+                               
+        self.SetName("DatabaseSelect")
+
+class TableSelect(wx.ComboBox):
+    """!Creates combo box for selecting attribute tables from the database
+    """
+    def __init__(self, parent,
+                 id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
+                 size=globalvar.DIALOG_COMBOBOX_SIZE,
+                 choices=[]):
+
+        super(TableSelect, self).__init__(parent, id, value, pos, size, choices,
+                                          style=wx.CB_READONLY)
+
+        self.SetName("TableSelect")
+
+        if not choices:
+            self.InsertTables()
+                
+    def InsertTables(self, driver=None, database=None):
+        """!Insert attribute tables into combobox"""
+        items = []
+
+        if not driver or not database:
+            connect = grass.db_connection()
+            
+            driver = connect['driver']
+            database = connect['database']
+        
+        ret = RunCommand('db.tables',
+                         flags = 'p',
+                         read = True,
+                         driver = driver,
+                         database = database)
+        
+        if ret:
+            for table in ret.splitlines():
+                items.append(table)
+            
+        self.SetItems(items)
+        self.SetValue('')
+        
+class ColumnSelect(wx.ComboBox):
+    """!Creates combo box for selecting columns in the attribute table
+    for a vector map.
+
+    @param parent window parent
+    @param id window id
+    @param value default value
+    @param size window size
+    @param vector vector map name
+    @param layer layer number
+    @param param parameters list (see menuform.py)
+    @param **kwags wx.ComboBox parameters
+    """
+    def __init__(self, parent, id = wx.ID_ANY, value = '', 
+                 size=globalvar.DIALOG_COMBOBOX_SIZE,
+                 vector = None, layer = 1, param = None, **kwargs):
+        self.defaultValue = value
+        self.param = param
+        
+        super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
+        self.SetName("ColumnSelect")
+        
+        if vector:
+            self.InsertColumns(vector, layer)
+    
+    def InsertColumns(self, vector, layer, excludeKey = False, excludeCols = None, type = None, dbInfo = None):
+        """!Insert columns for a vector attribute table into the columns combobox
+
+        @param vector vector name
+        @param layer vector layer number
+        @param excludeKey exclude key column from the list?
+        @param excludeCols list of columns to be removed from the list
+        @param type only columns of given type (given as list)
+        """
+        if not dbInfo:
+            dbInfo = VectorDBInfo(vector)
+        
+        try:
+            table = dbInfo.GetTable(int(layer))
+            columnchoices = dbInfo.GetTableDesc(table)
+            keyColumn = dbInfo.GetKeyColumn(int(layer))
+            columns = len(columnchoices.keys()) * ['']
+            for key, val in columnchoices.iteritems():
+                columns[val['index']] = key
+            if excludeKey: # exclude key column
+                columns.remove(keyColumn)
+            if excludeCols: # exclude key column
+                for key in columnchoices.iterkeys():
+                    if key in excludeCols:
+                        columns.remove(key)
+            if type: # only selected column types
+                for key, value in columnchoices.iteritems():
+                    if value['type'] not in type:
+                        try:
+                            columns.remove(key)
+                        except ValueError:
+                            pass
+        except (KeyError, ValueError):
+            columns = list()
+            
+        self.SetItems(columns)
+        self.SetValue(self.defaultValue)
+        
+        if self.param:
+            self.param['value'] = ''
+        
+    def InsertTableColumns(self, table, driver=None, database=None):
+        """!Insert table columns
+
+        @param table table name
+        @param driver driver name
+        @param database database name
+        """
+        columns = list()
+        
+        ret = RunCommand('db.columns',
+                         read = True,
+                         driver = driver,
+                         database = database,
+                         table = table)
+        
+        if ret:
+            columns = ret.splitlines()
+        
+        self.SetItems(columns)
+        self.SetValue(self.defaultValue)
+        
+        if self.param:
+            self.param['value'] = ''
+
+class DbaseSelect(wx.lib.filebrowsebutton.DirBrowseButton):
+    """!Widget for selecting GRASS Database"""
+    def __init__(self, parent, **kwargs):
+        super(DbaseSelect, self).__init__(parent, id = wx.ID_ANY,
+                                          size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
+                                          dialogTitle = _('Choose GIS Data Directory'),
+                                          buttonText = _('Browse'),
+                                          startDirectory = grass.gisenv()['GISDBASE'],
+                                          **kwargs)
+        
+class LocationSelect(wx.ComboBox):
+    """!Widget for selecting GRASS location"""
+    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
+                 gisdbase = None, **kwargs):
+        super(LocationSelect, self).__init__(parent, id, size = size, 
+                                             style = wx.CB_READONLY, **kwargs)
+        self.SetName("LocationSelect")
+        
+        if not gisdbase:
+            self.gisdbase = grass.gisenv()['GISDBASE']
+        else:
+            self.gisdbase = gisdbase
+        
+        self.SetItems(GetListOfLocations(self.gisdbase))
+
+    def UpdateItems(self, dbase):
+        """!Update list of locations
+
+        @param dbase path to GIS database
+        """
+        self.gisdbase = dbase
+        if dbase:
+            self.SetItems(GetListOfLocations(self.gisdbase))
+        else:
+            self.SetItems([])
+        
+class MapsetSelect(wx.ComboBox):
+    """!Widget for selecting GRASS mapset"""
+    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
+                 gisdbase = None, location = None, setItems = True,
+                 searchPath = False, new = False, **kwargs):
+        style = 0
+        if not new:
+            style = wx.CB_READONLY
+        super(MapsetSelect, self).__init__(parent, id, size = size, 
+                                           style = style, **kwargs)
+        self.searchPath = searchPath
+        
+        self.SetName("MapsetSelect")
+        if not gisdbase:
+            self.gisdbase = grass.gisenv()['GISDBASE']
+        else:
+            self.gisdbase = gisdbase
+        
+        if not location:
+            self.location = grass.gisenv()['LOCATION_NAME']
+        else:
+            self.location = location
+        
+        if setItems:
+            self.SetItems(self._getMapsets())
+        
+    def UpdateItems(self, location, dbase = None):
+        """!Update list of mapsets for given location
+
+        @param dbase path to GIS database (None to use currently selected)
+        @param location name of location
+        """
+        if dbase:
+            self.gisdbase = dbase
+        self.location = location
+        if location:
+            self.SetItems(self._getMapsets())
+        else:
+            self.SetItems([])
+     
+    def _getMapsets(self):
+        if self.searchPath:
+            return RunCommand('g.mapsets',
+                              read = True,
+                              flags = 'p',
+                              fs = 'newline').splitlines()
+        
+        return GetListOfMapsets(self.gisdbase, self.location, selectable = False)
+            
+class SubGroupSelect(wx.ComboBox):
+    """!Widget for selecting subgroups"""
+    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE, 
+                 **kwargs):
+        super(SubGroupSelect, self).__init__(parent, id, size = size, 
+                                             style = wx.CB_READONLY, **kwargs)
+        self.SetName("SubGroupSelect")
+
+    def Insert(self, group):
+        """!Insert subgroups for defined group"""
+        if not group:
+            return
+        gisenv = grass.gisenv()
+        try:
+            name, mapset = group.split('@', 1)
+        except ValueError:
+            name = group
+            mapset = gisenv['MAPSET']
+        
+        path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], mapset,
+                            'group', name, 'subgroup')
+        try:
+            self.SetItems(os.listdir(path))
+        except OSError:
+            self.SetItems([])
+        self.SetValue('')
+
+class FormatSelect(wx.Choice):
+    def __init__(self, parent, ogr = False,
+                 sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_SPIN_SIZE, 
+                 **kwargs):
+        """!Widget for selecting external (GDAL/OGR) format
+
+        @param parent parent window
+        @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
+        @param ogr True for OGR otherwise GDAL
+        """
+        super(FormatSelect, self).__init__(parent, id, size = size, 
+                                           style = wx.CB_READONLY, **kwargs)
+        self.SetName("FormatSelect")
+        
+        if ogr:
+            ftype = 'ogr'
+        else:
+            ftype = 'gdal'
+        
+        formats = list()
+        for f in GetFormats()[ftype].values():
+            formats += f
+        self.SetItems(formats)
+        
+    def GetExtension(self, name):
+        """!Get file extension by format name"""
+        formatToExt = {
+            # raster
+            'GeoTIFF' : 'tif',
+            'Erdas Imagine Images (.img)' : 'img',
+            'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
+            'Arc/Info Binary Grid' : 'adf',
+            'Portable Network Graphics' : 'png',
+            'JPEG JFIF' : 'jpg',
+            'Japanese DEM (.mem)' : 'mem',
+            'Graphics Interchange Format (.gif)' : 'gif',
+            'X11 PixMap Format' : 'xpm',
+            'MS Windows Device Independent Bitmap' : 'bmp',
+            'SPOT DIMAP' : 'dim',
+            'RadarSat 2 XML Product' : 'xml',
+            'EarthWatch .TIL' : 'til',
+            'ERMapper .ers Labelled' : 'ers',
+            'ERMapper Compressed Wavelets' : 'ecw',
+            'GRIdded Binary (.grb)' : 'grb',
+            'EUMETSAT Archive native (.nat)' : 'nat',
+            'Idrisi Raster A.1' : 'rst',
+            'Golden Software ASCII Grid (.grd)' : 'grd',
+            'Golden Software Binary Grid (.grd)' : 'grd',
+            'Golden Software 7 Binary Grid (.grd)' : 'grd',
+            'R Object Data Store' : 'r',
+            'USGS DOQ (Old Style)' : 'doq',
+            'USGS DOQ (New Style)' : 'doq',
+            'ENVI .hdr Labelled' : 'hdr',
+            'ESRI .hdr Labelled' : 'hdr',
+            'Generic Binary (.hdr Labelled)' : 'hdr',
+            'PCI .aux Labelled' : 'aux',
+            'EOSAT FAST Format' : 'fst',
+            'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
+            'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
+            'Swedish Grid RIK (.rik)' : 'rik',
+            'USGS Optional ASCII DEM (and CDED)' : 'dem',
+            'Northwood Numeric Grid Format .grd/.tab' : '',
+            'Northwood Classified Grid Format .grc/.tab' : '',
+            'ARC Digitized Raster Graphics' : 'arc',
+            'Magellan topo (.blx)' : 'blx',
+            'SAGA GIS Binary Grid (.sdat)' : 'sdat',
+            # vector
+            'ESRI Shapefile' : 'shp',
+            'UK .NTF'        : 'ntf',
+            'SDTS'           : 'ddf',
+            'DGN'            : 'dgn',
+            'VRT'            : 'vrt',
+            'REC'            : 'rec',
+            'BNA'            : 'bna',
+            'CSV'            : 'csv',
+            'GML'            : 'gml',
+            'GPX'            : 'gpx',
+            'KML'            : 'kml',
+            'GMT'            : 'gmt',
+            'PGeo'           : 'mdb',
+            'XPlane'         : 'dat',
+            'AVCBin'         : 'adf',
+            'AVCE00'         : 'e00',
+            'DXF'            : 'dxf',
+            'Geoconcept'     : 'gxt',
+            'GeoRSS'         : 'xml',
+            'GPSTrackMaker'  : 'gtm',
+            'VFK'            : 'vfk'
+            }
+        
+        try:
+            return formatToExt[name]
+        except KeyError:
+            return ''
+        
+class GdalSelect(wx.Panel):
+    def __init__(self, parent, panel, ogr = False, dest = False, 
+                 default = 'file', exclude = [], envHandler = None):
+        """!Widget for selecting GDAL/OGR datasource, format
+        
+        @param parent parent window
+        @param ogr    use OGR selector instead of GDAL
+        @param dest   True for output (destination)
+        @param default deafult type (ignored when dest == True)
+        @param exclude list of types to be excluded
+        """
+        self.parent = parent
+        self.ogr    = ogr
+        self.dest   = dest 
+        wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
+
+        self.settingsBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                        label = " %s " % _("Settings"))
+        
+        self.inputBox = wx.StaticBox(parent = self, id = wx.ID_ANY)
+        if dest:
+            self.inputBox.SetLabel(" %s " % _("Output settings"))
+        else:
+            self.inputBox.SetLabel(" %s " % _("Source settings"))
+        
+        # source type
+        sources = list()
+        self.sourceMap = { 'file' : -1,
+                           'dir'  : -1,
+                           'db'   : -1,
+                           'pro'  : -1,
+                           'native' : -1 }
+        idx = 0
+        if dest:
+            sources.append(_("Native"))
+            self.sourceMap['native'] = idx
+            idx += 1
+        if 'file' not in exclude:
+            sources.append(_("File"))
+            self.sourceMap['file'] = idx
+            idx += 1
+        if 'directory' not in exclude:
+            sources.append(_("Directory"))
+            self.sourceMap['dir'] = idx
+            idx += 1
+        if 'database' not in exclude:
+            sources.append(_("Database"))
+            self.sourceMap['db'] = idx
+            idx += 1
+        if 'protocol' not in exclude:
+            sources.append(_("Protocol"))
+            self.sourceMap['pro'] = idx
+        
+        if self.ogr:
+            self.settingsFile = os.path.join(GetSettingsPath(), 'wxOGR')
+        else:
+            self.settingsFile = os.path.join(GetSettingsPath(), 'wxGDAL')
+        
+        self._settings = self._loadSettings()
+        self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
+        self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsLoad)
+        self.settingsChoice.SetItems(self._settings.keys())
+        self.btnSettings = wx.Button(parent = self, id = wx.ID_SAVE)
+        self.btnSettings.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
+        
+        self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
+                                  style = wx.RA_SPECIFY_COLS,
+                                  choices = sources)
+        if dest:
+            self.source.SetLabel(" %s " % _('Output type'))
+        else:
+            self.source.SetLabel(" %s " % _('Source type'))
+        
+        self.source.SetSelection(0)
+        self.source.Bind(wx.EVT_RADIOBOX, self.OnSetType)
+        
+        # dsn widgets
+        if not ogr:
+            filemask = 'GeoTIFF (%s)|%s|%s (*.*)|*.*' % \
+                (self._getExtPattern('tif'), self._getExtPattern('tif'), _('All files'))
+        else:
+            filemask = 'ESRI Shapefile (%s)|%s|%s (*.*)|*.*' % \
+                (self._getExtPattern('shp'), self._getExtPattern('shp'), _('All files'))
+        
+        dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
+                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText = '',
+                                              dialogTitle=_('Choose file to import'),
+                                              buttonText=_('Browse'),
+                                              startDirectory=os.getcwd(),
+                                              changeCallback=self.OnSetDsn,
+                                              fileMask=filemask)
+        dsnFile.Hide()
+        
+        dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY, 
+                                            size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+                                            dialogTitle=_('Choose input directory'),
+                                            buttonText=_('Browse'),
+                                            startDirectory=os.getcwd(),
+                                            changeCallback=self.OnSetDsn)
+        dsnDir.SetName('GdalSelect')
+        dsnDir.Hide()
+        
+        dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
+                                                size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+                                                dialogTitle=_('Choose file'),
+                                                buttonText=_('Browse'),
+                                                startDirectory=os.getcwd(),
+                                                changeCallback=self.OnSetDsn)
+        dsnDbFile.Hide()
+        dsnDbFile.SetName('GdalSelect')
+
+        dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        dsnDbText.Hide()
+        dsnDbText.Bind(wx.EVT_TEXT, self.OnSetDsn)
+        dsnDbText.SetName('GdalSelect')
+
+        dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
+        dsnDbChoice.Hide()
+        dsnDbChoice.Bind(wx.EVT_CHOICE, self.OnSetDsn)
+        dsnDbChoice.SetName('GdalSelect')
+
+        dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        dsnPro.Hide()
+        dsnPro.Bind(wx.EVT_TEXT, self.OnSetDsn)
+        dsnPro.SetName('GdalSelect')
+
+        # format
+        self.format = FormatSelect(parent = self,
+                                   ogr = ogr)
+        self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
+        self.extension = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        self.extension.Bind(wx.EVT_TEXT, self.OnSetExtension)
+        self.extension.Hide()
+        
+        if ogr:
+            fType = 'ogr'
+        else:
+            fType = 'gdal'
+        self.input = { 'file' : [_("File:"),
+                                 dsnFile,
+                                 GetFormats(writableOnly = dest)[fType]['file']],
+                       'dir'  : [_("Name:"),
+                                 dsnDir,
+                                 GetFormats(writableOnly = dest)[fType]['file']],
+                       'db'   : [_("Name:"),
+                                 dsnDbText,
+                                 GetFormats(writableOnly = dest)[fType]['database']],
+                       'pro'  : [_("Protocol:"),
+                                 dsnPro,
+                                 GetFormats(writableOnly = dest)[fType]['protocol']],
+                       'db-win' : { 'file'   : dsnDbFile,
+                                    'text'   : dsnDbText,
+                                    'choice' : dsnDbChoice },
+                       'native' : [_("Name:"), dsnDir, ''],
+                       }
+        
+        if self.dest:
+            current = RunCommand('v.external.out',
+                                 parent = self,
+                                 read = True, parse = grass.parse_key_val,
+                                 flags = 'g')
+            if current['format'] == 'native':
+                self.dsnType = 'native'
+            elif current['format'] in GetFormats()['ogr']['database']:
+                self.dsnType = 'db'
+            else:
+                self.dsnType = 'dir'
+        else:
+            self.dsnType = default
+        
+        self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                     label = self.input[self.dsnType][0],
+                                     size = (75, -1))
+        self.extensionText = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                           label = _("Extension:"))
+        self.extensionText.Hide()
+        
+        self.creationOpt = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+        if not self.dest:
+            self.creationOpt.Hide()
+        
+        self._layout()
+        
+        self.OnSetType(event = None, sel = self.sourceMap[self.dsnType])
+        if self.dest:
+            if current['format'] != 'native':
+                self.OnSetFormat(event = None, format = current['format'])
+                self.OnSetDsn(event = None, path = current['dsn'])
+                self.creationOpt.SetValue(current['options'])
+        else:
+            if not ogr:
+                self.OnSetFormat(event = None, format = 'GeoTIFF')
+            else:
+                self.OnSetFormat(event = None, format = 'ESRI Shapefile')
+        
+    def _layout(self):
+        """!Layout"""
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
+        settingsSizer.Add(item = wx.StaticText(parent = self,
+                                               id = wx.ID_ANY,
+                                               label = _("Load settings:")),
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
+                          border  = 5)
+        settingsSizer.Add(item = self.settingsChoice,
+                          proportion = 1,
+                          flag = wx.EXPAND)
+        settingsSizer.Add(item = self.btnSettings,
+                          flag = wx.LEFT,
+                          border = 5)
+        
+        inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
+        
+        self.dsnSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        #self.dsnSizer.AddGrowableRow(0)
+        self.dsnSizer.AddGrowableCol(3)
+        
+        row = 0
+        self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                               label = _("Format:")),
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 0))
+        self.dsnSizer.Add(item=self.format,
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 1))
+        self.dsnSizer.Add(item = self.extensionText,
+                          flag=wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 2))
+        self.dsnSizer.Add(item=self.extension,
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 3))
+        row += 1
+        self.dsnSizer.Add(item = self.dsnText,
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 0))
+        self.dsnSizer.Add(item = self.input[self.dsnType][1],
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                          pos = (row, 1), span = (1, 3))
+        row += 1
+        if self.creationOpt.IsShown():
+            self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                                   label = _("Creation options:")),
+                              flag = wx.ALIGN_CENTER_VERTICAL,
+                              pos = (row, 0))
+            self.dsnSizer.Add(item = self.creationOpt,
+                              flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                              pos = (row, 1), span = (1, 3))
+            row += 1
+        
+        inputSizer.Add(item=self.dsnSizer, proportion = 1,
+                       flag=wx.EXPAND | wx.BOTTOM, border = 10)
+        
+        mainSizer.Add(item=settingsSizer, proportion=0,
+                      flag=wx.ALL | wx.EXPAND, border=5)
+        mainSizer.Add(item=self.source, proportion=0,
+                      flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
+        mainSizer.Add(item=inputSizer, proportion=0,
+                      flag=wx.ALL | wx.EXPAND, border=5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+    def _getExtPatternGlob(self, ext):
+        """!Get pattern for case-insensitive globing"""
+        pattern = '*.'
+        for c in ext:
+            pattern += '[%s%s]' % (c.lower(), c.upper())
+        return pattern
+    
+    def _getExtPattern(self, ext):
+        """!Get pattern for case-insensitive file mask"""
+        return '*.%s;*.%s' % (ext.lower(), ext.upper())
+
+    def OnSettingsLoad(self, event):
+        """!Load named settings"""
+        name = event.GetString()
+        if name not in self._settings:
+            GError(parent = self,
+                   message = _("Settings <%s> not found") % name)
+            return
+        data = self._settings[name]
+        self.OnSetType(event = None, sel = self.sourceMap[data[0]])
+        self.OnSetFormat(event = None, format = data[2])
+        self.OnSetDsn(event = None, path = data[1])
+        self.creationOpt.SetValue(data[3])
+        
+    def OnSettingsSave(self, event):
+        """!Save settings"""
+        dlg = wx.TextEntryDialog(parent = self,
+                                 message = _("Name:"),
+                                 caption = _("Save settings"))
+        if dlg.ShowModal() != wx.ID_OK:
+            return
+        
+        if not dlg.GetValue():
+            GMessage(parent = self,
+                     message = _("Name not given, settings is not saved."))
+            return
+        
+        name = dlg.GetValue()
+        try:
+            fd = open(self.settingsFile, 'a')
+            fd.write(name + ';' + self.dsnType + ';' +
+                     self.GetDsn() + ';' +
+                     self.format.GetStringSelection())
+            fd.write('\n')
+        except IOError:
+            GError(parent = self,
+                   message = _("Unable to save settings"))
+            return
+        fd.close()
+        
+        self._settings = self._loadSettings()
+        self.settingsChoice.Append(name)
+        self.settingsChoice.SetStringSelection(name)
+        
+        dlg.Destroy()
+                
+    def _loadSettings(self):
+        """!Load settings from the file
+
+        The file is defined by self.SettingsFile.
+        
+        @return parsed dict
+        @return empty dict on error
+        """
+        data = dict()
+        if not os.path.exists(self.settingsFile):
+            return data
+        
+        try:
+            fd = open(self.settingsFile, 'r')
+            for line in fd.readlines():
+                try:
+                    lineData = line.rstrip('\n').split(';')
+                    if len(lineData) > 4:
+                        # type, dsn, format, options
+                        data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
+                    else:
+                        data[lineData[0]] = (lineData[1], lineData[2], lineData[3], '')
+                except ValueError:
+                    pass
+        except IOError:
+            return data
+        
+        fd.close()
+        
+        return data
+
+    def OnSetType(self, event, sel = None):
+        """!Datasource type changed"""
+        if event:
+            sel = event.GetSelection()
+        else:
+            self.source.SetSelection(sel)
+        win = self.input[self.dsnType][1]
+        if win:
+            self.dsnSizer.Remove(win)
+            win.Hide()
+        
+        if sel == self.sourceMap['file']:   # file
+            self.dsnType = 'file'
+            format = self.input[self.dsnType][2][0]
+            try:
+                ext = self.format.GetExtension(format)
+                if not ext:
+                    raise KeyError
+                format += ' (%s)|%s|%s (*.*)|*.*' % \
+                    (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
+            except KeyError:
+                format += '%s (*.*)|*.*' % _('All files')
+            
+            win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
+                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+                                              dialogTitle=_('Choose file to import'),
+                                              buttonText=_('Browse'),
+                                              startDirectory=os.getcwd(),
+                                              changeCallback=self.OnSetDsn,
+                                              fileMask = format)
+            self.input[self.dsnType][1] = win
+        
+        elif sel == self.sourceMap['dir']: # directory
+            self.dsnType = 'dir'
+        elif sel == self.sourceMap['db']:  # database
+            self.dsnType = 'db'
+        elif sel == self.sourceMap['pro']: # protocol
+            self.dsnType = 'pro'
+        elif sel == self.sourceMap['native']:
+            self.dsnType = 'native'
+        
+        if self.dsnType == 'db':
+            self.input[self.dsnType][1] = self.input['db-win']['text']
+        win = self.input[self.dsnType][1]
+                
+        self.dsnSizer.Add(item = self.input[self.dsnType][1],
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                          pos = (1, 1), span = (1, 3))
+        win.SetValue('')
+        win.Show()
+        
+        if sel == self.sourceMap['native']: # native
+            win.Enable(False)
+            self.format.Enable(False)
+            self.creationOpt.Enable(False)
+            self.parent.btnOk.Enable(True)
+        else:
+            if not self.format.IsEnabled():
+                win.Enable(True)
+                self.format.Enable(True)
+                self.creationOpt.Enable(True)
+            self.dsnText.SetLabel(self.input[self.dsnType][0])
+            self.format.SetItems(self.input[self.dsnType][2])
+            if self.parent.GetName() == 'MultiImportDialog':
+                self.parent.list.DeleteAllItems()
+        
+        if sel in (self.sourceMap['file'],
+                   self.sourceMap['dir']):
+            if not self.ogr:
+                self.OnSetFormat(event = None, format = 'GeoTIFF')
+            else:
+                self.OnSetFormat(event = None, format = 'ESRI Shapefile')
+        
+        if sel == self.sourceMap['dir'] and not self.dest:
+            if not self.extension.IsShown():
+                self.extensionText.Show()
+                self.extension.Show()
+        else:
+            if self.extension.IsShown():
+                self.extensionText.Hide()
+                self.extension.Hide()
+        
+        self.dsnSizer.Layout()
+        
+    def GetDsn(self):
+        """!Get datasource name"""
+        if self.format.GetStringSelection() == 'PostgreSQL':
+            return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
+        
+        return self.input[self.dsnType][1].GetValue()
+    
+    def OnSetDsn(self, event, path = None):
+        """!Input DXF file/OGR dsn defined, update list of layer
+        widget"""
+        if event:
+            path = event.GetString()
+        else:
+            if self.format.GetStringSelection() == 'PostgreSQL':
+                for item in path.split(':', 1)[1].split(','):
+                    key, value = item.split('=', 1)
+                    if key == 'dbname':
+                        self.input[self.dsnType][1].SetStringSelection(value)
+                        break
+            else:
+                self.input[self.dsnType][1].SetValue(path)
+
+        if not path:
+            if self.dest:
+                self.parent.btnOk.Enable(False)
+            return
+        
+        if self.dest:
+            self.parent.btnOk.Enable(True)
+        else:
+            self._reloadLayers()
+        
+        if event:
+            event.Skip()
+        
+    def _reloadLayers(self):
+        """!Reload list of layers"""
+        dsn = self.GetDsn()
+        if not dsn:
+            return
+        
+        data = list()        
+        layerId = 1
+        
+        if self.ogr:
+            ret = RunCommand('v.in.ogr',
+                             quiet = True,
+                             read = True,
+                             flags = 'a',
+                             dsn = dsn)
+                
+            if not ret:
+                self.parent.list.LoadData()
+                if hasattr(self, "btn_run"):
+                    self.btn_run.Enable(False)
+                return
+            
+            layerId = 1
+            for line in ret.splitlines():
+                layerName, featureType = map(lambda x: x.strip(), line.split(' ', 1))
+                grassName = GetValidLayerName(layerName)
+                data.append((layerId, layerName, featureType, grassName))
+                layerId += 1
+        else:
+            if self.dsnType == 'file':
+                baseName = os.path.basename(dsn)
+                grassName = GetValidLayerName(baseName.split('.', -1)[0])
+                data.append((layerId, baseName, grassName))
+            elif self.dsnType == 'dir':
+                ext = self.extension.GetValue()
+                for filename in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
+                    baseName = os.path.basename(filename)
+                    grassName = GetValidLayerName(baseName.split('.', -1)[0])
+                    data.append((layerId, baseName, grassName))
+                    layerId += 1
+        if self.ogr:
+            dsn += '@OGR'
+        
+        evt = wxGdalSelect(dsn = dsn)
+        evt.SetId(self.input[self.dsnType][1].GetId())
+        wx.PostEvent(self.parent, evt)
+        
+        if self.parent.GetName() == 'MultiImportDialog':
+            self.parent.list.LoadData(data)
+            if len(data) > 0:
+                self.parent.btn_run.Enable(True)
+            else:
+                self.parent.btn_run.Enable(False)
+        
+    def OnSetExtension(self, event):
+        """!Extension changed"""
+        if not self.dest:
+            # reload layers
+            self._reloadLayers()
+        
+    def OnSetFormat(self, event, format = None):
+        """!Format changed"""
+        if self.dsnType not in ['file', 'dir', 'db']:
+            return
+        
+        win = self.input[self.dsnType][1]
+        self.dsnSizer.Remove(win)
+        
+        if self.dsnType == 'file':
+            win.Destroy()
+        else: # database
+            win.Hide()
+        
+        if event:
+            format = event.GetString()
+        else:
+            self.format.SetStringSelection(format)
+        
+        if self.dsnType == 'file':
+            try:
+                ext = self.format.GetExtension(format)
+                if not ext:
+                    raise KeyError
+                format += ' (%s)|%s|%s (*.*)|*.*' % \
+                    (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
+            except KeyError:
+                format += '%s (*.*)|*.*' % _('All files')
+            
+            win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
+                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+                                              dialogTitle=_('Choose file'),
+                                              buttonText=_('Browse'),
+                                              startDirectory=os.getcwd(),
+                                              changeCallback=self.OnSetDsn,
+                                              fileMask = format)
+            
+        elif self.dsnType == 'dir':
+            pass
+        
+        else: # database
+            if format == 'SQLite' or format == 'Rasterlite':
+                win = self.input['db-win']['file']
+            elif format == 'PostgreSQL' or format == 'PostGIS WKT Raster driver':
+                if grass.find_program('psql', ['--help']):
+                    win = self.input['db-win']['choice']
+                    if not win.GetItems():
+                        p = grass.Popen(['psql', '-ltA'], stdout = grass.PIPE)
+                        ret = p.communicate()[0]
+                        if ret:
+                            db = list()
+                            for line in ret.splitlines():
+                                sline = line.split('|')
+                                if len(sline) < 2:
+                                    continue
+                                dbname = sline[0]
+                                if dbname:
+                                    db.append(dbname)
+                            win.SetItems(db)
+                    if self.dest and win.GetStringSelection():
+                        self.parent.btnOk.Enable(True)
+                else:
+                    win = self.input['db-win']['text']
+            else:
+                win = self.input['db-win']['text']
+        
+        self.input[self.dsnType][1] = win
+        if not win.IsShown():
+            win.Show()
+        self.dsnSizer.Add(item = self.input[self.dsnType][1],
+                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                          pos = (1, 1), span = (1, 3))
+        self.dsnSizer.Layout()
+        
+        # update extension
+        self.extension.SetValue(self.GetFormatExt())
+
+        if not self.dest:
+            # reload layers
+            self._reloadLayers()
+        
+    def GetType(self):
+        """!Get source type"""
+        return self.dsnType
+
+    def GetDsn(self):
+        """!Get DSN"""
+        if self.format.GetStringSelection() == 'PostgreSQL':
+            return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
+        
+        return self.input[self.dsnType][1].GetValue()
+
+    def GetDsnWin(self):
+        """!Get list of DSN windows"""
+        win = list()
+        for stype in ('file', 'dir', 'pro'):
+            win.append(self.input[stype][1])
+        for stype in ('file', 'text', 'choice'):
+            win.append(self.input['db-win'][stype])
+        
+        return win
+    
+    def GetFormat(self):
+        """!Get format as string"""
+        return self.format.GetStringSelection().replace(' ', '_')
+    
+    def GetFormatExt(self):
+        """!Get format extension"""
+        return self.format.GetExtension(self.format.GetStringSelection())
+    
+    def GetOptions(self):
+        """!Get creation options"""
+        if not self.creationOpt.IsShown():
+            return ''
+        
+        return self.creationOpt.GetValue()
+    
+class ProjSelect(wx.ComboBox):
+    """!Widget for selecting input raster/vector map used by
+    r.proj/v.proj modules."""
+    def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
+                 **kwargs):
+        super(ProjSelect, self).__init__(parent, id, size = size, 
+                                         style = wx.CB_READONLY, **kwargs)
+        self.SetName("ProjSelect")
+        self.isRaster = isRaster
+        
+    def UpdateItems(self, dbase, location, mapset):
+        """!Update list of maps
+        
+        """
+        if not dbase:
+            dbase = grass.gisenv()['GISDBASE']
+        if not mapset:
+            mapset = grass.gisenv()['MAPSET']
+        if self.isRaster:
+            ret = RunCommand('r.proj',
+                             quiet = True,
+                             read = True,
+                             flags = 'l',
+                             dbase = dbase,
+                             location = location,
+                             mapset = mapset)
+        else:
+            ret = RunCommand('v.proj',
+                             quiet = True,
+                             read = True,
+                             flags = 'l',
+                             dbase = dbase,
+                             location = location,
+                             mapset = mapset)
+        listMaps = list()
+        if ret:
+            for line in ret.splitlines():
+                listMaps.append(line.strip())
+        ListSortLower(listMaps)
+        
+        self.SetItems(listMaps)
+        self.SetValue('')
+
+class ElementSelect(wx.Choice):
+    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
+                 **kwargs):
+        """!Widget for selecting GIS element
+        
+        @param parent parent window
+        """
+        super(ElementSelect, self).__init__(parent, id, size = size, 
+                                            style = wx.CB_READONLY, **kwargs)
+        self.SetName("ElementSelect")
+        
+        task = gtask.parse_interface('g.list')
+        p = task.get_param(value = 'type')
+        self.values = p.get('values', [])
+        self.valuesDesc = p.get('values_desc', [])
+        
+        self.SetItems(self.valuesDesc)
+
+    def GetValue(self, name):
+        """!Translate value
+
+        @param name element name
+        """
+        idx = self.valuesDesc.index(name)
+        if idx > -1:
+            return self.values[idx]
+        return ''
+
+class OgrTypeSelect(wx.Panel):
+    def __init__(self, parent, panel, **kwargs):
+        """!Widget to choose OGR feature type
+
+        @param parent parent window
+        @param panel wx.Panel instance used as parent window
+        """
+        wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
+        
+        self.ftype = wx.Choice(parent = self, id = wx.ID_ANY,
+                               size = (200, -1),
+                               choices = (_("Point"), _("LineString"), _("Polygon")))
+        self._layout()
+
+    def _layout(self):
+        """!Do layout"""
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(item = wx.StaticText(parent = self,
+                                       id = wx.ID_ANY,
+                                       label = _("Feature type:")),
+                  proportion = 1,
+                  flag = wx.ALIGN_CENTER_VERTICAL,
+                  border  = 5)
+        sizer.Add(item = self.ftype,
+                  proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_RIGHT)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def GetType(self):
+        """!Get selected type as string
+
+        @return feature type as string
+        """
+        sel = self.ftype.GetSelection()
+        if sel == 0:
+            return 'point'
+        elif sel == 1:
+            return 'line'
+        elif sel == 2:
+            return 'boundary'

Added: grass/trunk/gui/wxpython/gui_core/mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/mapdisp.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/mapdisp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,337 @@
+"""!
+ at package gui_core.mapdisp
+
+ at brief Base classes for Map display window
+
+Classes:
+ - MapFrameBase
+
+(C) 2009-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton <michael.barton at asu.edu>
+"""
+
+import os
+
+import wx
+
+from core       import globalvar
+from core.debug import Debug
+
+from grass.script import core as grass
+
+class MapFrameBase(wx.Frame):
+    """!Base class for map display window
+    
+    Derived class must use statusbarManager or override
+    GetProperty, SetProperty and HasProperty methods.
+    If derived class enables and disables auto-rendering,
+    it should override IsAutoRendered method.
+    """
+    def __init__(self, parent = None, id = wx.ID_ANY, title = None,
+                 style = wx.DEFAULT_FRAME_STYLE, toolbars = None,
+                 Map = None, auimgr = None, name = None, **kwargs):
+        """!
+        @param toolbars array of activated toolbars, e.g. ['map', 'digit']
+        @param Map instance of render.Map
+        @param auimgs AUI manager
+        @param name frame name
+        @param kwargs wx.Frame attributes
+        """
+        
+
+        self.Map        = Map       # instance of render.Map
+        self.parent     = parent
+        
+        wx.Frame.__init__(self, parent, id, title, style = style, name = name, **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))
+        
+        # toolbars
+        self.toolbars = {}
+        
+        #
+        # Fancy gui
+        #
+        self._mgr = wx.aui.AuiManager(self)
+        
+    def _initMap(self, map):
+        """!Initialize map display, set dimensions and map region
+        """
+        if not grass.find_program('g.region', ['--help']):
+            sys.exit(_("GRASS module '%s' not found. Unable to start map "
+                       "display window.") % 'g.region')
+        
+        self.width, self.height = self.GetClientSize()
+        
+        Debug.msg(2, "MapFrame._initMap():")
+        map.ChangeMapSize(self.GetClientSize())
+        map.region = map.GetRegion() # g.region -upgc
+        # self.Map.SetRegion() # adjust region to match display window
+        
+    def SetProperty(self, name, value):
+        """!Sets property"""
+        self.statusbarManager.SetProperty(name, value)
+        
+    def GetProperty(self, name):
+        """!Returns property"""
+        return self.statusbarManager.GetProperty(name)
+        
+    def HasProperty(self, name):
+        """!Checks whether object has property"""
+        return self.statusbarManager.HasProperty(name)
+    
+    def GetPPM(self):
+        """! Get pixel per meter
+        
+        @todo now computed every time, is it necessary?
+        @todo enable user to specify ppm (and store it in UserSettings)
+        """
+        # 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
+        ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
+                    (ppi[1] / 2.54) * 100)
+        
+        Debug.msg(4, "MapFrameBase.GetPPM(): 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],
+                   ppm[0], ppm[1]))
+        
+        return ppm
+    
+    def SetMapScale(self, value, map = None):
+        """! Set current map scale
+        
+        @param value scale value (n if scale is 1:n)
+        @param map Map instance (if none self.Map is used)
+        """
+        if not map:
+            map = self.Map
+        
+        region = self.Map.region
+        dEW = value * (region['cols'] / self.GetPPM()[0])
+        dNS = value * (region['rows'] / self.GetPPM()[1])
+        region['n'] = region['center_northing'] + dNS / 2.
+        region['s'] = region['center_northing'] - dNS / 2.
+        region['w'] = region['center_easting']  - dEW / 2.
+        region['e'] = region['center_easting']  + dEW / 2.
+        
+        # add to zoom history
+        self.GetWindow().ZoomHistory(region['n'], region['s'],
+                                   region['e'], region['w'])
+    
+    def GetMapScale(self, map = None):
+        """! Get current map scale
+        
+        @param map Map instance (if none self.Map is used)
+        """
+        if not map:
+            map = self.Map
+        
+        region = map.region
+        ppm = self.GetPPM()
+
+        heightCm = region['rows'] / ppm[1] * 100
+        widthCm  = region['cols'] / ppm[0] * 100
+
+        Debug.msg(4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" %
+                  (widthCm, heightCm))
+
+        xscale = (region['e'] - region['w']) / (region['cols'] / ppm[0])
+        yscale = (region['n'] - region['s']) / (region['rows'] / ppm[1])
+        scale = (xscale + yscale) / 2.
+        
+        Debug.msg(3, "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" % \
+                      (xscale, yscale, scale))
+        
+        return scale
+        
+    def GetProgressBar(self):
+        """!Returns progress bar
+        
+        Progress bar can be used by other classes.
+        """
+        return self.statusbarManager.GetProgressBar()
+        
+    def GetMap(self):
+        """!Returns current Map instance
+        """
+        return self.Map
+
+    def GetWindow(self):
+        """!Get map window"""
+        return self.MapWindow
+        
+    def GetMapToolbar(self):
+       """!Returns toolbar with zooming tools"""
+       raise NotImplementedError()
+       
+    def GetToolbar(self, name):
+        """!Returns toolbar if exists else None.
+        
+        Toolbars dictionary contains currently used toolbars only.
+        """
+        if name in self.toolbars:
+            return self.toolbars[name]
+        
+        return None
+       
+    def StatusbarUpdate(self):
+        """!Update statusbar content"""
+        self.statusbarManager.Update()
+        
+    def IsAutoRendered(self):
+        """!Check if auto-rendering is enabled"""
+        return self.GetProperty('render')
+        
+    def CoordinatesChanged(self):
+        """!Shows current coordinates on statusbar.
+        
+        Used in BufferedWindow to report change of map coordinates (under mouse cursor).
+        """
+        self.statusbarManager.ShowItem('coordinates')
+        
+    def StatusbarReposition(self):
+        """!Reposition items in statusbar"""
+        self.statusbarManager.Reposition()
+        
+    def StatusbarEnableLongHelp(self, enable = True):
+        """!Enable/disable toolbars long help"""
+        for toolbar in self.toolbars.itervalues():
+            toolbar.EnableLongHelp(enable)
+        
+    def IsStandalone(self):
+        """!Check if Map display is standalone"""
+        raise NotImplementedError("IsStandalone")
+   
+    def OnRender(self, event):
+        """!Re-render map composition (each map layer)
+        """
+        raise NotImplementedError("OnRender")
+        
+    def OnDraw(self, event):
+        """!Re-display current map composition
+        """
+        self.MapWindow.UpdateMap(render = False)
+        
+    def OnErase(self, event):
+        """!Erase the canvas
+        """
+        self.MapWindow.EraseMap()
+        
+    def OnZoomIn(self, event):
+        """!Zoom in the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        toolbar = self.GetMapToolbar()
+        self._switchTool(toolbar, event)
+        
+        win = self.GetWindow()
+        self._prepareZoom(mapWindow = win, zoomType = 1)
+        
+    def OnZoomOut(self, event):
+        """!Zoom out the map.
+        Set mouse cursor, zoombox attributes, and zoom direction
+        """
+        toolbar = self.GetMapToolbar()
+        self._switchTool(toolbar, event)
+        
+        win = self.GetWindow()
+        self._prepareZoom(mapWindow = win, zoomType = -1)
+        
+    def _prepareZoom(self, mapWindow, zoomType):
+        """!Prepares MapWindow for zoom, toggles toolbar
+        
+        @param mapWindow MapWindow to prepare
+        @param zoomType 1 for zoom in, -1 for zoom out
+        """
+        mapWindow.mouse['use'] = "zoom"
+        mapWindow.mouse['box'] = "box"
+        mapWindow.zoomtype = zoomType
+        mapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
+        
+        # change the cursor
+        mapWindow.SetCursor(self.cursors["cross"])
+    
+    def _switchTool(self, toolbar, event):
+        """!Helper function to switch tools"""
+        if toolbar:
+            toolbar.OnTool(event)
+            toolbar.action['desc'] = ''
+            
+    def OnPan(self, event):
+        """!Panning, set mouse to drag
+        """
+        toolbar = self.GetMapToolbar()
+        self._switchTool(toolbar, event)
+        
+        win = self.GetWindow()
+        self._preparePan(mapWindow = win)
+    
+    def _preparePan(self, mapWindow):
+        """!Prepares MapWindow for pan, toggles toolbar
+        
+        @param mapWindow MapWindow to prepare
+        """
+        mapWindow.mouse['use'] = "pan"
+        mapWindow.mouse['box'] = "pan"
+        mapWindow.zoomtype = 0
+        
+        # change the cursor
+        mapWindow.SetCursor(self.cursors["hand"])
+        
+    def OnZoomBack(self, event):
+        """!Zoom last (previously stored position)
+        """
+        self.MapWindow.ZoomBack()
+        
+    def OnZoomToMap(self, event):
+        """!
+        Set display extents to match selected raster (including NULLs)
+        or vector map.
+        """
+        self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
+    
+    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()


Property changes on: grass/trunk/gui/wxpython/gui_core/mapdisp.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/gui_core/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/mapwindow.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/mapwindow.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,238 @@
+"""!
+ at package gui_core.mapwindow
+
+ at brief Map display canvas - base class for buffered window.
+
+Classes:
+ - MapWindow
+
+(C) 2006-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton
+ at author Jachym Cepicky
+"""
+
+import wx
+
+class MapWindow(object):
+    """!Abstract map display window class
+    
+    Superclass for BufferedWindow class (2D display mode), and GLWindow
+    (3D display mode).
+    
+    Subclasses have to define
+     - _bindMouseEvents method which binds MouseEvent handlers
+     - Pixel2Cell
+     - Cell2Pixel (if it is possible)
+    
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 Map = None, tree = None, lmgr = None, **kwargs):
+        self.parent = parent # MapFrame
+        self.Map    = Map
+        self.tree   = tree
+        self.lmgr   = lmgr
+        
+        # mouse attributes -- position on the screen, begin and end of
+        # dragging, and type of drawing
+        self.mouse = {
+            'begin': [0, 0], # screen coordinates
+            'end'  : [0, 0],
+            'use'  : "pointer",
+            'box'  : "point"
+            }
+        # last east, north coordinates, changes on mouse motion
+        self.lastEN = None 
+        
+        # stores overridden cursor
+        self._overriddenCursor = None
+
+    def RegisterMouseEventHandler(self, event, handler, cursor = None):
+        """!Binds event handler
+        
+        Call event.Skip() in handler to allow default processing in MapWindow.
+        
+        @code
+        # your class methods
+        def OnButton(self, event):
+            # current map display's map window
+            # expects LayerManager to be the parent
+            self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
+            if self.mapwin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
+                                                     wx.StockCursor(wx.CURSOR_CROSS)):
+                self.parent.GetLayerTree().GetMapDisplay().Raise()
+            else:
+                # handle that you cannot get coordinates
+        
+        def OnMouseAction(self, event):
+            # get real world coordinates of mouse click
+            coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
+            self.text.SetLabel('Coor: ' + str(coor))
+            self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN)
+            event.Skip()
+        @endcode
+        
+        @param event one of mouse events
+        @param handler function to handle event
+        @param cursor cursor which temporary overrides current cursor
+        
+        @return True if successful
+        @return False if event cannot be bind
+        """
+        
+        # if it is a VDigitWindow it cannot be used
+        # hasattr is ugly
+        if hasattr(self, "digit"):
+            return False
+        
+        self.Bind(event, handler)
+        self.mouse['useBeforeGenericEvent'] = self.mouse['use']
+        self.mouse['use'] = 'genericEvent'
+        
+        if cursor:
+            self._overriddenCursor = self.GetCursor()
+            self.SetCursor(cursor)
+        
+        return True
+
+
+    def UnregisterMouseEventHandler(self, event):
+        """!Unbinds event handler a restores previous state
+        
+        You should unbind to restore normal MapWindow behaviour.
+        Note that this operation will unbind any other external (non-MapWindow) handlers.
+        
+        @param event event to unbind
+        
+        @return True if successful
+        @return False if event cannot be unbind
+        """
+        if hasattr(self, "digit"):
+            return False
+        
+        # it is not yet possible in wxPython to unbind exact event
+        ret = self.Unbind(event)
+        
+        # restore bind state
+        self._bindMouseEvents()
+        
+        # restore mouse use (previous state)
+        self.mouse['use'] = self.mouse['useBeforeGenericEvent']
+        
+        # restore overridden cursor
+        if self._overriddenCursor:
+            self.SetCursor(self._overriddenCursor)
+        
+        return ret
+    
+    def Pixel2Cell(self, (x, y)):
+        raise NotImplementedError()
+    
+    def Cell2Pixel(self, (east, north)):
+        raise NotImplementedError()
+
+    def OnMotion(self, event):
+        """!Tracks mouse motion and update statusbar
+        
+        @see GetLastEN
+        """
+        try:
+            self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
+        except (ValueError):
+            self.lastEN = None
+        # FIXME: special case for vdigit and access to statusbarManager
+        if self.parent.statusbarManager.GetMode() == 0: # Coordinates            
+            updated = False
+            if hasattr(self, "digit"):
+                precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                                             subkey = 'precision'))
+                updated = self._onMotion(self.lastEN, precision)
+
+            if not updated:
+                self.parent.CoordinatesChanged()
+        
+        event.Skip()
+
+    def GetLastEN(self):
+        """!Returns last coordinates of mouse cursor.
+        
+        @see OnMotion
+        """
+        return self.lastEN
+    
+    def GetLayerByName(self, name, mapType, dataType = 'layer'):
+        """!Get layer from layer tree by nam
+        
+        @param name layer name
+        @param type 'item' / 'layer' / 'nviz'
+
+        @return layer / map layer properties / nviz properties
+        @return None
+        """
+        if not self.tree:
+            return None
+        
+        try:
+            mapLayer = self.Map.GetListOfLayers(l_type = mapType, l_name = name)[0]
+        except IndexError:
+            return None
+        
+        if dataType == 'layer':
+            return mapLayer
+        item = self.tree.FindItemByData('maplayer', mapLayer)
+        if not item:
+            return None
+        if dataType == 'nviz':
+            return self.tree.GetPyData(item)[0]['nviz']
+        
+        return item
+        
+    def GetSelectedLayer(self, type = 'layer', multi = False):
+        """!Get selected layer from layer tree
+        
+        @param type 'item' / 'layer' / 'nviz'
+        @param multi return first selected layer or all
+        
+        @return layer / map layer properties / nviz properties
+        @return None / [] on failure
+        """
+        ret = []
+        if not self.tree or \
+                not self.tree.GetSelection():
+            if multi:
+                return []
+            else:
+                return None
+        
+        if multi and \
+                type == 'item':
+            return self.tree.GetSelections()
+        
+        for item in self.tree.GetSelections():
+            if not item.IsChecked():
+                if multi:
+                    continue
+                else:
+                    return None
+
+            if type == 'item': # -> multi = False
+                return item
+        
+            try:
+                if type == 'nviz':
+                    layer = self.tree.GetPyData(item)[0]['nviz']
+                else:
+                    layer = self.tree.GetPyData(item)[0]['maplayer']
+            except:
+                layer = None
+
+            if multi:
+                ret.append(layer)
+            else:
+                return layer
+            
+        return ret


Property changes on: grass/trunk/gui/wxpython/gui_core/mapwindow.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/gui_core/menu.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/menu.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/menu.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/menu.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,119 @@
+"""!
+ at package gui_core.menu
+
+ at brief Menu classes for wxGUI
+
+Classes:
+ - Menu
+
+(C) 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 Martin Landa <landa.martin gmail.com>
+ at author Pawel Netzel (menu customization)
+ at author Milena Nowotarska (menu customization)
+ at author Robert Szczepanek (menu customization)
+ at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
+"""
+
+import wx
+
+from core          import globalvar
+from core          import utils
+from core.gcmd     import EncodeString
+from core.settings import UserSettings
+
+class Menu(wx.MenuBar):
+    def __init__(self, parent, data):
+        """!Creates menubar"""
+        wx.MenuBar.__init__(self)
+        self.parent   = parent
+        self.menudata = data
+        self.menucmd  = dict()
+        
+        self.menustyle = UserSettings.Get(group='appearance', key='menustyle', subkey='selection')
+        
+        for eachMenuData in self.menudata.GetMenu():
+            for eachHeading in eachMenuData:
+                menuLabel = eachHeading[0]
+                menuItems = eachHeading[1]
+                self.Append(self._createMenu(menuItems), menuLabel)
+        
+    def _createMenu(self, menuData):
+        """!Creates menu"""
+        menu = wx.Menu()
+        for eachItem in menuData:
+            if len(eachItem) == 2:
+                label = eachItem[0]
+                subMenu = self._createMenu(eachItem[1])
+                menu.AppendMenu(wx.ID_ANY, label, subMenu)
+            else:
+                self._createMenuItem(menu, self.menustyle, *eachItem)
+        
+        self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
+        
+        return menu
+
+    def _createMenuItem(self, menu, menustyle, label, help, handler, gcmd, keywords,
+                        shortcut = '', wxId = wx.ID_ANY, kind = wx.ITEM_NORMAL):
+        """!Creates menu items
+        There are three menu styles (menu item text styles).
+        1 -- label only, 2 -- label and cmd name, 3 -- cmd name only
+        """
+        if not label:
+            menu.AppendSeparator()
+            return
+        
+        if len(gcmd) > 0:
+            helpString = gcmd + ' -- ' + help
+            if menustyle == 1:
+                label += '   [' + gcmd + ']'
+            elif menustyle == 2:
+                label = '      [' + gcmd + ']'
+        else:
+            helpString = help
+        
+        if shortcut:
+            label += '\t' + shortcut
+        
+        menuItem = menu.Append(wxId, label, helpString, kind)
+        
+        self.menucmd[menuItem.GetId()] = gcmd
+        
+        if gcmd: 
+            try: 
+                cmd = utils.split(str(gcmd)) 
+            except UnicodeError: 
+                cmd = utils.split(utils.EncodeString((gcmd))) 
+            if cmd and cmd[0] not in globalvar.grassCmd['all']: 
+                menuItem.Enable(False)
+        
+        rhandler = eval('self.parent.' + handler)
+        
+        self.parent.Bind(wx.EVT_MENU, rhandler, menuItem)
+
+    def GetData(self):
+        """!Get menu data"""
+        return self.menudata
+    
+    def GetCmd(self):
+        """!Get list of commands
+
+        @return list of commands
+        """
+        return self.menucmd
+        
+    def OnMenuHighlight(self, event):
+        """
+        Default menu help handler
+        """
+         # Show how to get menu item info from this event handler
+        id = event.GetMenuId()
+        item = self.FindItemById(id)
+        if item:
+            text = item.GetText()
+            help = item.GetHelp()
+
+        # but in this case just call Skip so the default is done
+        event.Skip()

Copied: grass/trunk/gui/wxpython/gui_core/preferences.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/preferences.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/preferences.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1510 @@
+"""!
+ at package gui_core.preferences
+
+ at brief User preferences dialog
+
+Sets default display font, etc.  If you want to add some value to
+settings you have to add default value to defaultSettings and set
+constraints in internalSettings in Settings class. Everything can be
+used in PreferencesDialog.
+
+Classes:
+ - PreferencesBaseDialog
+ - PreferencesDialog
+ - DefaultFontDialog
+ - MapsetAccess
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
+"""
+
+import os
+import sys
+import copy
+try:
+    import pwd
+    havePwd = True
+except ImportError:
+    havePwd = False
+
+import wx
+import wx.lib.colourselect    as csel
+import wx.lib.mixins.listctrl as listmix
+
+from wx.lib.newevent import NewEvent
+
+from grass.script import core as grass
+
+from core          import globalvar
+from core.gcmd     import RunCommand
+from core.utils    import ListOfMapsets, GetColorTables, ReadEpsgCodes
+from core.settings import UserSettings
+
+wxSettingsChanged, EVT_SETTINGS_CHANGED = NewEvent()
+
+class PreferencesBaseDialog(wx.Dialog):
+    """!Base preferences dialog"""
+    def __init__(self, parent, settings, title = _("User settings"),
+                 size = (500, 375),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        self.parent = parent # ModelerFrame
+        self.title  = title
+        self.size   = size
+        self.settings = settings
+        
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
+                           style = style)
+        
+        # notebook
+        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        
+        # dict for window ids
+        self.winId = {}
+        
+        # create notebook pages
+        
+        # buttons
+        self.btnDefault = wx.Button(self, wx.ID_ANY, _("Set to default"))
+        self.btnSave = wx.Button(self, wx.ID_SAVE)
+        self.btnApply = wx.Button(self, wx.ID_APPLY)
+        self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+        self.btnSave.SetDefault()
+        
+        # bindigs
+        self.btnDefault.Bind(wx.EVT_BUTTON, self.OnDefault)
+        self.btnDefault.SetToolTipString(_("Revert settings to default and apply changes"))
+        self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        self.btnApply.SetToolTipString(_("Apply changes for the current session"))
+        self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        self.btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
+        self.btnSave.SetDefault()
+        self.btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        self.btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        self._layout()
+        
+    def _layout(self):
+        """!Layout window"""
+        # sizers
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = self.btnDefault, proportion = 1,
+                     flag = wx.ALL, border = 5)
+        btnStdSizer = wx.StdDialogButtonSizer()
+        btnStdSizer.AddButton(self.btnCancel)
+        btnStdSizer.AddButton(self.btnSave)
+        btnStdSizer.AddButton(self.btnApply)
+        btnStdSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND, border = 0)
+        mainSizer.Add(item = btnStdSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        
+    def OnDefault(self, event):
+        """!Button 'Set to default' pressed"""
+        self.settings.userSettings = copy.deepcopy(self.settings.defaultSettings)
+        
+        # update widgets
+        for gks in self.winId.keys():
+            try:
+                group, key, subkey = gks.split(':')
+                value = self.settings.Get(group, key, subkey)
+            except ValueError:
+                group, key, subkey, subkey1 = gks.split(':')
+                value = self.settings.Get(group, key, [subkey, subkey1])
+            win = self.FindWindowById(self.winId[gks])
+            if win.GetName() in ('GetValue', 'IsChecked'):
+                value = win.SetValue(value)
+            elif win.GetName() == 'GetSelection':
+                value = win.SetSelection(value)
+            elif win.GetName() == 'GetStringSelection':
+                value = win.SetStringSelection(value)
+            else:
+                value = win.SetValue(value)
+        
+    def OnApply(self, event):
+        """!Button 'Apply' pressed
+        Posts event EVT_SETTINGS_CHANGED.
+        """
+        if self._updateSettings():
+            self.parent.goutput.WriteLog(_('Settings applied to current session but not saved'))
+            event = wxSettingsChanged()
+            wx.PostEvent(self, event)
+            self.Close()
+
+    def OnCloseWindow(self, event):
+        self.Hide()
+        
+    def OnCancel(self, event):
+        """!Button 'Cancel' pressed"""
+        self.Close()
+        
+    def OnSave(self, event):
+        """!Button 'Save' pressed
+        Posts event EVT_SETTINGS_CHANGED.
+        """
+        if self._updateSettings():
+            self.settings.SaveToFile()
+            self.parent.goutput.WriteLog(_('Settings saved to file \'%s\'.') % self.settings.filePath)
+            event = wxSettingsChanged()
+            wx.PostEvent(self, event)
+            self.Close()
+
+    def _updateSettings(self):
+        """!Update user settings"""
+        for item in self.winId.keys():
+            try:
+                group, key, subkey = item.split(':')
+                subkey1 = None
+            except ValueError:
+                group, key, subkey, subkey1 = item.split(':')
+            
+            id = self.winId[item]
+            win = self.FindWindowById(id)
+            if win.GetName() == 'GetValue':
+                value = win.GetValue()
+            elif win.GetName() == 'GetSelection':
+                value = win.GetSelection()
+            elif win.GetName() == 'IsChecked':
+                value = win.IsChecked()
+            elif win.GetName() == 'GetStringSelection':
+                value = win.GetStringSelection()
+            elif win.GetName() == 'GetColour':
+                value = tuple(win.GetValue())
+            else:
+                value = win.GetValue()
+
+            if key == 'keycolumn' and value == '':
+                wx.MessageBox(parent = self,
+                              message = _("Key column cannot be empty string."),
+                              caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
+                win.SetValue(self.settings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
+                return False
+
+            if subkey1:
+                self.settings.Set(group, value, key, [subkey, subkey1])
+            else:
+                self.settings.Set(group, value, key, subkey)
+        
+        if self.parent.GetName() == 'Modeler':
+            return True
+        
+        #
+        # update default window dimension
+        #
+        if self.settings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled') is True:
+            dim = ''
+            # layer manager
+            pos = self.parent.GetPosition()
+            size = self.parent.GetSize()
+            dim = '%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
+            # opened displays
+            for page in range(0, self.parent.gm_cb.GetPageCount()):
+                pos = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetPosition()
+                size = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetSize()
+
+                dim += ',%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
+
+            self.settings.Set(group = 'general', key = 'defWindowPos', subkey = 'dim', value = dim)
+        else:
+            self.settings.Set(group = 'general', key = 'defWindowPos', subkey = 'dim', value = '')
+
+        return True
+
+class PreferencesDialog(PreferencesBaseDialog):
+    """!User preferences dialog"""
+    def __init__(self, parent, title = _("GUI Settings"),
+                 settings = UserSettings):
+        
+        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
+                                       settings = settings)
+        
+        # create notebook pages
+        self._createGeneralPage(self.notebook)
+        self._createAppearancePage(self.notebook)
+        self._createDisplayPage(self.notebook)
+        self._createCmdPage(self.notebook)
+        self._createAttributeManagerPage(self.notebook)
+        self._createProjectionPage(self.notebook)
+        
+        self.SetMinSize(self.GetBestSize())
+        self.SetSize(self.size)
+        
+    def _createGeneralPage(self, notebook):
+        """!Create notebook page for general settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("General"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # Layer Manager settings
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Layer Manager settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        #
+        # ask when removing map layer from layer tree
+        #
+        row = 0
+        askOnRemoveLayer = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                       label = _("Ask when removing map layer from layer tree"),
+                                       name = 'IsChecked')
+        askOnRemoveLayer.SetValue(self.settings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'))
+        self.winId['manager:askOnRemoveLayer:enabled'] = askOnRemoveLayer.GetId()
+        
+        gridSizer.Add(item = askOnRemoveLayer,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1
+        askOnQuit = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                label = _("Ask when quiting wxGUI or closing display"),
+                                name = 'IsChecked')
+        askOnQuit.SetValue(self.settings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'))
+        self.winId['manager:askOnQuit:enabled'] = askOnQuit.GetId()
+        
+        gridSizer.Add(item = askOnQuit,
+                      pos = (row, 0), span = (1, 2))
+
+        row += 1
+        hideSearch = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                 label = _("Hide '%s' tab (requires GUI restart)") % _("Search module"),
+                                 name = 'IsChecked')
+        hideSearch.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'))
+        self.winId['manager:hideTabs:search'] = hideSearch.GetId()
+        
+        gridSizer.Add(item = hideSearch,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1
+        hidePyShell = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                  label = _("Hide '%s' tab (requires GUI restart)") % _("Python shell"),
+                                  name = 'IsChecked')
+        hidePyShell.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'))
+        self.winId['manager:hideTabs:pyshell'] = hidePyShell.GetId()
+        
+        gridSizer.Add(item = hidePyShell,
+                      pos = (row, 0), span = (1, 2))
+        
+        #
+        # Selected text is copied to clipboard
+        #
+        row += 1
+        copySelectedTextToClipboard = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                                  label = _("Automatically copy selected text to clipboard (in Command console)"),
+                                                  name = 'IsChecked')
+        copySelectedTextToClipboard.SetValue(self.settings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled'))
+        self.winId['manager:copySelectedTextToClipboard:enabled'] = copySelectedTextToClipboard.GetId()
+        
+        gridSizer.Add(item = copySelectedTextToClipboard,
+                      pos = (row, 0), span = (1, 2))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        #
+        # workspace
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Workspace settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        row = 0
+        posDisplay = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                 label = _("Suppress positioning Map Display Window(s)"),
+                                 name = 'IsChecked')
+        posDisplay.SetValue(self.settings.Get(group = 'general', key = 'workspace',
+                                              subkey = ['posDisplay', 'enabled']))
+        self.winId['general:workspace:posDisplay:enabled'] = posDisplay.GetId()
+        
+        gridSizer.Add(item = posDisplay,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1 
+        
+        posManager = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                 label = _("Suppress positioning Layer Manager window"),
+                                 name = 'IsChecked')
+        posManager.SetValue(self.settings.Get(group = 'general', key = 'workspace',
+                                              subkey = ['posManager', 'enabled']))
+        self.winId['general:workspace:posManager:enabled'] = posManager.GetId()
+        
+        gridSizer.Add(item = posManager,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1
+        defaultPos = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                 label = _("Save current window layout as default"),
+                                 name = 'IsChecked')
+        defaultPos.SetValue(self.settings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'))
+        defaultPos.SetToolTip(wx.ToolTip (_("Save current position and size of Layer Manager window and opened "
+                                            "Map Display window(s) and use as default for next sessions.")))
+        self.winId['general:defWindowPos:enabled'] = defaultPos.GetId()
+        
+        gridSizer.Add(item = defaultPos,
+                      pos = (row, 0), span = (1, 2))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        panel.SetSizer(border)
+        
+        return panel
+    
+
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createAppearancePage(self, notebook):
+        """!Create notebook page for display settings"""
+   
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Appearance"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+
+        #
+        # font settings
+        #
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Font for command output:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        outfontButton = wx.Button(parent = panel, id = wx.ID_ANY,
+                               label = _("Set font"), size = (100, -1))
+        gridSizer.Add(item = outfontButton,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        #
+        # appearence
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Appearance settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer  =  wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+
+        #
+        # element list
+        #
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Element list:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        elementList = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
+                                choices = self.settings.Get(group = 'appearance', key = 'elementListExpand',
+                                                            subkey = 'choices', internal = True),
+                                name = "GetSelection")
+        elementList.SetSelection(self.settings.Get(group = 'appearance', key = 'elementListExpand',
+                                                   subkey = 'selection'))
+        self.winId['appearance:elementListExpand:selection'] = elementList.GetId()
+
+        gridSizer.Add(item = elementList,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        #
+        # menu style
+        #
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Menu style (requires GUI restart):")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        listOfStyles = self.settings.Get(group = 'appearance', key = 'menustyle',
+                                         subkey = 'choices', internal = True)
+        
+        menuItemText = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
+                                 choices = listOfStyles,
+                                 name = "GetSelection")
+        menuItemText.SetSelection(self.settings.Get(group = 'appearance', key = 'menustyle', subkey = 'selection'))
+        
+        self.winId['appearance:menustyle:selection'] = menuItemText.GetId()
+        
+        gridSizer.Add(item = menuItemText,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+        
+        #
+        # gselect.TreeCtrlComboPopup height
+        #
+        row += 1
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Height of map selection popup window (in pixels):")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        min = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'min', internal = True)
+        max = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'max', internal = True)
+        value = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
+        
+        popupHeightSpin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1))
+        popupHeightSpin.SetRange(min,max)
+        popupHeightSpin.SetValue(value)
+        
+        self.winId['appearance:gSelectPopupHeight:value'] = popupHeightSpin.GetId()
+        
+        gridSizer.Add(item = popupHeightSpin,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+        
+        
+        #
+        # icon theme
+        #
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Icon theme (requires GUI restart):")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        iconTheme = wx.Choice(parent = panel, id = wx.ID_ANY, size = (100, -1),
+                              choices = self.settings.Get(group = 'appearance', key = 'iconTheme',
+                                                        subkey = 'choices', internal = True),
+                              name = "GetStringSelection")
+        iconTheme.SetStringSelection(self.settings.Get(group = 'appearance', key = 'iconTheme', subkey = 'type'))
+        self.winId['appearance:iconTheme:type'] = iconTheme.GetId()
+
+        gridSizer.Add(item = iconTheme,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        panel.SetSizer(border)
+                
+        # bindings
+        outfontButton.Bind(wx.EVT_BUTTON, self.OnSetOutputFont)
+        
+        return panel
+    
+    def _createDisplayPage(self, notebook):
+        """!Create notebook page for display settings"""
+   
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Map Display"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+
+        #
+        # font settings
+        #
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Default font for GRASS displays:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        fontButton = wx.Button(parent = panel, id = wx.ID_ANY,
+                               label = _("Set font"), size = (100, -1))
+        gridSizer.Add(item = fontButton,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 1))
+
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        #
+        # display settings
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Default display settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+
+        
+        #
+        # display driver
+        #
+        row = 0
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Display driver:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        listOfDrivers = self.settings.Get(group = 'display', key = 'driver', subkey = 'choices', internal = True)
+        driver = wx.Choice(parent = panel, id = wx.ID_ANY, size = (150, -1),
+                           choices = listOfDrivers,
+                           name = "GetStringSelection")
+        driver.SetStringSelection(self.settings.Get(group = 'display', key = 'driver', subkey = 'type'))
+        self.winId['display:driver:type'] = driver.GetId()
+        
+        gridSizer.Add(item = driver,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+        
+        #
+        # Statusbar mode
+        #
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Statusbar mode:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        listOfModes = self.settings.Get(group = 'display', key = 'statusbarMode', subkey = 'choices', internal = True)
+        statusbarMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (150, -1),
+                                  choices = listOfModes,
+                                  name = "GetSelection")
+        statusbarMode.SetSelection(self.settings.Get(group = 'display', key = 'statusbarMode', subkey = 'selection'))
+        self.winId['display:statusbarMode:selection'] = statusbarMode.GetId()
+
+        gridSizer.Add(item = statusbarMode,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+
+        #
+        # Background color
+        #
+        row += 1
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Background color:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        bgColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                    colour = self.settings.Get(group = 'display', key = 'bgcolor', subkey = 'color'),
+                                    size = globalvar.DIALOG_COLOR_SIZE)
+        bgColor.SetName('GetColour')
+        self.winId['display:bgcolor:color'] = bgColor.GetId()
+        
+        gridSizer.Add(item = bgColor,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+        
+        #
+        # Align extent to display size
+        #
+        row += 1
+        alignExtent = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                  label = _("Align region extent based on display size"),
+                                  name = "IsChecked")
+        alignExtent.SetValue(self.settings.Get(group = 'display', key = 'alignExtent', subkey = 'enabled'))
+        self.winId['display:alignExtent:enabled'] = alignExtent.GetId()
+
+        gridSizer.Add(item = alignExtent,
+                      pos = (row, 0), span = (1, 2))
+        
+        #
+        # Use computation resolution
+        #
+        row += 1
+        compResolution = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                     label = _("Constrain display resolution to computational settings"),
+                                     name = "IsChecked")
+        compResolution.SetValue(self.settings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
+        self.winId['display:compResolution:enabled'] = compResolution.GetId()
+
+        gridSizer.Add(item = compResolution,
+                      pos = (row, 0), span = (1, 2))
+
+        #
+        # auto-rendering
+        #
+        row += 1
+        autoRendering = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                    label = _("Enable auto-rendering"),
+                                    name = "IsChecked")
+        autoRendering.SetValue(self.settings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled'))
+        self.winId['display:autoRendering:enabled'] = autoRendering.GetId()
+
+        gridSizer.Add(item = autoRendering,
+                      pos = (row, 0), span = (1, 2))
+        
+        #
+        # auto-zoom
+        #
+        row += 1
+        autoZooming = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                  label = _("Enable auto-zooming to selected map layer"),
+                                  name = "IsChecked")
+        autoZooming.SetValue(self.settings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'))
+        self.winId['display:autoZooming:enabled'] = autoZooming.GetId()
+
+        gridSizer.Add(item = autoZooming,
+                      pos = (row, 0), span = (1, 2))
+
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        panel.SetSizer(border)
+                
+        # bindings
+        fontButton.Bind(wx.EVT_BUTTON, self.OnSetFont)
+        
+        return panel
+
+    def _createCmdPage(self, notebook):
+        """!Create notebook page for commad dialog settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Command"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Command dialog settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        #
+        # command dialog settings
+        #
+        row = 0
+        # overwrite
+        overwrite = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                label = _("Allow output files to overwrite existing files"),
+                                name = "IsChecked")
+        overwrite.SetValue(self.settings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
+        self.winId['cmd:overwrite:enabled'] = overwrite.GetId()
+        
+        gridSizer.Add(item = overwrite,
+                      pos = (row, 0), span = (1, 2))
+        row += 1
+        # close
+        close = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                            label = _("Close dialog when command is successfully finished"),
+                            name = "IsChecked")
+        close.SetValue(self.settings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
+        self.winId['cmd:closeDlg:enabled'] = close.GetId()
+        
+        gridSizer.Add(item = close,
+                      pos = (row, 0), span = (1, 2))
+        row += 1
+        # add layer
+        add = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                          label = _("Add created map into layer tree"),
+                          name = "IsChecked")
+        add.SetValue(self.settings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
+        self.winId['cmd:addNewLayer:enabled'] = add.GetId()
+    
+        gridSizer.Add(item = add,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1
+        # interactive input
+        interactive = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                  label = _("Allow interactive input"),
+                                  name = "IsChecked")
+        interactive.SetValue(self.settings.Get(group = 'cmd', key = 'interactiveInput', subkey = 'enabled'))
+        self.winId['cmd:interactiveInput:enabled'] = interactive.GetId()
+        gridSizer.Add(item = interactive,
+                      pos = (row, 0), span = (1, 2))
+        
+        row += 1
+        # verbosity
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Verbosity level:")),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 0))
+        verbosity = wx.Choice(parent = panel, id = wx.ID_ANY, size = (200, -1),
+                              choices = self.settings.Get(group = 'cmd', key = 'verbosity', subkey = 'choices', internal = True),
+                              name = "GetStringSelection")
+        verbosity.SetStringSelection(self.settings.Get(group = 'cmd', key = 'verbosity', subkey = 'selection'))
+        self.winId['cmd:verbosity:selection'] = verbosity.GetId()
+        
+        gridSizer.Add(item = verbosity,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        #
+        # raster settings
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Raster settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        #
+        # raster overlay
+        #
+        row = 0
+        rasterOpaque = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                    label = _("Make null cells opaque"),
+                                    name = 'IsChecked')
+        rasterOpaque.SetValue(self.settings.Get(group = 'cmd', key = 'rasterOpaque', subkey = 'enabled'))
+        self.winId['cmd:rasterOpaque:enabled'] = rasterOpaque.GetId()
+        
+        gridSizer.Add(item = rasterOpaque,
+                      pos = (row, 0), span = (1, 2))
+
+        # default color table
+        row += 1
+        rasterCTCheck = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                    label = _("Default color table"),
+                                    name = 'IsChecked')
+        rasterCTCheck.SetValue(self.settings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'enabled'))
+        self.winId['cmd:rasterColorTable:enabled'] = rasterCTCheck.GetId()
+        rasterCTCheck.Bind(wx.EVT_CHECKBOX, self.OnCheckColorTable)
+        
+        gridSizer.Add(item = rasterCTCheck,
+                      pos = (row, 0))
+        
+        rasterCTName = wx.Choice(parent = panel, id = wx.ID_ANY, size = (200, -1),
+                               choices = GetColorTables(),
+                               name = "GetStringSelection")
+        rasterCTName.SetStringSelection(self.settings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'selection'))
+        self.winId['cmd:rasterColorTable:selection'] = rasterCTName.GetId()
+        if not rasterCTCheck.IsChecked():
+            rasterCTName.Enable(False)
+        
+        gridSizer.Add(item = rasterCTName,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        #
+        # vector settings
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Vector settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.FlexGridSizer (cols = 7, hgap = 3, vgap = 3)
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Display:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        for type in ('point', 'line', 'centroid', 'boundary',
+                     'area', 'face'):
+            chkbox = wx.CheckBox(parent = panel, label = type)
+            checked = self.settings.Get(group = 'cmd', key = 'showType',
+                                        subkey = [type, 'enabled'])
+            chkbox.SetValue(checked)
+            self.winId['cmd:showType:%s:enabled' % type] = chkbox.GetId()
+            gridSizer.Add(item = chkbox)
+
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createAttributeManagerPage(self, notebook):
+        """!Create notebook page for 'Attribute Table Manager' settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Attributes"))
+
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+
+        #
+        # highlighting
+        #
+        highlightBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Highlighting"))
+        highlightSizer = wx.StaticBoxSizer(highlightBox, wx.VERTICAL)
+
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Color:"))
+        hlColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                    colour = self.settings.Get(group = 'atm', key = 'highlight', subkey = 'color'),
+                                    size = globalvar.DIALOG_COLOR_SIZE)
+        hlColor.SetName('GetColour')
+        self.winId['atm:highlight:color'] = hlColor.GetId()
+
+        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(hlColor, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width (in pixels):"))
+        hlWidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (50, -1),
+                              initial = self.settings.Get(group = 'atm', key = 'highlight',subkey = 'width'),
+                              min = 1, max = 1e6)
+        self.winId['atm:highlight:width'] = hlWidth.GetId()
+
+        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(hlWidth, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        highlightSizer.Add(item = flexSizer,
+                           proportion = 0,
+                           flag = wx.ALL | wx.EXPAND,
+                           border = 5)
+
+        pageSizer.Add(item = highlightSizer,
+                      proportion = 0,
+                      flag = wx.ALL | wx.EXPAND,
+                      border = 5)
+
+        #
+        # data browser related settings
+        #
+        dataBrowserBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Data browser"))
+        dataBrowserSizer = wx.StaticBoxSizer(dataBrowserBox, wx.VERTICAL)
+
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Left mouse double click:"))
+        leftDbClick = wx.Choice(parent = panel, id = wx.ID_ANY,
+                                choices = self.settings.Get(group = 'atm', key = 'leftDbClick', subkey = 'choices', internal = True),
+                                name = "GetSelection")
+        leftDbClick.SetSelection(self.settings.Get(group = 'atm', key = 'leftDbClick', subkey = 'selection'))
+        self.winId['atm:leftDbClick:selection'] = leftDbClick.GetId()
+
+        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(leftDbClick, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        # encoding
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("Encoding (e.g. utf-8, ascii, iso8859-1, koi8-r):"))
+        encoding = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+                               value = self.settings.Get(group = 'atm', key = 'encoding', subkey = 'value'),
+                               name = "GetValue", size = (200, -1))
+        self.winId['atm:encoding:value'] = encoding.GetId()
+
+        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(encoding, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        # ask on delete record
+        askOnDeleteRec = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                     label = _("Ask when deleting data record(s) from table"),
+                                     name = 'IsChecked')
+        askOnDeleteRec.SetValue(self.settings.Get(group = 'atm', key = 'askOnDeleteRec', subkey = 'enabled'))
+        self.winId['atm:askOnDeleteRec:enabled'] = askOnDeleteRec.GetId()
+
+        flexSizer.Add(askOnDeleteRec, proportion = 0)
+
+        dataBrowserSizer.Add(item = flexSizer,
+                           proportion = 0,
+                           flag = wx.ALL | wx.EXPAND,
+                           border = 5)
+
+        pageSizer.Add(item = dataBrowserSizer,
+                      proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                      border = 3)
+
+        #
+        # create table
+        #
+        createTableBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                                    label = " %s " % _("Create table"))
+        createTableSizer = wx.StaticBoxSizer(createTableBox, wx.VERTICAL)
+
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("Key column:"))
+        keyColumn = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+                                size = (250, -1))
+        keyColumn.SetValue(self.settings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
+        self.winId['atm:keycolumn:value'] = keyColumn.GetId()
+        
+        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(keyColumn, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        createTableSizer.Add(item = flexSizer,
+                             proportion = 0,
+                             flag = wx.ALL | wx.EXPAND,
+                             border = 5)
+
+        pageSizer.Add(item = createTableSizer,
+                      proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+
+        return panel
+
+    def _createProjectionPage(self, notebook):
+        """!Create notebook page for workspace settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Projection"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #
+        # projections statusbar settings
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Projection statusbar settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(1)
+
+        # epsg
+        row = 0
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("EPSG code:"))
+        epsgCode = wx.ComboBox(parent = panel, id = wx.ID_ANY,
+                               name = "GetValue",
+                               size = (150, -1))
+        self.epsgCodeDict = dict()
+        epsgCode.SetValue(str(self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')))
+        self.winId['projection:statusbar:epsg'] = epsgCode.GetId()
+        
+        gridSizer.Add(item = label,
+                      pos = (row, 0),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = epsgCode,
+                      pos = (row, 1), span = (1, 2))
+        
+        # proj
+        row += 1
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("Proj.4 string (required):"))
+        projString = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+                                 value = self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'),
+                                 name = "GetValue", size = (400, -1))
+        self.winId['projection:statusbar:proj4'] = projString.GetId()
+
+        gridSizer.Add(item = label,
+                      pos = (row, 0),
+                      flag  =  wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = projString,
+                      pos = (row, 1), span = (1, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        # epsg file
+        row += 1
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("EPSG file:"))
+        projFile = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+                               value  =  self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'projFile'),
+                               name = "GetValue", size = (400, -1))
+        self.winId['projection:statusbar:projFile'] = projFile.GetId()
+        gridSizer.Add(item = label,
+                      pos = (row, 0),
+                      flag  =  wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = projFile,
+                      pos = (row, 1),
+                      flag  =  wx.ALIGN_CENTER_VERTICAL)
+        
+        # note + button
+        row += 1
+        note = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                             label = _("Load EPSG codes (be patient), enter EPSG code or "
+                                       "insert Proj.4 string directly."))
+        gridSizer.Add(item = note,
+                      span = (1, 2),
+                      pos = (row, 0))
+
+        row += 1
+        epsgLoad = wx.Button(parent = panel, id = wx.ID_ANY,
+                             label = _("&Load EPSG codes"))
+        gridSizer.Add(item = epsgLoad,
+                      flag = wx.ALIGN_RIGHT,
+                      pos = (row, 1))
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        #
+        # format
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Coordinates format"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(2)
+
+        row = 0
+        # ll format
+        ll = wx.RadioBox(parent = panel, id = wx.ID_ANY,
+                         label = " %s " % _("LL projections"),
+                         choices = ["DMS", "DEG"],
+                         name = "GetStringSelection")
+        self.winId['projection:format:ll'] = ll.GetId()
+        if self.settings.Get(group = 'projection', key = 'format', subkey = 'll') == 'DMS':
+            ll.SetSelection(0)
+        else:
+            ll.SetSelection(1)
+        
+        # precision
+        precision =  wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                                 min = 0, max = 12,
+                                 name = "GetValue")
+        precision.SetValue(int(self.settings.Get(group = 'projection', key = 'format', subkey = 'precision')))
+        self.winId['projection:format:precision'] = precision.GetId()
+                
+        gridSizer.Add(item = ll,
+                      pos = (row, 0))
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Precision:")),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
+                      border = 20,
+                      pos = (row, 1))
+        gridSizer.Add(item = precision,
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 2))
+        
+        
+        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+        
+        panel.SetSizer(border)
+
+        # bindings
+        epsgLoad.Bind(wx.EVT_BUTTON, self.OnLoadEpsgCodes)
+        epsgCode.Bind(wx.EVT_COMBOBOX, self.OnSetEpsgCode)
+        epsgCode.Bind(wx.EVT_TEXT_ENTER, self.OnSetEpsgCode)
+        
+        return panel
+
+    def OnCheckColorTable(self, event):
+        """!Set/unset default color table"""
+        win = self.FindWindowById(self.winId['cmd:rasterColorTable:selection'])
+        if event.IsChecked():
+            win.Enable()
+        else:
+            win.Enable(False)
+        
+    def OnLoadEpsgCodes(self, event):
+        """!Load EPSG codes from the file"""
+        win = self.FindWindowById(self.winId['projection:statusbar:projFile'])
+        path = win.GetValue()
+
+        self.epsgCodeDict = ReadEpsgCodes(path)
+        list = self.FindWindowById(self.winId['projection:statusbar:epsg'])
+        if type(self.epsgCodeDict) == type(''):
+            wx.MessageBox(parent = self,
+                          message = _("Unable to read EPSG codes: %s") % self.epsgCodeDict,
+                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            self.epsgCodeDict = dict()
+            list.SetItems([])
+            list.SetValue('')
+            self.FindWindowById(self.winId['projection:statusbar:proj4']).SetValue('')
+            return
+        
+        choices = map(str, self.epsgCodeDict.keys())
+
+        list.SetItems(choices)
+        try:
+            code = int(list.GetValue())
+        except ValueError:
+            code = -1
+        win = self.FindWindowById(self.winId['projection:statusbar:proj4'])
+        if code in self.epsgCodeDict:
+            win.SetValue(self.epsgCodeDict[code][1])
+        else:
+            list.SetSelection(0)
+            code = int(list.GetStringSelection())
+            win.SetValue(self.epsgCodeDict[code][1])
+    
+    def OnSetEpsgCode(self, event):
+        """!EPSG code selected"""
+        winCode = self.FindWindowById(event.GetId())
+        win = self.FindWindowById(self.winId['projection:statusbar:proj4'])
+        if not self.epsgCodeDict:
+            wx.MessageBox(parent = self,
+                          message = _("EPSG code %s not found") % event.GetString(),
+                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            winCode.SetValue('')
+            win.SetValue('')
+        
+        try:
+            code = int(event.GetString())
+        except ValueError:
+            wx.MessageBox(parent = self,
+                          message = _("EPSG code %s not found") % str(code),
+                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            winCode.SetValue('')
+            win.SetValue('')
+        
+        
+        try:
+            win.SetValue(self.epsgCodeDict[code][1].replace('<>', '').strip())
+        except KeyError:
+            wx.MessageBox(parent = self,
+                          message = _("EPSG code %s not found") % str(code),
+                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            winCode.SetValue('')
+            win.SetValue('')
+        
+    def OnSetFont(self, event):
+        """'Set font' button pressed"""
+        dlg = DefaultFontDialog(parent = self,
+                                title = _('Select default display font'),
+                                style = wx.DEFAULT_DIALOG_STYLE,
+                                type = 'font')
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            # set default font and encoding environmental variables
+            if dlg.font:
+                os.environ["GRASS_FONT"] = dlg.font
+                self.settings.Set(group = 'display', value = dlg.font,
+                                  key = 'font', subkey = 'type')
+
+            if dlg.encoding and \
+                    dlg.encoding != "ISO-8859-1":
+                os.environ["GRASS_ENCODING"] = dlg.encoding
+                self.settings.Set(group = 'display', value = dlg.encoding,
+                                  key = 'font', subkey = 'encoding')
+                
+        dlg.Destroy()
+        
+        event.Skip()
+
+    def OnSetOutputFont(self, event):
+        """'Set output font' button pressed
+        """
+
+        type = self.settings.Get(group = 'appearance', key = 'outputfont', subkey = 'type')   
+                           
+        size = self.settings.Get(group = 'appearance', key = 'outputfont', subkey = 'size')
+        if size == None or size == 0: size = 11
+        size = float(size)
+        if type == None or type == '': type = 'Courier'
+        
+        outfont = wx.Font(size, wx.FONTFAMILY_MODERN, wx.NORMAL, 0, faceName = type)
+        
+        fontdata = wx.FontData()
+        fontdata.EnableEffects(True)
+        fontdata.SetColour('black')
+        fontdata.SetInitialFont(outfont)
+        
+        dlg = wx.FontDialog(self, fontdata)
+        
+        'FIXME: native font dialog does not initialize with current font'
+
+        if dlg.ShowModal() == wx.ID_OK:
+            outdata = dlg.GetFontData()
+            font = outdata.GetChosenFont()
+
+            self.settings.Set(group = 'appearance', value = font.GetFaceName(),
+                                  key = 'outputfont', subkey = 'type')
+            self.settings.Set(group = 'appearance', value = font.GetPointSize(),
+                                  key = 'outputfont', subkey = 'size')
+        dlg.Destroy()
+
+        event.Skip()
+
+class DefaultFontDialog(wx.Dialog):
+    """
+    Opens a file selection dialog to select default font
+    to use in all GRASS displays
+    """
+    def __init__(self, parent, title, id = wx.ID_ANY,
+                 style = wx.DEFAULT_DIALOG_STYLE |
+                 wx.RESIZE_BORDER,
+                 settings = UserSettings,
+                 type = 'font'):
+        
+        self.settings = settings
+        self.type = type
+        
+        wx.Dialog.__init__(self, parent, id, title, style = style)
+
+        panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.fontlist = self.GetFonts()
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridSizer.AddGrowableCol(0)
+
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("Select font:"))
+        gridSizer.Add(item = label,
+                      flag = wx.ALIGN_TOP,
+                      pos = (0,0))
+        
+        self.fontlb = wx.ListBox(parent = panel, id = wx.ID_ANY, pos = wx.DefaultPosition,
+                                 choices = self.fontlist,
+                                 style = wx.LB_SINGLE|wx.LB_SORT)
+        self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.fontlb)
+        self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.fontlb)
+
+        gridSizer.Add(item = self.fontlb,
+                flag = wx.EXPAND, pos = (1, 0))
+
+        if self.type == 'font':
+            if "GRASS_FONT" in os.environ:
+                self.font = os.environ["GRASS_FONT"]
+            else:
+                self.font = self.settings.Get(group = 'display',
+                                              key = 'font', subkey = 'type')
+            self.encoding = self.settings.Get(group = 'display',
+                                          key = 'font', subkey = 'encoding')
+
+            label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                  label = _("Character encoding:"))
+            gridSizer.Add(item = label,
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (2, 0))
+
+            self.textentry = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+                                         value = self.encoding)
+            gridSizer.Add(item = self.textentry,
+                    flag = wx.EXPAND, pos = (3, 0))
+
+            self.textentry.Bind(wx.EVT_TEXT, self.OnEncoding)
+
+        elif self.type == 'outputfont':
+            self.font = self.settings.Get(group = 'appearance',
+                                              key = 'outputfont', subkey = 'type')
+            self.fontsize = self.settings.Get(group = 'appearance',
+                                          key = 'outputfont', subkey = 'size')
+            label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                              label = _("Font size:"))
+            gridSizer.Add(item = label,
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 0))
+                      
+            self.spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY)
+            if self.fontsize:
+                self.spin.SetValue(self.fontsize)
+            self.spin.Bind(wx.EVT_SPINCTRL, self.OnSizeSpin)
+            self.spin.Bind(wx.EVT_TEXT, self.OnSizeSpin)
+            gridSizer.Add(item = self.spin,
+                      flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (3, 0))
+
+        else: 
+            return
+
+        if self.font:
+            self.fontlb.SetStringSelection(self.font, True)
+
+        sizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.ALL,
+                  border = 5)
+
+        border.Add(item = sizer, proportion = 1,
+                   flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(parent = panel, id = wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(parent = panel, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        border.Add(item = btnsizer, proportion = 0,
+                   flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        
+        panel.SetAutoLayout(True)
+        panel.SetSizer(border)
+        border.Fit(self)
+        
+        self.Layout()
+        
+    def EvtRadioBox(self, event):
+        if event.GetInt() == 0:
+            self.fonttype = 'grassfont'
+        elif event.GetInt() == 1:
+            self.fonttype = 'truetype'
+
+        self.fontlist = self.GetFonts(self.fonttype)
+        self.fontlb.SetItems(self.fontlist)
+
+    def OnEncoding(self, event):
+        self.encoding = event.GetString()
+
+    def EvtListBox(self, event):
+        self.font = event.GetString()
+        event.Skip()
+
+    def EvtListBoxDClick(self, event):
+        self.font = event.GetString()
+        event.Skip()
+        
+    def OnSizeSpin(self, event):
+        self.fontsize = self.spin.GetValue()
+        event.Skip()
+    
+    def GetFonts(self):
+        """
+        parses fonts directory or fretypecap file to get a list of fonts for the listbox
+        """
+        fontlist = []
+
+        cmd = ["d.font", "-l"]
+
+        ret = RunCommand('d.font',
+                         read = True,
+                         flags = 'l')
+
+        if not ret:
+            return fontlist
+
+        dfonts = ret.splitlines()
+        dfonts.sort(lambda x,y: cmp(x.lower(), y.lower()))
+        for item in range(len(dfonts)):
+           # ignore duplicate fonts and those starting with #
+           if not dfonts[item].startswith('#') and \
+                  dfonts[item] != dfonts[item-1]:
+              fontlist.append(dfonts[item])
+
+        return fontlist
+
+class MapsetAccess(wx.Dialog):
+    """!Controls setting options and displaying/hiding map overlay
+    decorations
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _('Manage access to mapsets'),
+                 size  =  (350, 400),
+                 style  =  wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        wx.Dialog.__init__(self, parent, id, title, size = size, style = style)
+
+        self.all_mapsets_ordered = ListOfMapsets(get = 'ordered')
+        self.accessible_mapsets  = ListOfMapsets(get = 'accessible')
+        self.curr_mapset = grass.gisenv()['MAPSET']
+
+        # make a checklistbox from available mapsets and check those that are active
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        label = wx.StaticText(parent = self, id = wx.ID_ANY,
+                              label = _("Check a mapset to make it accessible, uncheck it to hide it.\n"
+                                        "  Notes:\n"
+                                        "    - The current mapset is always accessible.\n"
+                                        "    - You may only write to the current mapset.\n"
+                                        "    - You may only write to mapsets which you own."))
+        
+        sizer.Add(item = label, proportion = 0,
+                  flag = wx.ALL, border = 5)
+
+        self.mapsetlb = CheckListMapset(parent = self)
+        self.mapsetlb.LoadData()
+        
+        sizer.Add(item = self.mapsetlb, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+
+        # check all accessible mapsets
+        for mset in self.accessible_mapsets:
+            self.mapsetlb.CheckItem(self.all_mapsets_ordered.index(mset), True)
+
+        # FIXME (howto?): grey-out current mapset
+        #self.mapsetlb.Enable(0, False)
+
+        # dialog buttons
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY,
+                             style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+        okbtn = wx.Button(self, wx.ID_OK)
+        okbtn.SetDefault()
+        btnsizer.AddButton(okbtn)
+
+        cancelbtn = wx.Button(self, wx.ID_CANCEL)
+        btnsizer.AddButton(cancelbtn)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        # do layout
+        self.Layout()
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+        self.SetMinSize(size)
+        
+    def GetMapsets(self):
+        """!Get list of checked mapsets"""
+        ms = []
+        i = 0
+        for mset in self.all_mapsets_ordered:
+            if self.mapsetlb.IsChecked(i):
+                ms.append(mset)
+            i += 1
+
+        return ms
+
+class CheckListMapset(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
+    """!List of mapset/owner/group"""
+    def __init__(self, parent, pos = wx.DefaultPosition,
+                 log = None):
+        self.parent = parent
+        
+        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
+                             style = wx.LC_REPORT)
+        listmix.CheckListCtrlMixin.__init__(self)
+        self.log = log
+
+        # setup mixins
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+    def LoadData(self):
+        """!Load data into list"""
+        self.InsertColumn(0, _('Mapset'))
+        self.InsertColumn(1, _('Owner'))
+        ### self.InsertColumn(2, _('Group'))
+        gisenv = grass.gisenv()
+        locationPath = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'])
+
+        for mapset in self.parent.all_mapsets_ordered:
+            index = self.InsertStringItem(sys.maxint, mapset)
+            mapsetPath = os.path.join(locationPath,
+                                      mapset)
+            stat_info = os.stat(mapsetPath)
+            if havePwd:
+                self.SetStringItem(index, 1, "%s" % pwd.getpwuid(stat_info.st_uid)[0])
+                # FIXME: get group name
+                ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) 
+            else:
+                # FIXME: no pwd under MS Windows (owner: 0, group: 0)
+                self.SetStringItem(index, 1, "%-8s" % stat_info.st_uid)
+                ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid)
+                
+        self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE)
+        ### self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE)
+        
+    def OnCheckItem(self, index, flag):
+        """!Mapset checked/unchecked"""
+        mapset = self.parent.all_mapsets_ordered[index]
+        if mapset == self.parent.curr_mapset:
+            self.CheckItem(index, True)

Copied: grass/trunk/gui/wxpython/gui_core/prompt.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/prompt.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/prompt.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/prompt.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1154 @@
+"""!
+ at package gui_core.prompt
+
+ at brief wxGUI command prompt
+
+Classes:
+ - PromptListCtrl
+ - TextCtrlAutoComplete
+ - GPrompt
+ - GPromptPopUp
+ - GPromptSTC
+
+(C) 2009-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton <michael.barton at asu.edu>
+ at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
+"""
+
+import os
+import sys
+import difflib
+import codecs
+
+import wx
+import wx.stc
+import wx.lib.mixins.listctrl as listmix
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+from core          import globalvar
+from core          import utils
+from lmgr.menudata import ManagerData
+from core.gcmd     import EncodeString, DecodeString
+
+class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
+    """!PopUp window used by GPromptPopUp"""
+    def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition,
+                 size = wx.DefaultSize, style = 0):
+        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        
+class TextCtrlAutoComplete(wx.ComboBox, listmix.ColumnSorterMixin):
+    """!Auto complete text area used by GPromptPopUp"""
+    def __init__ (self, parent, statusbar,
+                  id = wx.ID_ANY, choices = [], **kwargs):
+        """!Constructor works just like wx.TextCtrl except you can pass in a
+        list of choices.  You can also change the choice list at any time
+        by calling setChoices.
+        
+        Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete
+        """
+        self.statusbar = statusbar
+        
+        if 'style' in kwargs:
+            kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']
+        else:
+            kwargs['style'] = wx.TE_PROCESS_ENTER
+        
+        wx.ComboBox.__init__(self, parent, id, **kwargs)
+        
+        # some variables
+        self._choices = choices
+        self._hideOnNoMatch = True
+        self._module = None      # currently selected module
+        self._choiceType = None  # type of choice (module, params, flags, raster, vector ...)
+        self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
+        self._historyItem = 0   # last item
+        
+        # sort variable needed by listmix
+        self.itemDataMap = dict()
+        
+        # widgets
+        try:
+            self.dropdown = wx.PopupWindow(self)
+        except NotImplementedError:
+            self.Destroy()
+            raise NotImplementedError
+        
+        # create the list and bind the events
+        self.dropdownlistbox = PromptListCtrl(parent = self.dropdown,
+                                              style = wx.LC_REPORT | wx.LC_SINGLE_SEL | \
+                                                  wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER,
+                                              pos = wx.Point(0, 0))
+        
+        listmix.ColumnSorterMixin.__init__(self, 1)
+        
+        # set choices (list of GRASS modules)
+        self._choicesCmd = globalvar.grassCmd['all']
+        self._choicesMap = dict()
+        for type in ('raster', 'vector'):
+            self._choicesMap[type] = grass.list_strings(type = type[:4])
+        # first search for GRASS module
+        self.SetChoices(self._choicesCmd)
+        
+        self.SetMinSize(self.GetSize())
+        
+        # bindings...
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
+        self.Bind(wx.EVT_TEXT, self.OnEnteredText)
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
+        self.Bind(wx.EVT_KEY_DOWN , self.OnKeyDown)
+        ### self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
+
+        # if need drop down on left click
+        self.dropdown.Bind(wx.EVT_LISTBOX , self.OnListItemSelected, self.dropdownlistbox)
+        self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.OnListClick)
+        self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.OnListDClick)
+        self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.OnListColClick)
+
+        self.Bind(wx.EVT_COMBOBOX, self.OnCommandSelect)
+        
+    def _updateDataList(self, choices):
+        """!Update data list"""
+        # delete, if need, all the previous data
+        if self.dropdownlistbox.GetColumnCount() != 0:
+            self.dropdownlistbox.DeleteAllColumns()
+            self.dropdownlistbox.DeleteAllItems()
+        # and update the dict
+        if choices:
+            for numVal, data in enumerate(choices):
+                self.itemDataMap[numVal] = data
+        else:
+            numVal = 0
+        self.SetColumnCount(numVal)
+    
+    def _setListSize(self):
+        """!Set list size"""
+        choices = self._choices
+        longest = 0
+        for choice in choices:
+            longest = max(len(choice), longest)
+        longest += 3
+        itemcount = min(len( choices ), 7) + 2
+        charheight = self.dropdownlistbox.GetCharHeight()
+        charwidth = self.dropdownlistbox.GetCharWidth()
+        self.popupsize = wx.Size(charwidth*longest, charheight*itemcount)
+        self.dropdownlistbox.SetSize(self.popupsize)
+        self.dropdown.SetClientSize(self.popupsize)
+        
+    def _showDropDown(self, show = True):
+        """!Either display the drop down list (show = True) or hide it
+        (show = False).
+        """
+        if show:
+            size = self.dropdown.GetSize()
+            width, height = self.GetSizeTuple()
+            x, y = self.ClientToScreenXY(0, height)
+            if size.GetWidth() != width:
+                size.SetWidth(width)
+                self.dropdown.SetSize(size)
+                self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
+            if (y + size.GetHeight()) < self._screenheight:
+                self.dropdown.SetPosition(wx.Point(x, y))
+            else:
+                self.dropdown.SetPosition(wx.Point(x, y - height - size.GetHeight()))
+        
+        self.dropdown.Show(show)
+    
+    def _listItemVisible(self):
+        """!Moves the selected item to the top of the list ensuring it is
+        always visible.
+        """
+        toSel = self.dropdownlistbox.GetFirstSelected()
+        if toSel == -1:
+            return
+        self.dropdownlistbox.EnsureVisible(toSel)
+
+    def _setModule(self, name):
+        """!Set module's choices (flags, parameters)""" 
+        # get module's description
+        if name in self._choicesCmd and not self._module:
+            try:
+                self._module = gtask.parse_interface(name)
+            except IOError:
+                self._module = None
+             
+        # set choices (flags)
+        self._choicesMap['flag'] = self._module.get_list_flags()
+        for idx in range(len(self._choicesMap['flag'])):
+            item = self._choicesMap['flag'][idx]
+            desc = self._module.get_flag(item)['label']
+            if not desc:
+                desc = self._module.get_flag(item)['description']
+            
+            self._choicesMap['flag'][idx] = '%s (%s)' % (item, desc)
+        
+        # set choices (parameters)
+        self._choicesMap['param'] = self._module.get_list_params()
+        for idx in range(len(self._choicesMap['param'])):
+            item = self._choicesMap['param'][idx]
+            desc = self._module.get_param(item)['label']
+            if not desc:
+                desc = self._module.get_param(item)['description']
+            
+            self._choicesMap['param'][idx] = '%s (%s)' % (item, desc)
+    
+    def _setValueFromSelected(self):
+         """!Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
+         Will do nothing if no item is selected in the wx.ListCtrl.
+         """
+         sel = self.dropdownlistbox.GetFirstSelected()
+         if sel < 0:
+             return
+         
+         if self._colFetch != -1:
+             col = self._colFetch
+         else:
+             col = self._colSearch
+         itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
+         
+         cmd = utils.split(str(self.GetValue()))
+         if len(cmd) > 0 and cmd[0] in self._choicesCmd:
+             # -> append text (skip last item)
+             if self._choiceType == 'param':
+                 itemtext = itemtext.split(' ')[0]
+                 self.SetValue(' '.join(cmd) + ' ' + itemtext + '=')
+                 optType = self._module.get_param(itemtext)['prompt']
+                 if optType in ('raster', 'vector'):
+                     # -> raster/vector map
+                     self.SetChoices(self._choicesMap[optType], optType)
+             elif self._choiceType == 'flag':
+                 itemtext = itemtext.split(' ')[0]
+                 if len(itemtext) > 1:
+                     prefix = '--'
+                 else:
+                     prefix = '-'
+                 self.SetValue(' '.join(cmd[:-1]) + ' ' + prefix + itemtext)
+             elif self._choiceType in ('raster', 'vector'):
+                 self.SetValue(' '.join(cmd[:-1]) + ' ' + cmd[-1].split('=', 1)[0] + '=' + itemtext)
+         else:
+             # -> reset text
+             self.SetValue(itemtext + ' ')
+             
+             # define module
+             self._setModule(itemtext)
+             
+             # use parameters as default choices
+             self._choiceType = 'param'
+             self.SetChoices(self._choicesMap['param'], type = 'param')
+         
+         self.SetInsertionPointEnd()
+         
+         self._showDropDown(False)
+         
+    def GetListCtrl(self):
+        """!Method required by listmix.ColumnSorterMixin"""
+        return self.dropdownlistbox
+    
+    def SetChoices(self, choices, type = 'module'):
+        """!Sets the choices available in the popup wx.ListBox.
+        The items will be sorted case insensitively.
+
+        @param choices list of choices
+        @param type type of choices (module, param, flag, raster, vector)
+        """
+        self._choices = choices
+        self._choiceType = type
+        
+        self.dropdownlistbox.SetWindowStyleFlag(wx.LC_REPORT | wx.LC_SINGLE_SEL |
+                                                wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER)
+        if not isinstance(choices, list):
+            self._choices = [ x for x in choices ]
+        if self._choiceType not in ('raster', 'vector'):
+            # do not sort raster/vector maps
+            utils.ListSortLower(self._choices)
+        
+        self._updateDataList(self._choices)
+        
+        self.dropdownlistbox.InsertColumn(0, "")
+        for num, colVal in enumerate(self._choices):
+            index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
+            self.dropdownlistbox.SetStringItem(index, 0, colVal)
+            self.dropdownlistbox.SetItemData(index, num)
+        self._setListSize()
+        
+        # there is only one choice for both search and fetch if setting a single column:
+        self._colSearch = 0
+        self._colFetch = -1
+
+    def OnClick(self, event):
+        """Left mouse button pressed"""
+        sel = self.dropdownlistbox.GetFirstSelected()
+        if not self.dropdown.IsShown():
+            if sel > -1:
+                self.dropdownlistbox.Select(sel)
+            else:
+                self.dropdownlistbox.Select(0)
+            self._listItemVisible()
+            self._showDropDown()
+        else:
+            self.dropdown.Hide()
+        
+    def OnCommandSelect(self, event):
+        """!Command selected from history"""
+        self._historyItem = event.GetSelection() - len(self.GetItems())
+        self.SetFocus()
+        
+    def OnListClick(self, evt):
+        """!Left mouse button pressed"""
+        toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
+        #no values on poition, return
+        if toSel == -1: return
+        self.dropdownlistbox.Select(toSel)
+
+    def OnListDClick(self, evt):
+        """!Mouse button double click"""
+        self._setValueFromSelected()
+
+    def OnListColClick(self, evt):
+        """!Left mouse button pressed on column"""
+        col = evt.GetColumn()
+        # reverse the sort
+        if col == self._colSearch:
+            self._ascending = not self._ascending
+        self.SortListItems( evt.GetColumn(), ascending=self._ascending )
+        self._colSearch = evt.GetColumn()
+        evt.Skip()
+
+    def OnListItemSelected(self, event):
+        """!Item selected"""
+        self._setValueFromSelected()
+        event.Skip()
+
+    def OnEnteredText(self, event):
+        """!Text entered"""
+        text = event.GetString()
+        
+        if not text:
+            # control is empty; hide dropdown if shown:
+            if self.dropdown.IsShown():
+                self._showDropDown(False)
+            event.Skip()
+            return
+        
+        try:
+            cmd = utils.split(str(text))
+        except ValueError, e:
+            self.statusbar.SetStatusText(str(e))
+            cmd = text.split(' ')
+        pattern = str(text)
+        
+        if len(cmd) > 0 and cmd[0] in self._choicesCmd and not self._module:
+            self._setModule(cmd[0])
+        elif len(cmd) > 1 and cmd[0] in self._choicesCmd:
+            if self._module:
+                if len(cmd[-1].split('=', 1)) == 1:
+                    # new option
+                    if cmd[-1][0] == '-':
+                        # -> flags
+                        self.SetChoices(self._choicesMap['flag'], type = 'flag')
+                        pattern = cmd[-1].lstrip('-')
+                    else:
+                        # -> options
+                        self.SetChoices(self._choicesMap['param'], type = 'param')
+                        pattern = cmd[-1]
+                else:
+                    # value
+                    pattern = cmd[-1].split('=', 1)[1]
+        else:
+            # search for GRASS modules
+            if self._module:
+                # -> switch back to GRASS modules list
+                self.SetChoices(self._choicesCmd)
+                self._module = None
+                self._choiceType = None
+        
+        self._choiceType
+        self._choicesMap
+        found = False
+        choices = self._choices
+        for numCh, choice in enumerate(choices):
+            if choice.lower().startswith(pattern):
+                found = True
+            if found:
+                self._showDropDown(True)
+                item = self.dropdownlistbox.GetItem(numCh)
+                toSel = item.GetId()
+                self.dropdownlistbox.Select(toSel)
+                break
+        
+        if not found:
+            self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
+            if self._hideOnNoMatch:
+                self._showDropDown(False)
+                if self._module and '=' not in cmd[-1]:
+                    message = ''
+                    if cmd[-1][0] == '-': # flag
+                        message = _("Warning: flag <%(flag)s> not found in '%(module)s'") % \
+                            { 'flag' : cmd[-1][1:], 'module' : self._module.name }
+                    else: # option
+                        message = _("Warning: option <%(param)s> not found in '%(module)s'") % \
+                            { 'param' : cmd[-1], 'module' : self._module.name }
+                    self.statusbar.SetStatusText(message)
+        
+        if self._module and len(cmd[-1]) == 2 and cmd[-1][-2] == '=':
+            optType = self._module.get_param(cmd[-1][:-2])['prompt']
+            if optType in ('raster', 'vector'):
+                # -> raster/vector map
+                self.SetChoices(self._choicesMap[optType], optType)
+        
+        self._listItemVisible()
+        
+        event.Skip()
+        
+    def OnKeyDown (self, event):
+        """!Do some work when the user press on the keys: up and down:
+        move the cursor left and right: move the search
+        """
+        skip = True
+        sel = self.dropdownlistbox.GetFirstSelected()
+        visible = self.dropdown.IsShown()
+        KC = event.GetKeyCode()
+        
+        if KC == wx.WXK_RIGHT:
+            # right -> show choices
+            if sel < (self.dropdownlistbox.GetItemCount() - 1):
+                self.dropdownlistbox.Select(sel + 1)
+                self._listItemVisible()
+            self._showDropDown()
+            skip = False
+        elif KC == wx.WXK_UP:
+            if visible:
+                if sel > 0:
+                    self.dropdownlistbox.Select(sel - 1)
+                    self._listItemVisible()
+                self._showDropDown()
+                skip = False
+            else:
+                self._historyItem -= 1
+                try:
+                    self.SetValue(self.GetItems()[self._historyItem])
+                except IndexError:
+                    self._historyItem += 1
+        elif KC == wx.WXK_DOWN:
+            if visible:
+                if sel < (self.dropdownlistbox.GetItemCount() - 1):
+                    self.dropdownlistbox.Select(sel + 1)
+                    self._listItemVisible()
+                self._showDropDown()
+                skip = False
+            else:
+                if self._historyItem < -1:
+                    self._historyItem += 1
+                    self.SetValue(self.GetItems()[self._historyItem])
+        
+        if visible:
+            if event.GetKeyCode() == wx.WXK_RETURN:
+                self._setValueFromSelected()
+                skip = False
+            if event.GetKeyCode() == wx.WXK_ESCAPE:
+                self._showDropDown(False)
+                skip = False
+        if skip:
+            event.Skip()
+        
+    def OnControlChanged(self, event):
+        """!Control changed"""
+        if self.IsShown():
+            self._showDropDown(False)
+        
+        event.Skip()
+
+class GPrompt(object):
+    """!Abstract class for interactive wxGUI prompt
+
+    See subclass GPromptPopUp and GPromptSTC.
+    """
+    def __init__(self, parent):
+        self.parent = parent                 # GMConsole
+        self.panel  = self.parent.GetPanel()
+        
+        if self.parent.parent.GetName() not in ("LayerManager", "Modeler"):
+            self.standAlone = True
+        else:
+            self.standAlone = False
+        
+        # dictionary of modules (description, keywords, ...)
+        if not self.standAlone:
+            if self.parent.parent.GetName() == 'Modeler':
+                self.moduleDesc = ManagerData().GetModules()
+            else:
+                self.moduleDesc = parent.parent.menubar.GetData().GetModules()
+            self.moduleList = self._getListOfModules()
+            self.mapList = self._getListOfMaps()
+            self.mapsetList = utils.ListOfMapsets()
+        else:
+            self.moduleDesc = self.moduleList = self.mapList = None
+        
+        # auto complete items
+        self.autoCompList   = list()
+        self.autoCompFilter = None
+        
+        # command description (gtask.grassTask)
+        self.cmdDesc = None
+        self.cmdbuffer = self._readHistory()
+        self.cmdindex = len(self.cmdbuffer)
+        
+    def _readHistory(self):
+        """!Get list of commands from history file"""
+        hist = list()
+        env = grass.gisenv()
+        try:
+            fileHistory = codecs.open(os.path.join(env['GISDBASE'],
+                                                   env['LOCATION_NAME'],
+                                                   env['MAPSET'],
+                                                   '.bash_history'),
+                                      encoding = 'utf-8', mode = 'r', errors='replace')
+        except IOError:
+            return hist
+        
+        try:
+            for line in fileHistory.readlines():
+                hist.append(line.replace('\n', ''))
+        finally:
+            fileHistory.close()
+        
+        return hist
+
+    def GetCommandDesc(self, cmd):
+        """!Get description for given command"""
+        if cmd in self.moduleDesc:
+            return self.moduleDesc[cmd]['desc']
+        
+        return ''
+    
+    def GetCommandItems(self):
+        """!Get list of available commands"""
+        items = list()
+        
+        if self.autoCompFilter is not None:
+            mList = self.autoCompFilter
+        else:
+            mList = self.moduleList
+            
+        if not mList:
+            return items
+        
+        prefixes = mList.keys()
+        prefixes.sort()
+        
+        for prefix in prefixes:
+            for command in mList[prefix]:
+                name = prefix + '.' + command
+                if name not in items:
+                    items.append(name)
+                
+        items.sort()
+        
+        return items
+    
+    def _getListOfModules(self):
+        """!Get list of modules"""
+        result = dict()
+        for module in globalvar.grassCmd['all']:
+            try:
+                group, name = module.split('.',1)
+            except ValueError:
+                continue # TODO
+            
+            if group not in result:
+                result[group] = list()
+            result[group].append(name)
+            
+            # for better auto-completion: 
+            # not only result['r']={...,'colors.out',...}, but also result['r.colors']={'out',...}
+            for i in range(len(name.split('.'))-1):
+                group = '.'.join([group,name.split('.',1)[0]])
+                name = name.split('.',1)[1]
+                if group not in result:
+                    result[group] = list()
+                result[group].append(name)
+      
+        # sort list of names
+        for group in result.keys():
+            result[group].sort()
+        
+        return result
+    
+    def _getListOfMaps(self):
+        """!Get list of maps"""
+        result = dict()
+        result['raster'] = grass.list_strings('rast')
+        result['vector'] = grass.list_strings('vect')
+        
+        return result
+
+    def OnRunCmd(self, event):
+        """!Run command"""
+        cmdString = event.GetString()
+        
+        if self.standAlone:
+            return
+        
+        if cmdString[:2] == 'd.' and not self.parent.curr_page:
+            self.parent.NewDisplay(show=True)
+        
+        cmd = utils.split(cmdString)
+        if len(cmd) > 1:
+            self.parent.RunCmd(cmd, switchPage = True)
+        else:
+            self.parent.RunCmd(cmd, switchPage = False)
+        
+        self.OnUpdateStatusBar(None)
+        
+    def OnUpdateStatusBar(self, event):
+        """!Update Layer Manager status bar"""
+        if self.standAlone:
+            return
+        
+        if event is None:
+            self.parent.parent.statusbar.SetStatusText("")
+        else:
+            self.parent.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
+            event.Skip()
+        
+    def GetPanel(self):
+        """!Get main widget panel"""
+        return self.panel
+
+    def GetInput(self):
+        """!Get main prompt widget"""
+        return self.input
+    
+    def SetFilter(self, data, module = True):
+        """!Set filter
+
+        @param data data dict
+        @param module True to filter modules, otherwise data
+        """
+        if module:
+            if data:
+                self.moduleList = data
+            else:
+                self.moduleList = self._getListOfModules()
+        else:
+            if data:
+                self.dataList = data
+            else:
+                self.dataList = self._getListOfMaps()
+        
+class GPromptPopUp(GPrompt, TextCtrlAutoComplete):
+    """!Interactive wxGUI prompt - popup version"""
+    def __init__(self, parent):
+        GPrompt.__init__(self, parent)
+        
+        ### todo: fix TextCtrlAutoComplete to work also on Macs
+        ### reason: missing wx.PopupWindow()
+        try:
+            TextCtrlAutoComplete.__init__(self, parent = self.panel, id = wx.ID_ANY,
+                                          value = "",
+                                          style = wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
+                                          statusbar = self.parent.parent.statusbar)
+            self.SetItems(self._readHistory())
+        except NotImplementedError:
+            # wx.PopupWindow may be not available in wxMac
+            # see http://trac.wxwidgets.org/ticket/9377
+            wx.TextCtrl.__init__(parent = self.panel, id = wx.ID_ANY,
+                                 value = "",
+                                 style=wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
+                                 size = (-1, 25))
+            self.searchBy.Enable(False)
+            self.search.Enable(False)
+        
+        self.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, ''))
+        
+        wx.CallAfter(self.SetInsertionPoint, 0)
+        
+        # bidnings
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
+        self.Bind(wx.EVT_TEXT,       self.OnUpdateStatusBar)
+        
+    def OnCmdErase(self, event):
+        """!Erase command prompt"""
+        self.input.SetValue('')
+
+class GPromptSTC(GPrompt, wx.stc.StyledTextCtrl):
+    """!Styled wxGUI prompt with autocomplete and calltips"""    
+    def __init__(self, parent, id = wx.ID_ANY, margin = False):
+        GPrompt.__init__(self, parent)
+        wx.stc.StyledTextCtrl.__init__(self, self.panel, id)
+        
+        #
+        # styles
+        #                
+        self.SetWrapMode(True)
+        self.SetUndoCollection(True)        
+        
+        #
+        # create command and map lists for autocompletion
+        #
+        self.AutoCompSetIgnoreCase(False) 
+        
+        #
+        # line margins
+        #
+        # TODO print number only from cmdlog
+        self.SetMarginWidth(1, 0)
+        self.SetMarginWidth(2, 0)
+        if margin:
+            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+            self.SetMarginWidth(0, 30)
+        else:
+            self.SetMarginWidth(0, 0)
+        
+        #
+        # miscellaneous
+        #
+        self.SetViewWhiteSpace(False)
+        self.SetUseTabs(False)
+        self.UsePopUp(True)
+        self.SetSelBackground(True, "#FFFF00")
+        self.SetUseHorizontalScrollBar(True)
+        
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+        self.Bind(wx.stc.EVT_STC_AUTOCOMP_SELECTION, self.OnItemSelected)
+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemChanged)
+        
+    def OnTextSelectionChanged(self, event):
+        """!Copy selected text to clipboard and skip event.
+        The same function is in GMStc class (goutput.py).
+        """
+        self.Copy()
+        event.Skip()
+        
+    def OnItemChanged(self, event):
+        """!Change text in statusbar 
+        if the item selection in the auto-completion list is changed"""
+        # list of commands
+        if self.toComplete['entity'] == 'command':
+            item = self.toComplete['cmd'].rpartition('.')[0] + '.' + self.autoCompList[event.GetIndex()] 
+            try:
+                desc = self.moduleDesc[item]['desc']        
+            except KeyError:
+                desc = '' 
+            self.ShowStatusText(desc)
+        # list of flags    
+        elif self.toComplete['entity'] == 'flags':
+            desc = self.cmdDesc.get_flag(self.autoCompList[event.GetIndex()])['description']
+            self.ShowStatusText(desc)
+        # list of parameters
+        elif self.toComplete['entity'] == 'params':
+            item = self.cmdDesc.get_param(self.autoCompList[event.GetIndex()])
+            desc = item['name'] + '=' + item['type']
+            if not item['required']:
+                desc = '[' + desc + ']'
+            desc += ': ' + item['description']
+            self.ShowStatusText(desc)
+        # list of flags and commands       
+        elif self.toComplete['entity'] == 'params+flags':
+            if self.autoCompList[event.GetIndex()][0] == '-':
+                desc = self.cmdDesc.get_flag(self.autoCompList[event.GetIndex()].strip('-'))['description']
+            else:
+                item = self.cmdDesc.get_param(self.autoCompList[event.GetIndex()])
+                desc = item['name'] + '=' + item['type']
+                if not item['required']:
+                    desc = '[' + desc + ']'
+                desc += ': ' + item['description']
+            self.ShowStatusText(desc)
+        else:
+            self.ShowStatusText('')
+            
+    def OnItemSelected(self, event):
+        """!Item selected from the list"""
+        lastWord = self.GetWordLeft()
+        # to insert selection correctly if selected word partly matches written text
+        match = difflib.SequenceMatcher(None, event.GetText(), lastWord)
+        matchTuple = match.find_longest_match(0, len(event.GetText()), 0, len(lastWord))
+    
+        compl = event.GetText()[matchTuple[2]:]
+        text = self.GetTextLeft() + compl
+        # add space or '=' at the end
+        end = '='
+        for char in ('.','-','='):
+            if text.split(' ')[-1].find(char) >= 0:
+                end = ' '
+        
+        compl += end
+        text += end
+
+        self.AddText(compl)
+        pos = len(text)
+        self.SetCurrentPos(pos)
+        
+        cmd = text.strip().split(' ')[0]
+
+        if not self.cmdDesc or cmd != self.cmdDesc.get_name():
+            if cmd in ('r.mapcalc', 'r3.mapcalc') and \
+                    self.parent.parent.GetName() == 'LayerManager':
+                self.parent.parent.OnMapCalculator(event = None, cmd = [cmd])
+                # add command to history & clean prompt
+                self.UpdateCmdHistory([cmd])
+                self.OnCmdErase(None)
+            else:
+                try:
+                    self.cmdDesc = gtask.parse_interface(cmd)
+                except IOError:
+                    self.cmdDesc = None
+        
+    def UpdateCmdHistory(self, cmd):
+        """!Update command history
+        
+        @param cmd command given as a list
+        """
+        # add command to history    
+        self.cmdbuffer.append(' '.join(cmd))
+        
+        # keep command history to a managable size
+        if len(self.cmdbuffer) > 200:
+            del self.cmdbuffer[0]
+        self.cmdindex = len(self.cmdbuffer)
+        
+    def EntityToComplete(self):
+        """!Determines which part of command (flags, parameters) should
+        be completed at current cursor position"""
+        entry = self.GetTextLeft()
+        toComplete = dict()
+        try:
+            cmd = entry.split()[0].strip()
+        except IndexError:
+            return None
+        
+        if len(utils.split(str(entry))) > 1:
+            if cmd in globalvar.grassCmd['all']:
+                toComplete['cmd'] = cmd
+                if entry[-1] == ' ':
+                    words = entry.split(' ')
+                    if any(word.startswith('-') for word in words):
+                        toComplete['entity'] = 'params'
+                    else:
+                        toComplete['entity'] = 'params+flags'
+                else:
+                    # get word left from current position
+                    word = self.GetWordLeft(withDelimiter = True)
+                    
+                    if word[0] == '=' and word[-1] == '@':
+                        toComplete['entity'] = 'mapsets'
+                    elif word[0] == '=':
+                        # get name of parameter
+                        paramName = self.GetWordLeft(withDelimiter = False, ignoredDelimiter = '=').strip('=')
+                        if paramName:
+                            try:
+                                param = self.cmdDesc.get_param(paramName)
+                            except (ValueError, AttributeError):
+                                return None
+                        else:
+                            return None
+                        
+                        if param['values']:
+                            toComplete['entity'] = 'param values'
+                        elif param['prompt'] == 'raster' and param['element'] == 'cell':
+                            toComplete['entity'] = 'raster map'
+                        elif param['prompt'] == 'vector' and param['element'] == 'vector':
+                            toComplete['entity'] = 'vector map'
+                    elif word[0] == '-':
+                        toComplete['entity'] = 'flags'
+                    elif word[0] == ' ':
+                        toComplete['entity'] = 'params'
+            else:
+                return None
+        else:
+            toComplete['entity'] = 'command'
+            toComplete['cmd'] = cmd
+        
+        return toComplete
+    
+    def GetWordLeft(self, withDelimiter = False, ignoredDelimiter = None):
+        """!Get word left from current cursor position. The beginning
+        of the word is given by space or chars: .,-= 
+        
+        @param withDelimiter returns the word with the initial delimeter
+        @param ignoredDelimiter finds the word ignoring certain delimeter
+        """
+        textLeft = self.GetTextLeft()
+        
+        parts = list()
+        if ignoredDelimiter is None:
+            ignoredDelimiter = ''
+        
+        for char in set(' .,-=') - set(ignoredDelimiter):
+            if not withDelimiter:
+                delimiter = ''
+            else:
+                delimiter = char
+            parts.append(delimiter + textLeft.rpartition(char)[2])
+        return min(parts, key=lambda x: len(x))
+         
+    def ShowList(self):
+        """!Show sorted auto-completion list if it is not empty"""
+        if len(self.autoCompList) > 0:
+            self.autoCompList.sort()
+            self.AutoCompShow(lenEntered = 0, itemList = ' '.join(self.autoCompList))    
+        
+    def OnKeyPressed(self, event):
+        """!Key press capture for autocompletion, calltips, and command history
+
+        @todo event.ControlDown() for manual autocomplete
+        """
+        # keycodes used: "." = 46, "=" = 61, "-" = 45 
+        pos = self.GetCurrentPos()
+        #complete command after pressing '.'
+        if event.GetKeyCode() == 46 and not event.ShiftDown():
+            self.autoCompList = list()
+            entry = self.GetTextLeft()
+            self.InsertText(pos, '.')
+            self.CharRight()
+            self.toComplete = self.EntityToComplete()
+            try:
+                if self.toComplete['entity'] == 'command': 
+                    self.autoCompList = self.moduleList[entry.strip()]
+            except (KeyError, TypeError):
+                return
+            self.ShowList()
+
+        # complete flags after pressing '-'       
+        elif event.GetKeyCode() == 45 and not event.ShiftDown(): 
+            self.autoCompList = list()
+            entry = self.GetTextLeft()
+            self.InsertText(pos, '-')
+            self.CharRight()
+            self.toComplete = self.EntityToComplete()
+            if self.toComplete['entity'] == 'flags' and self.cmdDesc:
+                if self.GetTextLeft()[-2:] == ' -': # complete e.g. --quite
+                    for flag in self.cmdDesc.get_options()['flags']:
+                        if len(flag['name']) == 1:
+                            self.autoCompList.append(flag['name'])
+                else:
+                    for flag in self.cmdDesc.get_options()['flags']:
+                        if len(flag['name']) > 1:
+                            self.autoCompList.append(flag['name'])            
+            self.ShowList()
+            
+        # complete map or values after parameter
+        elif event.GetKeyCode() == 61 and not event.ShiftDown():
+            self.autoCompList = list()
+            self.InsertText(pos, '=')
+            self.CharRight()
+            self.toComplete = self.EntityToComplete()
+            if self.toComplete and 'entity' in self.toComplete:
+                if self.toComplete['entity'] == 'raster map':
+                    self.autoCompList = self.mapList['raster']
+                elif self.toComplete['entity'] == 'vector map':
+                    self.autoCompList = self.mapList['vector']
+                elif self.toComplete['entity'] == 'param values':
+                    param = self.GetWordLeft(withDelimiter = False, ignoredDelimiter='=').strip(' =')
+                    self.autoCompList = self.cmdDesc.get_param(param)['values']
+            self.ShowList()
+        
+        # complete mapset ('@')
+        elif event.GetKeyCode() == 50 and event.ShiftDown():
+            self.autoCompList = list()
+            self.InsertText(pos, '@')
+            self.CharRight()
+            self.toComplete = self.EntityToComplete()
+            
+            if self.toComplete and self.toComplete['entity'] == 'mapsets':
+                self.autoCompList = self.mapsetList
+            self.ShowList()
+            
+        # complete after pressing CTRL + Space          
+        elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
+            self.autoCompList = list()
+            self.toComplete = self.EntityToComplete()
+            if self.toComplete is None:
+                return 
+
+            #complete command
+            if self.toComplete['entity'] == 'command':
+                for command in globalvar.grassCmd['all']:
+                    if command.find(self.toComplete['cmd']) == 0:
+                        dotNumber = list(self.toComplete['cmd']).count('.') 
+                        self.autoCompList.append(command.split('.',dotNumber)[-1])
+                
+            
+            # complete flags in such situations (| is cursor):
+            # r.colors -| ...w, q, l
+            # r.colors -w| ...w, q, l  
+            elif self.toComplete['entity'] == 'flags' and self.cmdDesc:
+                for flag in self.cmdDesc.get_options()['flags']:
+                    if len(flag['name']) == 1:
+                        self.autoCompList.append(flag['name'])
+                    
+            # complete parameters in such situations (| is cursor):
+            # r.colors -w | ...color, map, rast, rules
+            # r.colors col| ...color
+            elif self.toComplete['entity'] == 'params' and self.cmdDesc:
+                for param in self.cmdDesc.get_options()['params']:
+                    if param['name'].find(self.GetWordLeft(withDelimiter=False)) == 0:
+                        self.autoCompList.append(param['name'])           
+            
+            # complete flags or parameters in such situations (| is cursor):
+            # r.colors | ...-w, -q, -l, color, map, rast, rules
+            # r.colors color=grey | ...-w, -q, -l, color, map, rast, rules
+            elif self.toComplete['entity'] == 'params+flags' and self.cmdDesc:
+                self.autoCompList = list()
+                
+                for param in self.cmdDesc.get_options()['params']:
+                    self.autoCompList.append(param['name'])
+                for flag in self.cmdDesc.get_options()['flags']:
+                    if len(flag['name']) == 1:
+                        self.autoCompList.append('-' + flag['name'])
+                    else:
+                        self.autoCompList.append('--' + flag['name'])
+                    
+                self.ShowList() 
+                   
+            # complete map or values after parameter  
+            # r.buffer input=| ...list of raster maps
+            # r.buffer units=| ... feet, kilometers, ...   
+            elif self.toComplete['entity'] == 'raster map':
+                self.autoCompList = list()
+                self.autoCompList = self.mapList['raster']
+            elif self.toComplete['entity'] == 'vector map':
+                self.autoCompList = list()
+                self.autoCompList = self.mapList['vector']
+            elif self.toComplete['entity'] == 'param values':
+                self.autoCompList = list()
+                param = self.GetWordLeft(withDelimiter = False, ignoredDelimiter='=').strip(' =')
+                self.autoCompList = self.cmdDesc.get_param(param)['values']
+                
+            self.ShowList()
+
+        elif event.GetKeyCode() == wx.WXK_TAB:
+            # show GRASS command calltips (to hide press 'ESC')
+            entry = self.GetTextLeft()
+            try:
+                cmd = entry.split()[0].strip()
+            except IndexError:
+                cmd = ''
+            
+            if cmd not in globalvar.grassCmd['all']:
+                return
+            
+            info = gtask.command_info(cmd)
+            
+            self.CallTipSetBackground("#f4f4d1")
+            self.CallTipSetForeground("BLACK")
+            self.CallTipShow(pos, info['usage'] + '\n\n' + info['description'])
+            
+            
+        elif event.GetKeyCode() in [wx.WXK_UP, wx.WXK_DOWN] and \
+                 not self.AutoCompActive():
+            # Command history using up and down   
+            if len(self.cmdbuffer) < 1:
+                return
+            
+            self.DocumentEnd()
+            
+            # move through command history list index values
+            if event.GetKeyCode() == wx.WXK_UP:
+                self.cmdindex = self.cmdindex - 1
+            if event.GetKeyCode() == wx.WXK_DOWN:
+                self.cmdindex = self.cmdindex + 1
+            if self.cmdindex < 0:
+                self.cmdindex = 0
+            if self.cmdindex > len(self.cmdbuffer) - 1:
+                self.cmdindex = len(self.cmdbuffer) - 1
+            
+            try:
+                txt = self.cmdbuffer[self.cmdindex]
+            except:
+                txt = ''
+            
+            # clear current line and insert command history    
+            self.DelLineLeft()
+            self.DelLineRight()
+            pos = self.GetCurrentPos()            
+            self.InsertText(pos,txt)
+            self.LineEnd()
+            self.parent.parent.statusbar.SetStatusText('')
+            
+        elif event.GetKeyCode() == wx.WXK_RETURN and \
+                self.AutoCompActive() == False:
+            # run command on line when <return> is pressed
+            
+            if self.parent.GetName() == "ModelerDialog":
+                self.parent.OnOk(None)
+                return
+            
+            # find the command to run
+            line = self.GetCurLine()[0].strip()
+            if len(line) == 0:
+                return
+            
+            # parse command into list
+            try:
+                cmd = utils.split(str(line))
+            except UnicodeError:
+                cmd = utils.split(utils.EncodeString((line)))
+            cmd = map(utils.DecodeString, cmd)
+            
+            #  send the command list to the processor 
+            if cmd[0] in ('r.mapcalc', 'r3.mapcalc') and len(cmd) == 1:
+                self.parent.parent.OnMapCalculator(event = None, cmd = cmd)
+            else:
+                self.parent.RunCmd(cmd)
+            
+            # add command to history & clean prompt
+            self.UpdateCmdHistory(cmd)
+            self.OnCmdErase(None)
+            self.parent.parent.statusbar.SetStatusText('')
+            
+        elif event.GetKeyCode() == wx.WXK_SPACE:
+            items = self.GetTextLeft().split()
+            if len(items) == 1:
+                cmd = items[0].strip()
+                if cmd in globalvar.grassCmd['all'] and \
+                        cmd != 'r.mapcalc' and \
+                        (not self.cmdDesc or cmd != self.cmdDesc.get_name()):
+                    try:
+                        self.cmdDesc = gtask.parse_interface(cmd)
+                    except IOError:
+                        self.cmdDesc = None
+            event.Skip()
+        
+        else:
+            event.Skip()
+
+    def ShowStatusText(self, text):
+        """!Sets statusbar text, if it's too long, it is cut off"""
+        maxLen = self.parent.parent.statusbar.GetFieldRect(0).GetWidth()/ 7 # any better way?
+        if len(text) < maxLen:
+            self.parent.parent.statusbar.SetStatusText(text)
+        else:
+            self.parent.parent.statusbar.SetStatusText(text[:maxLen]+'...')
+        
+        
+    def GetTextLeft(self):
+        """!Returns all text left of the caret"""
+        pos = self.GetCurrentPos()
+        self.HomeExtend()
+        entry = self.GetSelectedText()
+        self.SetCurrentPos(pos)
+        
+        return entry
+    
+    def OnDestroy(self, event):
+        """!The clipboard contents can be preserved after
+        the app has exited"""
+        wx.TheClipboard.Flush()
+        event.Skip()
+
+    def OnCmdErase(self, event):
+        """!Erase command prompt"""
+        self.Home()
+        self.DelLineRight()

Copied: grass/trunk/gui/wxpython/gui_core/toolbars.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/toolbars.py)
===================================================================
--- grass/trunk/gui/wxpython/gui_core/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,177 @@
+"""!
+ at package gui_core.toolbars
+
+ at brief Base classes toolbar widgets
+
+Classes:
+ - BaseToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import platform
+
+import wx
+
+from core               import globalvar
+from core.debug         import Debug
+
+class BaseToolbar(wx.ToolBar):
+    """!Abstract toolbar class"""
+    def __init__(self, parent):
+        self.parent = parent
+        wx.ToolBar.__init__(self, parent = self.parent, id = wx.ID_ANY)
+        
+        self.action = dict()
+        
+        self.Bind(wx.EVT_TOOL, self.OnTool)
+        
+        self.SetToolBitmapSize(globalvar.toolbarSize)
+        
+    def InitToolbar(self, toolData):
+        """!Initialize toolbar, add tools to the toolbar
+        """
+        for tool in toolData:
+            self.CreateTool(*tool)
+        
+        self._data = toolData
+        
+    def _toolbarData(self):
+        """!Toolbar data (virtual)"""
+        return None
+    
+    def CreateTool(self, label, bitmap, kind,
+                   shortHelp, longHelp, handler, pos = -1):
+        """!Add tool to the toolbar
+        
+        @param pos if -1 add tool, if > 0 insert at given pos
+        @return id of tool
+        """
+        bmpDisabled = wx.NullBitmap
+        tool = -1
+        if label:
+            tool = vars(self)[label] = wx.NewId()
+            Debug.msg(3, "CreateTool(): tool=%d, label=%s bitmap=%s" % \
+                          (tool, label, bitmap))
+            if pos < 0:
+                toolWin = self.AddLabelTool(tool, label, bitmap,
+                                            bmpDisabled, kind,
+                                            shortHelp, longHelp)
+            else:
+                toolWin = self.InsertLabelTool(pos, tool, label, bitmap,
+                                            bmpDisabled, kind,
+                                            shortHelp, longHelp)
+            self.Bind(wx.EVT_TOOL, handler, toolWin)
+        else: # separator
+            self.AddSeparator()
+        
+        return tool
+    
+    def EnableLongHelp(self, enable = True):
+        """!Enable/disable long help
+        
+        @param enable True for enable otherwise disable
+        """
+        for tool in self._data:
+            if tool[0] == '': # separator
+                continue
+            
+            if enable:
+                self.SetToolLongHelp(vars(self)[tool[0]], tool[4])
+            else:
+                self.SetToolLongHelp(vars(self)[tool[0]], "")
+        
+    def OnTool(self, event):
+        """!Tool selected
+        """
+        if self.parent.GetName() == "GCPFrame":
+            return
+        
+        if hasattr(self.parent, 'toolbars'):
+            if self.parent.GetToolbar('vdigit'):
+                # update vdigit toolbar (unselect currently selected tool)
+                id = self.parent.toolbars['vdigit'].GetAction(type = 'id')
+                self.parent.toolbars['vdigit'].ToggleTool(id, False)
+        
+        if event:
+            # deselect previously selected tool
+            id = self.action.get('id', -1)
+            if id != event.GetId():
+                self.ToggleTool(self.action['id'], False)
+            else:
+                self.ToggleTool(self.action['id'], True)
+            
+            self.action['id'] = event.GetId()
+            
+            event.Skip()
+        else:
+            # initialize toolbar
+            self.ToggleTool(self.action['id'], True)
+        
+    def GetAction(self, type = 'desc'):
+        """!Get current action info"""
+        return self.action.get(type, '')
+    
+    def SelectDefault(self, event):
+        """!Select default tool"""
+        self.ToggleTool(self.defaultAction['id'], True)
+        self.defaultAction['bind'](event)
+        self.action = { 'id' : self.defaultAction['id'],
+                        'desc' : self.defaultAction.get('desc', '') }
+        
+    def FixSize(self, width):
+        """!Fix toolbar width on Windows
+            
+        @todo Determine why combobox causes problems here
+        """
+        if platform.system() == 'Windows':
+            size = self.GetBestSize()
+            self.SetSize((size[0] + width, size[1]))
+
+    def Enable(self, tool, enable = True):
+        """!Enable/Disable defined tool
+        
+        @param tool name
+        @param enable True to enable otherwise disable tool
+        """
+        try:
+            id = getattr(self, tool)
+        except AttributeError:
+            return
+        
+        self.EnableTool(id, enable)
+
+    def EnableAll(self, enable = True):
+        """!Enable/Disable all tools
+        
+        @param enable True to enable otherwise disable tool
+        """
+        for item in self._toolbarData():
+            if not item[0]:
+                continue
+            self.Enable(item[0], enable)
+        
+    def _getToolbarData(self, data):
+        """!Define tool
+        """
+        retData = list()
+        for args in data:
+            retData.append(self._defineTool(*args))
+        return retData
+
+    def _defineTool(self, name = None, icon = None, handler = None, item = wx.ITEM_NORMAL, pos = -1):
+        """!Define tool
+        """
+        if name:
+            return (name, icon.GetBitmap(),
+                    item, icon.GetLabel(), icon.GetDesc(),
+                    handler, pos)
+        return ("", "", "", "", "", "") # separator

Added: grass/trunk/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/widgets.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_core/widgets.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,231 @@
+"""!
+ at package gui_core.widgets
+
+ at brief Core GUI widgets
+
+Classes:
+ - ScrolledPanel
+ - NTCValidator
+ - NumTextCtrl
+ - FloatSlider
+ - SymbolButton
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Enhancements by Michael Barton <michael.barton asu.edu>
+ at author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
+"""
+
+import string
+
+import wx
+import wx.lib.scrolledpanel as SP
+try:
+    import wx.lib.agw.flatnotebook   as FN
+except ImportError:
+    import wx.lib.flatnotebook   as FN
+try:
+    from wx.lib.buttons import ThemedGenBitmapTextButton as BitmapTextButton
+except ImportError: # not sure about TGBTButton version
+    from wx.lib.buttons import GenBitmapTextButton as BitmapTextButton
+
+from core import globalvar
+
+class GNotebook(FN.FlatNotebook):
+    """!Generic notebook widget
+    """
+    def __init__(self, parent, style, **kwargs):
+        if globalvar.hasAgw:
+            FN.FlatNotebook.__init__(self, parent, id = wx.ID_ANY, agwStyle = style, **kwargs)
+        else:
+            FN.FlatNotebook.__init__(self, parent, id = wx.ID_ANY, style = style, **kwargs)
+        
+        self.notebookPages = {}
+            
+    def AddPage(self, **kwargs):
+        """!Add a new page
+        """
+        if 'name' in kwargs:
+            self.notebookPages[kwargs['name']] = kwargs['page']
+            del kwargs['name']
+        super(GNotebook, self).AddPage(**kwargs)
+
+    def InsertPage(self, **kwargs):
+        """!Insert a new page
+        """
+        if 'name' in kwargs:
+            self.notebookPages[kwargs['name']] = kwargs['page']
+            del kwargs['name']
+        super(GNotebook, self).InsertPage(**kwargs)
+
+    def SetSelectionByName(self, page):
+        """!Set notebook
+        
+        @param page names, eg. 'layers', 'output', 'search', 'pyshell', 'nviz'
+        """
+        idx = self.GetPageIndexByName(page)
+        if self.GetSelection() != idx:
+            self.SetSelection(idx)
+        
+    def GetPageIndexByName(self, page):
+        """!Get notebook page index
+        
+        @param page name
+        """
+        if page not in self.notebookPages:
+            return -1
+        
+        return self.GetPageIndex(self.notebookPages[page])
+
+class ScrolledPanel(SP.ScrolledPanel):
+    """!Custom ScrolledPanel to avoid strange behaviour concerning focus"""
+    def __init__(self, parent):
+        SP.ScrolledPanel.__init__(self, parent = parent, id = wx.ID_ANY)
+    def OnChildFocus(self, event):
+        pass
+        
+        
+class NTCValidator(wx.PyValidator):
+    """!validates input in textctrls, taken from wxpython demo"""
+    def __init__(self, flag = None):
+        wx.PyValidator.__init__(self)
+        self.flag = flag
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+
+    def Clone(self):
+        return NTCValidator(self.flag)
+
+    def OnChar(self, event):
+        key = event.GetKeyCode()
+        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
+            event.Skip()
+            return
+        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.-':
+            event.Skip()
+            return
+        if not wx.Validator_IsSilent():
+            wx.Bell()
+        # Returning without calling even.Skip eats the event before it
+        # gets to the text control
+        return  
+    
+class NumTextCtrl(wx.TextCtrl):
+    """!Class derived from wx.TextCtrl for numerical values only"""
+    def __init__(self, parent,  **kwargs):
+##        self.precision = kwargs.pop('prec')
+        wx.TextCtrl.__init__(self, parent = parent,
+            validator = NTCValidator(flag = 'DIGIT_ONLY'), **kwargs)
+        
+            
+    def SetValue(self, value):
+        super(NumTextCtrl, self).SetValue( str(value))
+        
+    def GetValue(self):
+        val = super(NumTextCtrl, self).GetValue()
+        if val == '':
+            val = '0'
+        try:
+            return float(val)
+        except ValueError:
+            val = ''.join(''.join(val.split('-')).split('.'))
+            return float(val)
+        
+    def SetRange(self, min, max):
+        pass
+   
+class FloatSlider(wx.Slider):
+    """!Class derived from wx.Slider for floats"""
+    def __init__(self, **kwargs):
+        Debug.msg(1, "FloatSlider.__init__()")
+        wx.Slider.__init__(self, **kwargs)
+        self.coef = 1.
+        #init range
+        self.minValueOrig = 0
+        self.maxValueOrig = 1
+        
+    def SetValue(self, value):
+        value *= self.coef 
+        if abs(value) < 1 and value != 0:
+            while abs(value) < 1:
+                value *= 100
+                self.coef *= 100
+            super(FloatSlider, self).SetRange(self.minValueOrig * self.coef, self.maxValueOrig * self.coef)
+        super(FloatSlider, self).SetValue(value)
+        
+        Debug.msg(4, "FloatSlider.SetValue(): value = %f" % value)
+        
+    def SetRange(self, minValue, maxValue):
+        self.coef = 1.
+        self.minValueOrig = minValue
+        self.maxValueOrig = maxValue
+        if abs(minValue) < 1 or abs(maxValue) < 1:
+            while (abs(minValue) < 1 and minValue != 0) or (abs(maxValue) < 1 and maxValue != 0):
+                minValue *= 100
+                maxValue *= 100
+                self.coef *= 100
+            super(FloatSlider, self).SetValue(super(FloatSlider, self).GetValue() * self.coef)
+        super(FloatSlider, self).SetRange(minValue, maxValue)
+        Debug.msg(4, "FloatSlider.SetRange(): minValue = %f, maxValue = %f" % (minValue, maxValue))
+            
+    def GetValue(self):
+        val = super(FloatSlider, self).GetValue()
+        Debug.msg(4, "FloatSlider.GetValue(): value = %f" % (val/self.coef))
+        return val/self.coef
+        
+        
+class SymbolButton(BitmapTextButton):
+    """!Button with symbol and label."""
+    def __init__(self, parent, usage, label, **kwargs):
+        """!Constructor
+        
+        @param parent parent (usually wx.Panel)
+        @param usage determines usage and picture
+        @param label displayed label
+        """
+        BitmapTextButton.__init__(self, parent = parent, label = " " + label, **kwargs)
+        
+        size = (15, 15)
+        buffer = wx.EmptyBitmap(*size)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        maskColor = wx.Color(255, 255, 255)
+        dc.SetBrush(wx.Brush(maskColor))
+        dc.Clear()
+        
+        if usage == 'record':
+            self.DrawRecord(dc, size)
+        elif usage == 'stop':
+            self.DrawStop(dc, size)
+        elif usage == 'play':
+            self.DrawPlay(dc, size)
+        elif usage == 'pause':
+            self.DrawPause(dc, size)
+
+        buffer.SetMaskColour(maskColor)
+        self.SetBitmapLabel(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def DrawRecord(self, dc, size):
+        """!Draw record symbol"""
+        dc.SetBrush(wx.Brush(wx.Color(255, 0, 0)))
+        dc.DrawCircle(size[0]/2, size[1] / 2, size[0] / 2)
+        
+    def DrawStop(self, dc, size):
+        """!Draw stop symbol"""
+        dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
+        dc.DrawRectangle(0, 0, size[0], size[1])
+        
+    def DrawPlay(self, dc, size):
+        """!Draw play symbol"""
+        dc.SetBrush(wx.Brush(wx.Color(0, 255, 0)))
+        points = (wx.Point(0, 0), wx.Point(0, size[1]), wx.Point(size[0], size[1] / 2))
+        dc.DrawPolygon(points)
+        
+    def DrawPause(self, dc, size):
+        """!Draw pause symbol"""
+        dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
+        dc.DrawRectangle(0, 0, 2 * size[0] / 5, size[1])
+        dc.DrawRectangle(3 * size[0] / 5, 0, 2 * size[0] / 5, size[1])


Property changes on: grass/trunk/gui/wxpython/gui_core/widgets.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Deleted: grass/trunk/gui/wxpython/gui_modules/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/__init__.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/__init__.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,46 +0,0 @@
-all = [
-    "colorrules.py",
-    "dbm.py",
-    "dbm_base.py",
-    "dbm_dialogs.py",
-    "debug.py",
-    "disp_print.py",
-    "gcmd.py",
-    "gcpmanager.py",
-    "gcpmapdisp.py",
-    "gdialogs.py",
-    "georect.py",
-    "ghelp.py"
-    "globalvar.py",
-    "goutput.py",
-    "gselect.py",
-    "histogram.py",
-    "layertree.py",
-    "location_wizard.py",
-    "mapdisp_window.py",
-    "mapdisp.py",
-    "mapdisp_statusbar.py",
-    "mcalc_builder.py",
-    "menu.py",
-    "menudata.py",
-    "menuform.py",
-    "nviz_mapdisp.py",
-    "nviz_preferences.py",
-    "nviz_tools.py",
-    "ogc_services.py",
-    "preferences.py",
-    "render.py",
-    "rules.py",
-    "sqlbuilder.py",
-    "toolbars.py",
-    "units.py",
-    "utils.py",
-    "vclean.py",
-    "vdigit.py",
-    "workspace.py",
-    "wxnviz.py",
-    "wxplot.py",
-    "wxplot_dialogs.py",
-    "wxvdriver.py",
-    "wxvdigit.py",
-]

Deleted: grass/trunk/gui/wxpython/gui_modules/colorrules.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/colorrules.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/colorrules.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1843 +0,0 @@
-"""
- at package colorrules.py
-
- at brief Dialog for interactive management of raster color tables and
-vector rgb_column attributes.
-
-Classes:
- - RulesPanel
- - ColorTable
- - RasterColorTable
- - VectorColorTable
- - ThematicVectorTable
- - BuferedWindow
-
-(C) 2008, 2010-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton (Arizona State University)
- at author Martin Landa <landa.martin gmail.com> (various updates)
- at author Anna Kratochvilova <kratochanna gmail.com> (split to base and derived classes)
-"""
-
-import os
-import sys
-import shutil
-import copy
-import tempfile
-
-import wx
-import wx.lib.colourselect as csel
-import wx.lib.scrolledpanel as scrolled
-import wx.lib.filebrowsebutton as filebrowse
-
-import grass.script as grass
-
-import dbm
-import gcmd
-import globalvar
-import gselect
-import render
-import utils
-import menuform
-from debug import Debug as Debug
-from preferences import globalSettings as UserSettings
-from nviz_mapdisp import wxUpdateProperties
-
-
-class RulesPanel:
-    def __init__(self, parent, mapType, attributeType, properties, panelWidth = 180):
-        """!Create rules panel
-        
-        @param mapType raster/vector
-        @param attributeType color/size for choosing widget type
-        @param properties properties of classes derived from ColorTable
-        @param panelWidth width of scroll panel"""
-        
-        self.ruleslines = {}
-        self.mapType = mapType
-        self.attributeType = attributeType
-        self.properties = properties
-        self.parent = parent
-        self.panelWidth = panelWidth
-        
-        self.mainSizer = wx.FlexGridSizer(cols = 3, vgap = 6, hgap = 4)
-        # put small border at the top of panel
-        for i in range(3):
-            self.mainSizer.Add(item = wx.Size(3, 3))
-        
-        self.mainPanel = scrolled.ScrolledPanel(parent, id = wx.ID_ANY,
-                                          size = (self.panelWidth, 300),
-                                          style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
-                
-        # (un)check all
-        self.checkAll = wx.CheckBox(parent, id = wx.ID_ANY, label = _("Check all"))
-        self.checkAll.SetValue(True)
-        # clear button
-        self.clearAll = wx.Button(parent, id = wx.ID_ANY, label = _("Clear all"))
-        #  determines how many rules should be added
-        self.numRules = wx.SpinCtrl(parent, id = wx.ID_ANY,
-                                    min = 1, max = 1e6)
-        # add rules
-        self.btnAdd = wx.Button(parent, id = wx.ID_ADD)
-        
-        self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAddRules)
-        self.checkAll.Bind(wx.EVT_CHECKBOX, self.OnCheckAll)
-        self.clearAll.Bind(wx.EVT_BUTTON, self.OnClearAll)
-
-        self.mainPanel.SetSizer(self.mainSizer)
-        self.mainPanel.SetAutoLayout(True)
-        self.mainPanel.SetupScrolling()    
-    
-    def Clear(self):
-        """!Clear and widgets and delete information"""
-        self.ruleslines.clear()
-        self.mainSizer.Clear(deleteWindows=True)
-    
-    def OnCheckAll(self, event):
-        """!(Un)check all rules"""
-        check = event.GetInt()
-        for child in self.mainPanel.GetChildren():
-            if child.GetName() == 'enable':
-                child.SetValue(check)
-            else:
-                child.Enable(check)
-                
-    def OnClearAll(self, event):
-        """!Delete all widgets in panel"""
-        self.Clear()
-        
-    def OnAddRules(self, event):
-        """!Add rules button pressed"""
-        nrules = self.numRules.GetValue()
-        self.AddRules(nrules)
-        
-    def AddRules(self, nrules, start = False):
-        """!Add rules 
-        @param start set widgets (not append)"""
-       
-        snum = len(self.ruleslines.keys())
-        if start:
-            snum = 0
-        for num in range(snum, snum + nrules):
-            # enable
-            enable = wx.CheckBox(parent = self.mainPanel, id = num)
-            enable.SetValue(True)
-            enable.SetName('enable')
-            enable.Bind(wx.EVT_CHECKBOX, self.OnRuleEnable)
-            # value
-            txt_ctrl = wx.TextCtrl(parent = self.mainPanel, id = 1000 + num,
-                                   size = (80, -1),
-                                   style = wx.TE_NOHIDESEL)
-            if self.mapType == 'vector':
-                txt_ctrl.SetToolTipString(_("Enter vector attribute values"))
-            txt_ctrl.Bind(wx.EVT_TEXT, self.OnRuleValue)
-            txt_ctrl.SetName('source')
-            if self.attributeType == 'color':
-                # color
-                columnCtrl = csel.ColourSelect(self.mainPanel, id = 2000 + num,
-                                               size  =  globalvar.DIALOG_COLOR_SIZE)
-                columnCtrl.Bind(csel.EVT_COLOURSELECT, self.OnRuleColor)
-                columnCtrl.SetName('target')
-                if not start:
-                    self.ruleslines[enable.GetId()] = { 'value' : '',
-                                                        'color': "0:0:0" }
-            else:
-                # size or width
-                init = 2
-                if self.attributeType == 'size':
-                    init = 100
-                columnCtrl = wx.SpinCtrl(self.mainPanel, id = 2000 + num,
-                                         size = (50, -1), min = 1, max = 1e4,
-                                         initial = init)
-                columnCtrl.Bind(wx.EVT_SPINCTRL, self.OnRuleSize)
-                columnCtrl.Bind(wx.EVT_TEXT, self.OnRuleSize)
-                columnCtrl.SetName('target')
-                if not start:
-                    self.ruleslines[enable.GetId()] = { 'value' : '',
-                                                        self.attributeType: init }
-        
-            self.mainSizer.Add(item = enable, proportion = 0,
-                              flag = wx.ALIGN_CENTER_VERTICAL)
-            self.mainSizer.Add(item = txt_ctrl, proportion = 0,
-                              flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
-            self.mainSizer.Add(item = columnCtrl, proportion = 0,
-                              flag = wx.ALIGN_CENTER | wx.RIGHT, border = 10)
-        
-        self.mainPanel.Layout()
-        self.mainPanel.SetupScrolling(scroll_x = False)
-    
-    def OnRuleEnable(self, event):
-        """!Rule enabled/disabled"""
-        id = event.GetId()
-        
-        if event.IsChecked():
-            self.mainPanel.FindWindowById(id + 1000).Enable()
-            self.mainPanel.FindWindowById(id + 2000).Enable()
-            if self.mapType == 'vector' and not self.parent.GetParent().colorTable:
-                vals = []
-                vals.append(self.mainPanel.FindWindowById(id + 1000).GetValue())
-                try:
-                    vals.append(self.mainPanel.FindWindowById(id + 1 + 1000).GetValue())
-                except AttributeError:
-                    vals.append(None)
-                value = self.SQLConvert(vals)
-            else:
-                value = self.mainPanel.FindWindowById(id + 1000).GetValue()
-            color = self.mainPanel.FindWindowById(id + 2000).GetValue()
-            
-            if self.attributeType == 'color':
-            # color
-                color_str = str(color[0]) + ':' \
-                          + str(color[1]) + ':' \
-                          + str(color[2])
-                self.ruleslines[id] = {'value' : value,
-                                       'color' : color_str }
-                
-            else:
-            # size or width
-                self.ruleslines[id] = {'value' : value,
-                                       self.attributeType  : float(color) }
-        
-        else:
-            self.mainPanel.FindWindowById(id + 1000).Disable()
-            self.mainPanel.FindWindowById(id + 2000).Disable()
-            del self.ruleslines[id]
-        
-    def OnRuleColor(self, event):
-        """!Rule color changed"""
-        num = event.GetId()
-        
-        rgba_color = event.GetValue()
-        
-        rgb_string = str(rgba_color[0]) + ':' \
-                   + str(rgba_color[1]) + ':' \
-                   + str(rgba_color[2])
-        
-        self.ruleslines[num-2000]['color'] = rgb_string
-     
-    def OnRuleSize(self, event):
-        """!Rule size changed"""
-        num = event.GetId()
-        size = event.GetInt()
-        
-        self.ruleslines[num - 2000][self.attributeType] = size
-        
-    def OnRuleValue(self, event):
-        """!Rule value changed"""
-        num = event.GetId()
-        val = event.GetString().strip()
-        
-        if val == '':
-            return
-        try:
-            table = self.parent.colorTable
-        except AttributeError:
-            # due to scrollpanel in vector dialog
-            table = self.parent.GetParent().colorTable
-        if table:
-            self.SetRasterRule(num, val)
-        else:
-            self.SetVectorRule(num, val)
-
-    def SetRasterRule(self, num, val): 
-        """!Set raster rule"""       
-        self.ruleslines[num - 1000]['value'] = val
-
-    def SetVectorRule(self, num, val):
-        """!Set vector rule"""
-        vals = []
-        vals.append(val)
-        try:
-            vals.append(self.mainPanel.FindWindowById(num + 1).GetValue())
-        except AttributeError:
-            vals.append(None)
-        self.ruleslines[num - 1000]['value'] = self.SQLConvert(vals)
-            
-    def Enable(self, enable = True):
-        """!Enable/Disable all widgets"""
-        for child in self.mainPanel.GetChildren():
-            child.Enable(enable)
-        sql = True
-        self.LoadRulesline(sql)# todo
-        self.btnAdd.Enable(enable)
-        self.numRules.Enable(enable)
-        self.checkAll.Enable(enable)
-        self.clearAll.Enable(enable)
-        
-        
-    def LoadRules(self):
-        message = ""        
-        for item in range(len(self.ruleslines)):
-            try:
-                self.mainPanel.FindWindowById(item + 1000).SetValue(self.ruleslines[item]['value'])
-                r, g, b = (0, 0, 0) # default
-                if not self.ruleslines[item][self.attributeType]:
-                    if self.attributeType == 'color':
-                        self.ruleslines[item][self.attributeType] = '%d:%d:%d' % (r, g, b)
-                    elif self.attributeType == 'size':
-                        self.ruleslines[item][self.attributeType] = 100                
-                    elif self.attributeType == 'width':
-                        self.ruleslines[item][self.attributeType] = 2
-                    
-                if self.attributeType == 'color':
-                    try:
-                        r, g, b = map(int, self.ruleslines[item][self.attributeType].split(':'))
-                    except ValueError, e:
-                        message =  _("Bad color format. Use color format '0:0:0'")
-                    self.mainPanel.FindWindowById(item + 2000).SetValue((r, g, b))
-                else:
-                    value = float(self.ruleslines[item][self.attributeType])
-                    self.mainPanel.FindWindowById(item + 2000).SetValue(value)
-            except:
-                continue
-                
-        if message:
-            gcmd.GMessage(parent = self.parent, message = message)
-            return False
-        
-        return True
-                
-    def SQLConvert(self, vals):
-        """!Prepare value for SQL query"""
-        if vals[0].isdigit():
-            sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
-            if vals[1]:
-                sqlrule += ' AND %s<%s' % (self.properties['sourceColumn'], vals[1])
-        else:
-            sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
-        
-        return sqlrule  
-
-class ColorTable(wx.Frame):
-    def __init__(self, parent, title, id = wx.ID_ANY,
-                 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
-                 **kwargs):
-        """!Dialog for interactively entering rules for map management
-        commands
-
-        @param raster True to raster otherwise vector
-        @param nviz True if ColorTable is called from nviz thematic mapping
-        """
-        self.parent = parent # GMFrame
-        wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
-        
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        # instance of render.Map to be associated with display
-        self.Map  = render.Map() 
-        
-        # input map to change
-        self.inmap = ''
-        # reference to layer with preview
-        self.layer = None     
-        # layout
-        self._doLayout()
-        
-        # bindings
-        self.Bind(wx.EVT_BUTTON, self.OnHelp, self.btnHelp)
-        self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
-        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
-        self.Bind(wx.EVT_BUTTON, self.OnApply, self.btnApply)
-        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
-        self.Bind(wx.EVT_CLOSE,  self.OnCloseWindow)
-       
-        self.Bind(wx.EVT_BUTTON, self.OnPreview, self.btnPreview)
-        
-    def _initLayer(self):
-        """!Set initial layer when opening dialog"""
-        # set map layer from layer tree, first selected,
-        # if not the right type, than select another
-        try:
-            sel = self.parent.curr_page.maptree.layer_selected
-            if sel and self.parent.curr_page.maptree.GetPyData(sel)[0]['type'] == self.mapType:
-                layer = sel
-            else:
-                layer = self.parent.curr_page.maptree.FindItemByData(key = 'type', value = self.mapType)
-        except:
-            layer = None
-        if layer:
-            mapLayer = self.parent.curr_page.maptree.GetPyData(layer)[0]['maplayer']
-            name = mapLayer.GetName()
-            type = mapLayer.GetType()
-            self.selectionInput.SetValue(name)
-            self.inmap = name
-    
-    def _createMapSelection(self, parent):
-        """!Create map selection part of dialog"""
-        # top controls
-        if self.mapType == 'raster':
-            maplabel = _('Select raster map:')
-        else:
-            maplabel = _('Select vector map:')
-        inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
-                                label = " %s " % maplabel)
-        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
-
-        self.selectionInput = gselect.Select(parent, id = wx.ID_ANY,
-                                             size = globalvar.DIALOG_GSELECT_SIZE,
-                                             type = self.mapType)
-        # layout
-        inputSizer.Add(item = self.selectionInput,
-                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
-        return inputSizer
-    
-    def _createFileSelection(self, parent):
-        """!Create file (open/save rules) selection part of dialog"""
-        inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
-                                label = " %s " % _("Import or export color table:"))
-        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
-        
-        self.loadRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
-                                                     size = globalvar.DIALOG_GSELECT_SIZE,
-                                                     labelText = _('Load color table from file:'),
-                                                     dialogTitle = _('Choose file to load color table'),
-                                                     buttonText = _('Load'),
-                                                     toolTip = _("Type filename or click to choose "
-                                                                 "file and load color table"),
-                                                     startDirectory = os.getcwd(), fileMode = wx.OPEN,
-                                                     changeCallback = self.OnLoadRulesFile)
-        self.saveRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
-                                                     size = globalvar.DIALOG_GSELECT_SIZE,
-                                                     labelText = _('Save color table to file:'),
-                                                     dialogTitle = _('Choose file to save color table'),
-                                                     toolTip = _("Type filename or click to choose "
-                                                                 "file and save color table"),
-                                                     buttonText = _('Save'),
-                                                     startDirectory = os.getcwd(), fileMode = wx.SAVE,
-                                                     changeCallback = self.OnSaveRulesFile)
-        
-        default = wx.Button(parent = parent, id = wx.ID_ANY, label = _("Reload default table"))   
-        # layout
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(item = self.loadRules, proportion = 1,
-                  flag = wx.RIGHT | wx.EXPAND, border = 10)
-        sizer.Add(item = default, flag = wx.ALIGN_CENTER_VERTICAL)
-        inputSizer.Add(item = sizer,
-                       flag = wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(item = self.saveRules, proportion = 1,
-                  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
-        inputSizer.Add(item = sizer, proportion = 1,
-                       flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        default.Bind(wx.EVT_BUTTON, self.OnLoadDefaultTable)
-        
-        if self.mapType == 'vector':
-            # parent is collapsible pane
-            parent.SetSizer(inputSizer)
-        
-        return inputSizer   
-         
-    def _createPreview(self, parent):
-        """!Create preview"""
-        # initialize preview display
-        self.InitDisplay()
-        self.preview = BufferedWindow(parent, id = wx.ID_ANY, size = (400, 300),
-                                      Map = self.Map)
-        self.preview.EraseMap()
-        
-    def _createButtons(self):
-        """!Create buttons for leaving dialog"""
-        self.btnHelp = wx.Button(parent = self, id = wx.ID_HELP)
-        self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
-        self.btnApply = wx.Button(parent = self, id = wx.ID_APPLY) 
-        self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
-        
-        self.btnOK.SetDefault()
-        self.btnOK.Enable(False)
-        self.btnApply.Enable(False)
-        
-        # layout
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(wx.Size(-1, -1), proportion = 1)
-        btnSizer.Add(self.btnHelp,
-                     flag = wx.LEFT | wx.RIGHT, border = 5)
-        btnSizer.Add(self.btnCancel,
-                     flag = wx.LEFT | wx.RIGHT, border = 5)
-        btnSizer.Add(self.btnApply,
-                     flag = wx.LEFT | wx.RIGHT, border = 5)
-        btnSizer.Add(self.btnOK,
-                     flag = wx.LEFT | wx.RIGHT, border = 5)
-        
-        return btnSizer
-    
-    def _createBody(self, parent):
-        """!Create dialog body consisting of rules and preview"""
-        bodySizer =  wx.GridBagSizer(hgap = 5, vgap = 5)
-        bodySizer.AddGrowableRow(1)
-        bodySizer.AddGrowableCol(2)
-
-        row = 0
-        # label with range
-        self.cr_label = wx.StaticText(parent, id = wx.ID_ANY)
-        bodySizer.Add(item = self.cr_label, pos = (row, 0), span = (1, 3),
-                      flag = wx.ALL, border = 5)
-
-        row += 1
-        # color table
-        self.rulesPanel = RulesPanel(parent = parent, mapType = self.mapType,
-                                     attributeType = self.attributeType, properties = self.properties)
-        
-        bodySizer.Add(item = self.rulesPanel.mainPanel, pos = (row, 0),
-                      span = (1, 2), flag = wx.EXPAND)
-        # add two rules as default
-        self.rulesPanel.AddRules(2)
-        
-        # preview window
-        self._createPreview(parent = parent)
-        bodySizer.Add(item = self.preview, pos = (row, 2), flag = wx.EXPAND)
-        
-        row += 1
-        # add ckeck all and clear all
-        bodySizer.Add(item = self.rulesPanel.checkAll, flag = wx.ALIGN_CENTER_VERTICAL, 
-                      pos = (row, 0))
-        bodySizer.Add(item = self.rulesPanel.clearAll, pos = (row, 1))
-        
-        # preview button
-        self.btnPreview = wx.Button(parent, id = wx.ID_ANY,
-                                    label = _("Preview"))
-        bodySizer.Add(item = self.btnPreview, pos = (row, 2),
-                      flag = wx.ALIGN_RIGHT)
-        self.btnPreview.Enable(False)
-        self.btnPreview.SetToolTipString(_("Show preview of map "
-                                           "(current Map Display extent is used)."))
-        
-        row +=1
-        # add rules button and spin to sizer
-        bodySizer.Add(item = self.rulesPanel.numRules, pos = (row, 0),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        bodySizer.Add(item = self.rulesPanel.btnAdd, pos = (row, 1))
-        
-        return bodySizer    
-        
-    def InitDisplay(self):
-        """!Initialize preview display, set dimensions and region
-        """
-        self.width = self.Map.width = 400
-        self.height = self.Map.height = 300
-        self.Map.geom = self.width, self.height
-
-    def OnCloseWindow(self, event):
-        """!Window closed
-        """
-        self.OnCancel(event)
-          
-    def OnApply(self, event):
-        """!Apply selected color table
-        
-        @return True on success otherwise False
-        """
-        ret = self.CreateColorTable()
-        if not ret:
-            gcmd.GMessage(parent = self, message = _("No valid color rules given."))
-        
-        if ret:
-            display = self.parent.GetLayerTree().GetMapDisplay()
-            if display and display.IsAutoRendered():
-                display.GetWindow().UpdateMap(render = True)
-        
-        return ret
-
-    def OnOK(self, event):
-        """!Apply selected color table and close the dialog"""
-        if self.OnApply(event):
-            self.OnCancel(event)
-    
-    def OnCancel(self, event):
-        """!Do not apply any changes, remove associated
-            rendered images and close the dialog"""
-        self.Map.Clean()
-        self.Destroy()
-        
-    def OnSaveRulesFile(self, event):
-        """!Save color table to file"""
-        path = event.GetString()
-        if not os.path.exists(path):
-            return
-        
-        rulestxt = ''   
-        for rule in self.rulesPanel.ruleslines.itervalues():
-            if 'value' not in rule:
-                continue
-            rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
-        if not rulestxt:
-            gcmd.GMessage(message = _("Nothing to save."),
-                          parent = self)
-            return
-        
-        fd = open(path, 'w')
-        fd.write(rulestxt)
-        fd.close()            
-         
-    def OnLoadRulesFile(self, event):
-        """!Load color table from file"""
-        path = event.GetString()
-        if not os.path.exists(path):
-            return
-        
-        self.rulesPanel.Clear()
-        
-        file = open(path, 'r')
-        ctable = file.read()
-        self.ReadColorTable(ctable = ctable)
-        
-    def ReadColorTable(self, ctable):
-        """!Read color table
-        
-        @param table color table in format coming from r.colors.out"""
-        
-        rulesNumber = len(ctable.splitlines())
-        self.rulesPanel.AddRules(rulesNumber)
-        
-        minim = maxim = count = 0
-        for line in ctable.splitlines():
-            try:
-                value, color = map(lambda x: x.strip(), line.split(' '))
-            except ValueError:
-                gcmd.GMessage(parent = self, message = _("Invalid color table format"))
-                self.rulesPanel.Clear()
-                return
-            
-            self.rulesPanel.ruleslines[count]['value'] = value
-            self.rulesPanel.ruleslines[count]['color'] = color
-            self.rulesPanel.mainPanel.FindWindowById(count + 1000).SetValue(value)
-            rgb = list()
-            for c in color.split(':'):
-                rgb.append(int(c))
-            self.rulesPanel.mainPanel.FindWindowById(count + 2000).SetColour(rgb)
-            # range
-            try:
-                if float(value) < minim:
-                    minim = float(value)
-                if float(value) > maxim:
-                    maxim = float(value)
-            except ValueError: # nv, default
-                pass
-            count += 1
-        
-        if self.mapType == 'vector':
-            # raster min, max is known from r.info
-            self.properties['min'], self.properties['max'] = minim, maxim
-            self.SetRangeLabel()
-            
-        self.OnPreview(tmp = True)  
-         
-    def OnLoadDefaultTable(self, event):
-        """!Load internal color table"""
-        self.LoadTable()
-        
-    def LoadTable(self, mapType = 'raster'):
-        """!Load current color table (using `r(v).colors.out`)
-        
-        @param mapType map type (raster or vector)"""
-        self.rulesPanel.Clear()
-
-        if mapType == 'raster':
-            cmd = ['r.colors.out',
-                   'read=True',
-                   'map=%s' % self.inmap,
-                   'rules=-']
-        else:
-            cmd = ['v.colors.out',
-                   'read=True',
-                   'map=%s' % self.inmap,
-                   'rules=-']
-            
-            if self.properties['sourceColumn'] and self.properties['sourceColumn'] != 'cat':
-                cmd.append('column=%s' % self.properties['sourceColumn'])
-            
-        cmd = utils.CmdToTuple(cmd)
-        
-        if self.inmap:
-            ctable = gcmd.RunCommand(cmd[0], **cmd[1])
-        else:
-            self.OnPreview()
-            return
-        
-        self.ReadColorTable(ctable = ctable)     
-    
-    def CreateColorTable(self, tmp = False):
-        """!Creates color table
-
-        @return True on success
-        @return False on failure
-        """
-        rulestxt = ''
-        
-        for rule in self.rulesPanel.ruleslines.itervalues():
-            if 'value' not in rule: # skip empty rules
-                continue
-            
-            if rule['value'] not in ('nv', 'default') and \
-                    rule['value'][-1] != '%' and \
-                    not self._IsNumber(rule['value']):
-                gcmd.GError(_("Invalid rule value '%s'. Unable to apply color table.") % rule['value'],
-                            parent = self)
-                return False
-            
-            rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
-           
-        if not rulestxt:
-            return False
-        
-        gtemp = utils.GetTempfile()
-        output = open(gtemp, "w")
-        try:
-            output.write(rulestxt)
-        finally:
-            output.close()
-                
-        cmd = ['%s.colors' % self.mapType[0],#r.colors/v.colors
-                'map=%s' % self.inmap,
-                'rules=%s' % gtemp]
-        if self.mapType == 'vector' and self.properties['sourceColumn']\
-                                    and self.properties['sourceColumn'] != 'cat':
-            cmd.append('column=%s' % self.properties['sourceColumn'])
-        cmd = utils.CmdToTuple(cmd)
-        ret = gcmd.RunCommand(cmd[0], **cmd[1])               
-        if ret != 0:
-            return False
-        
-        return True
-    
-    def DoPreview(self, ltype, cmdlist):
-        """!Update preview (based on computational region)"""
-        
-        if not self.layer:
-            self.layer = self.Map.AddLayer(type = ltype, name = 'preview', command = cmdlist,
-                                           l_active = True, l_hidden = False, l_opacity = 1.0,
-                                           l_render = False) 
-        else:
-            self.layer.SetCmd(cmdlist)
-        
-        # apply new color table and display preview
-        self.CreateColorTable(tmp = True)
-        self.preview.UpdatePreview()
-        
-    def RunHelp(self, cmd):
-        """!Show GRASS manual page"""
-        gcmd.RunCommand('g.manual',
-                        quiet = True,
-                        parent = self,
-                        entry = cmd)
-        
-    def _IsNumber(self, s):
-        """!Check if 's' is a number"""
-        try:
-            float(s)
-            return True
-        except ValueError:
-            return False
-        
-
-class RasterColorTable(ColorTable):
-    def __init__(self, parent, **kwargs):
-        """!Dialog for interactively entering color rules for raster maps"""
-
-        self.mapType = 'raster'
-        self.attributeType = 'color' 
-        self.colorTable = True 
-        # raster properties
-        self.properties = {
-            # min cat in raster map
-            'min' : None,
-            # max cat in raster map
-            'max' : None,
-            }        
-        
-        ColorTable.__init__(self, parent,
-                            title = _('Create new color table for raster map'), **kwargs)
-        
-        self._initLayer()
-        
-        self.SetMinSize(self.GetSize()) 
-        self.CentreOnScreen()
-        self.Show()
-    
-    def _doLayout(self):
-        """!Do main layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        #
-        # map selection
-        #
-        mapSelection = self._createMapSelection(parent = self)
-        sizer.Add(item = mapSelection, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # manage extern tables
-        #
-        fileSelection = self._createFileSelection(parent = self)
-        sizer.Add(item = fileSelection, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # body & preview
-        #
-        bodySizer = self._createBody(parent = self)
-        sizer.Add(item = bodySizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # buttons
-        #
-        btnSizer = self._createButtons()
-        sizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                                       style = wx.LI_HORIZONTAL), proportion = 0,
-                                       flag = wx.EXPAND | wx.ALL, border = 5) 
-        
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
-        
-        self.SetSizer(sizer)
-        sizer.Layout()
-        sizer.Fit(self)
-        self.Layout()
-    
-    def OnSelectionInput(self, event):
-        """!Raster map selected"""
-        if event:
-            self.inmap = event.GetString()
-    
-        self.loadRules.SetValue('')
-        self.saveRules.SetValue('')
-        if self.inmap:
-            if not grass.find_file(name = self.inmap, element = 'cell')['file']:
-                self.inmap = None
-        
-        if not self.inmap:
-            self.btnPreview.Enable(False)
-            self.btnOK.Enable(False)
-            self.btnApply.Enable(False)
-            self.LoadTable()
-            return
-        
-        info = grass.raster_info(map = self.inmap)
-        
-        if info:
-            self.properties['min'] = info['min']
-            self.properties['max'] = info['max']
-            self.LoadTable()
-        else:
-            self.inmap = ''
-            self.properties['min'] = self.properties['max'] = None
-            self.btnPreview.Enable(False)
-            self.btnOK.Enable(False)
-            self.btnApply.Enable(False)
-            self.preview.EraseMap()
-            self.cr_label.SetLabel(_('Enter raster category values or percents'))
-            return
-        
-        if info['datatype'] == 'CELL':
-            mapRange = _('range')
-        else:
-            mapRange = _('fp range')
-        self.cr_label.SetLabel(_('Enter raster category values or percents (%(range)s = %(min)d-%(max)d)') %
-                                 { 'range' : mapRange,
-                                   'min' : self.properties['min'],
-                                   'max' : self.properties['max'] })                       
-            
-        self.btnPreview.Enable()
-        self.btnOK.Enable()
-        self.btnApply.Enable()
-            
-          
-    def OnPreview(self, tmp = True):
-        """!Update preview (based on computational region)"""
-        if not self.inmap:
-            self.preview.EraseMap()
-            return
-        
-        cmdlist = ['d.rast',
-                   'map=%s' % self.inmap]
-        ltype = 'raster'
-        
-        # find existing color table and copy to temp file
-        try:
-            name, mapset = self.inmap.split('@')
-        except ValueError:
-            name = self.inmap
-            mapset = grass.find_file(self.inmap, element = 'cell')['mapset']
-            if not mapset:
-                return
-        old_colrtable = None
-        if mapset == grass.gisenv()['MAPSET']:
-            old_colrtable = grass.find_file(name = name, element = 'colr')['file']
-        else:
-            old_colrtable = grass.find_file(name = name, element = 'colr2/' + mapset)['file']
-        
-        if old_colrtable:
-            colrtemp = utils.GetTempfile()
-            shutil.copyfile(old_colrtable, colrtemp)
-            
-        ColorTable.DoPreview(self, ltype, cmdlist)  
-        
-        # restore previous color table
-        if tmp:
-            if old_colrtable:
-                shutil.copyfile(colrtemp, old_colrtable)
-                os.remove(colrtemp)
-            else:
-                gcmd.RunCommand('r.colors',
-                                parent = self,
-                                flags = 'r',
-                                map = self.inmap)
-        
-    def OnHelp(self, event):
-        """!Show GRASS manual page"""
-        cmd = 'r.colors'
-        ColorTable.RunHelp(self, cmd = cmd)
-    
-
-                      
-class VectorColorTable(ColorTable):
-    def __init__(self, parent, attributeType, **kwargs):
-        """!Dialog for interactively entering color rules for vector maps"""
-        # dialog attributes
-        self.mapType = 'vector'
-        self.attributeType = attributeType # color, size, width
-        # in version 7 v.colors used, otherwise color column only
-        self.version7 = int(grass.version()['version'].split('.')[0]) >= 7
-        self.colorTable = False
-        self.updateColumn = True
-        # vector properties
-        self.properties = {
-            # vector layer for attribute table to use for setting color
-            'layer' : 1, 
-            # vector attribute table used for setting color         
-            'table' : '',
-            # vector attribute column for assigning colors
-            'sourceColumn' : '', 
-            # vector attribute column to use for loading colors
-            'loadColumn' : '',
-            # vector attribute column to use for storing colors
-            'storeColumn' : '',    
-            # vector attribute column for temporary storing colors   
-            'tmpColumn' : 'tmp_0',
-            # min value of attribute column/vector color table
-            'min': None,
-            # max value of attribute column/vector color table            
-            'max': None
-            }     
-        self.columnsProp = {'color': {'name': 'GRASSRGB', 'type1': 'varchar(11)', 'type2': ['character']},
-                            'size' : {'name': 'GRASSSIZE', 'type1': 'integer', 'type2': ['integer']},
-                            'width': {'name': 'GRASSWIDTH', 'type1': 'integer', 'type2': ['integer']}}
-        ColorTable.__init__(self, parent = parent,
-                            title = _('Create new color rules for vector map'), **kwargs)
-        
-        # additional bindings for vector color management
-        self.Bind(wx.EVT_COMBOBOX, self.OnLayerSelection, self.layerSelect)
-        self.Bind(wx.EVT_COMBOBOX, self.OnSourceColumnSelection, self.sourceColumn)
-        self.Bind(wx.EVT_COMBOBOX, self.OnFromColSelection, self.fromColumn)
-        self.Bind(wx.EVT_COMBOBOX, self.OnToColSelection, self.toColumn)
-        self.Bind(wx.EVT_BUTTON, self.OnAddColumn, self.addColumn)
-        
-        self._initLayer()
-        if self.colorTable:
-            self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
-        else:
-            self.cr_label.SetLabel(_("Enter vector attribute values:"))
-        self.SetMinSize(self.GetSize()) 
-        self.CentreOnScreen()
-
-        self.SetSize((-1, 760))
-        self.Show()
-    
-    def _createVectorAttrb(self, parent):
-        """!Create part of dialog with layer/column selection"""
-        inputBox = wx.StaticBox(parent = parent, id = wx.ID_ANY,
-                                label = " %s " % _("Select vector columns"))
-        cb_vl_label = wx.StaticText(parent, id = wx.ID_ANY,
-                                             label = _('Layer:'))
-        cb_vc_label = wx.StaticText(parent, id = wx.ID_ANY,
-                                         label = _('Attribute column:'))
-                                        
-        if self.attributeType == 'color':
-            labels =  [_("Load color from column:"), _("Save color to column:")]
-        elif self.attributeType == 'size':
-            labels =  [_("Load size from column:"), _("Save size to column:")]
-        elif self.attributeType == 'width':
-            labels =  [_("Load width from column:"), _("Save width to column:")]
-            
-        if self.version7 and self.attributeType == 'color':
-            self.useColumn = wx.CheckBox(parent, id = wx.ID_ANY,
-                                  label = _("Use color column instead of color table:"))
-            self.useColumn.Bind(wx.EVT_CHECKBOX, self.OnCheckColumn)
-        
-        fromColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
-                                            label = labels[0])
-        toColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
-                                            label = labels[1])
-                                                
-        self.rgb_range_label = wx.StaticText(parent, id = wx.ID_ANY)
-        self.layerSelect = gselect.LayerSelect(parent)
-        self.sourceColumn = gselect.ColumnSelect(parent)
-        self.fromColumn = gselect.ColumnSelect(parent)
-        self.toColumn = gselect.ColumnSelect(parent)
-        self.addColumn = wx.Button(parent, id = wx.ID_ANY,
-                                             label = _('Add column'))
-        self.addColumn.SetToolTipString(_("Add GRASSRGB column to current attribute table."))
-        
-        # layout
-        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
-        vSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        row = 0
-        vSizer.Add(cb_vl_label, pos = (row, 0),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.layerSelect,  pos = (row, 1),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1
-        vSizer.Add(cb_vc_label, pos = (row, 0),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.sourceColumn, pos = (row, 1),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.rgb_range_label, pos = (row, 2),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1   
-        if self.version7 and self.attributeType == 'color':
-            vSizer.Add(self.useColumn, pos = (row, 0), span = (1, 2),
-                       flag = wx.ALIGN_CENTER_VERTICAL)
-            row += 1
-            
-        vSizer.Add(fromColumnLabel, pos = (row, 0),
-                  flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.fromColumn, pos = (row, 1),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1
-        vSizer.Add(toColumnLabel, pos = (row, 0),
-                  flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.toColumn, pos = (row, 1),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        vSizer.Add(self.addColumn, pos = (row, 2),
-                   flag = wx.ALIGN_CENTER_VERTICAL)
-        inputSizer.Add(item = vSizer,
-                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
-        self.colorColumnSizer = vSizer        
-        return inputSizer 
-       
-    def _doLayout(self):
-        """!Do main layout"""
-        scrollPanel = scrolled.ScrolledPanel(self, id = wx.ID_ANY, size = (650, 500),
-                                             style = wx.TAB_TRAVERSAL)
-        scrollPanel.SetupScrolling()
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        #
-        # map selection
-        #
-        mapSelection = self._createMapSelection(parent = scrollPanel)
-        sizer.Add(item = mapSelection, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # manage extern tables
-        #
-        if self.version7 and self.attributeType == 'color':
-            self.cp = wx.CollapsiblePane(scrollPanel, label = _("Import or export color table"),
-                                         winid = wx.ID_ANY,
-                                        style = wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
-            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, self.cp)
-        
-            self._createFileSelection(parent = self.cp.GetPane())
-            sizer.Add(item = self.cp, proportion = 0,
-                      flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # set vector attributes
-        #
-        vectorAttrb = self._createVectorAttrb(parent = scrollPanel)
-        sizer.Add(item = vectorAttrb, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # body & preview
-        #
-        bodySizer = self._createBody(parent = scrollPanel)
-        sizer.Add(item = bodySizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        scrollPanel.SetSizer(sizer)
-        scrollPanel.Fit()        
-        
-        #
-        # buttons
-        #
-        btnSizer = self._createButtons()
-        
-        mainsizer = wx.BoxSizer(wx.VERTICAL)
-        mainsizer.Add(scrollPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
-        mainsizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                                       style = wx.LI_HORIZONTAL), proportion = 0,
-                                       flag = wx.EXPAND | wx.ALL, border = 5) 
-        mainsizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
-        
-        self.SetSizer(mainsizer)
-        mainsizer.Layout()
-        mainsizer.Fit(self)     
-          
-    def OnPaneChanged(self, event = None):
-        # redo the layout
-        self.Layout()
-        # and also change the labels
-        if self.cp.IsExpanded():
-            self.cp.SetLabel('')
-        else:
-            self.cp.SetLabel(_("Import or export color table"))
-        
-    def CheckMapset(self):
-        """!Check if current vector is in current mapset"""
-        if grass.find_file(name = self.inmap,
-                           element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
-            return True
-        else:
-            return False 
-         
-    def NoConnection(self, vectorName):
-        dlg = wx.MessageDialog(parent = self,
-                                message = _("Database connection for vector map <%s> "
-                                            "is not defined in DB file.  Do you want to create and "
-                                            "connect new attribute table?") % vectorName,
-                                caption = _("No database connection defined"),
-                                style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
-        if dlg.ShowModal() == wx.ID_YES:
-            dlg.Destroy()
-            menuform.GUI(parent = self).ParseCommand(['v.db.addtable', 'map=' + self.inmap], 
-                                                      completed = (self.CreateAttrTable, self.inmap, ''))
-        else:
-            dlg.Destroy()
-  
-    def OnCheckColumn(self, event):
-        """!Use color column instead of color table"""
-        if self.useColumn.GetValue():
-            self.properties['loadColumn'] = self.fromColumn.GetStringSelection()
-            self.properties['storeColumn'] = self.toColumn.GetStringSelection()
-            self.fromColumn.Enable(True)
-            self.toColumn.Enable(True)
-            self.colorTable = False
-            
-            if self.properties['loadColumn']:
-                self.LoadTable()
-            else:
-                self.rulesPanel.Clear()
-        else:
-            self.properties['loadColumn'] = ''
-            self.properties['storeColumn'] = ''
-            self.fromColumn.Enable(False)
-            self.toColumn.Enable(False)
-            self.colorTable = True
-            self.LoadTable()
-            
-    def EnableVectorAttributes(self, enable):
-        """!Enable/disable part of dialog connected with db"""
-        for child in self.colorColumnSizer.GetChildren():
-            child.GetWindow().Enable(enable)
-    
-    def DisableClearAll(self):
-        """!Enable, disable the whole dialog"""
-        self.rulesPanel.Clear()
-        self.EnableVectorAttributes(False)
-        self.btnPreview.Enable(False)
-        self.btnOK.Enable(False)
-        self.btnApply.Enable(False)
-        self.preview.EraseMap()
-        
-    def OnSelectionInput(self, event):
-        """!Vector map selected"""
-        if event:
-            if self.inmap:
-                # switch to another map -> delete temporary column
-                self.DeleteTemporaryColumn()
-            self.inmap = event.GetString()
-            
-        if self.version7 and self.attributeType == 'color': 
-            self.loadRules.SetValue('')
-            self.saveRules.SetValue('')
-        
-        if self.inmap:
-            if not grass.find_file(name = self.inmap, element = 'vector')['file']:
-                self.inmap = None
-        
-        self.UpdateDialog()
-       
-    def UpdateDialog(self):
-        """!Update dialog after map selection"""  
-        
-        if not self.inmap:
-            self.DisableClearAll()
-            return
-        
-        if not self.CheckMapset():
-            # v.colors doesn't need the map to be in current mapset
-            if not (self.version7 and self.attributeType == 'color'):
-                message = _("Selected map <%s> is not in current mapset <%s>. "
-                            "Attribute table cannot be edited.") % \
-                            (self.inmap, grass.gisenv()['MAPSET'])
-                wx.CallAfter(gcmd.GMessage, parent = self, message = message)
-                self.DisableClearAll()
-                return
-                
-        # check for db connection
-        self.dbInfo = gselect.VectorDBInfo(self.inmap)
-        enable = True
-        if not len(self.dbInfo.layers): # no connection
-            if not (self.version7 and self.attributeType == 'color'): # otherwise it doesn't matter
-                wx.CallAfter(self.NoConnection, self.inmap)
-                enable = False
-            for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
-                combo.SetValue("")
-                combo.Clear()
-            for prop in ('sourceColumn', 'loadColumn', 'storeColumn'):
-                self.properties[prop] = ''
-            self.EnableVectorAttributes(False)
-        else: # db connection exist
-        # initialize layer selection combobox
-            self.EnableVectorAttributes(True)
-            self.layerSelect.InsertLayers(self.inmap)
-            # initialize attribute table for layer=1
-            self.properties['layer'] = self.layerSelect.GetString(0)
-            self.layerSelect.SetStringSelection(self.properties['layer'])
-            layer = int(self.properties['layer'])
-            self.properties['table'] = self.dbInfo.layers[layer]['table']
-            
-            if self.attributeType == 'color':
-                self.AddTemporaryColumn(type = 'varchar(11)')
-            else:
-                self.AddTemporaryColumn(type = 'integer')
-            
-            # initialize column selection comboboxes 
-            
-            self.OnLayerSelection(event = None)
-
-        if self.version7 and self.attributeType == 'color':
-            self.useColumn.SetValue(False)
-            self.OnCheckColumn(event = None) 
-            self.useColumn.Enable(self.CheckMapset())
-                    
-        self.LoadTable()
-            
-        self.btnPreview.Enable(enable)
-        self.btnOK.Enable(enable)
-        self.btnApply.Enable(enable)   
-    
-    def AddTemporaryColumn(self, type):
-        """!Add temporary column to not overwrite the original values,
-            need to be deleted when closing dialog and unloading map
-            
-            @param type type of column (e.g. vachar(11))"""
-        if not self.CheckMapset():
-            return
-        # because more than one dialog with the same map can be opened we must test column name and
-        # create another one
-        while self.properties['tmpColumn'] in self.dbInfo.GetTableDesc(self.properties['table']).keys():
-            name, idx = self.properties['tmpColumn'].split('_')
-            idx = int(idx)
-            idx += 1
-            self.properties['tmpColumn'] = name + '_' + str(idx)
-        
-        if self.version7:
-            modul = 'v.db.addcolumn'
-        else:
-            modul = 'v.db.addcol'
-        ret = gcmd.RunCommand(modul,
-                              parent = self,
-                              map = self.inmap,
-                              layer = self.properties['layer'],
-                              column = '%s %s' % (self.properties['tmpColumn'], type))
-        
-    def DeleteTemporaryColumn(self):
-        """!Delete temporary column"""
-        if not self.CheckMapset():
-            return
-        
-        if self.inmap:
-            if self.version7:
-                modul = 'v.db.dropcolumn'
-            else:
-                modul = 'v.db.dropcol'
-            ret = gcmd.RunCommand(modul,
-                                  map = self.inmap,
-                                  layer = self.properties['layer'],
-                                  column = self.properties['tmpColumn'])
-        
-    def OnLayerSelection(self, event):
-        # reset choices in column selection comboboxes if layer changes
-        vlayer = int(self.layerSelect.GetStringSelection())
-        self.sourceColumn.InsertColumns(vector = self.inmap, layer = vlayer,
-                                        type = ['integer', 'double precision'], dbInfo = self.dbInfo,
-                                        excludeCols = ['tmpColumn'])
-        self.sourceColumn.SetStringSelection('cat')
-        self.properties['sourceColumn'] = self.sourceColumn.GetString(0)
-        
-        if self.attributeType == 'color':
-            type = ['character']
-        else:
-            type = ['integer']
-        self.fromColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
-                                      dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
-        self.toColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
-                                    dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
-        
-        found = self.fromColumn.FindString(self.columnsProp[self.attributeType]['name'])
-        if found != wx.NOT_FOUND:
-            self.fromColumn.SetSelection(found)
-            self.toColumn.SetSelection(found)
-            self.properties['loadColumn'] = self.fromColumn.GetString(found)
-            self.properties['storeColumn'] = self.toColumn.GetString(found)
-        else:
-            self.properties['loadColumn'] = ''
-            self.properties['storeColumn'] = ''
-        
-        if event:
-            self.LoadTable()
-        self.Update()
-        
-    def OnSourceColumnSelection(self, event):
-        self.properties['sourceColumn'] = event.GetString()
-        
-        self.LoadTable()
-    
-    def OnAddColumn(self, event):
-        """!Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist"""
-        if self.columnsProp[self.attributeType]['name'] not in self.fromColumn.GetItems():
-            if self.version7:
-                modul = 'v.db.addcolumn'
-            else:
-                modul = 'v.db.addcol'
-            ret = gcmd.RunCommand(modul,
-                                  map = self.inmap,
-                                  layer = self.properties['layer'],
-                                  columns = '%s %s' % (self.columnsProp[self.attributeType]['name'],
-                                            self.columnsProp[self.attributeType]['type1']))
-            self.toColumn.InsertColumns(self.inmap, self.properties['layer'],
-                                        type = self.columnsProp[self.attributeType]['type2'])
-            self.toColumn.SetStringSelection(self.columnsProp[self.attributeType]['name'])
-            self.properties['storeColumn'] = self.toColumn.GetStringSelection()
-            
-            self.LoadTable()
-        else:
-            gcmd.GMessage(parent = self,
-                          message = _("%s column already exists.") % \
-                                    self.columnsProp[self.attributeType]['name'])
-                        
-    def CreateAttrTable(self, dcmd, layer, params, propwin):
-        """!Create attribute table"""
-        if dcmd:
-            cmd = utils.CmdToTuple(dcmd)
-            ret = gcmd.RunCommand(cmd[0], **cmd[1])
-            if ret == 0:
-                self.OnSelectionInput(None)
-                return True
-            
-        for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
-            combo.SetValue("")
-            combo.Disable()
-        return False    
-    
-    def LoadTable(self):
-        """!Load table"""
-        if self.colorTable:
-            ColorTable.LoadTable(self, mapType = 'vector')
-        else:
-            self.LoadRulesFromColumn()
-            
-    def LoadRulesFromColumn(self):
-        """!Load current column (GRASSRGB, size column)"""
-        
-        self.rulesPanel.Clear()
-        if not self.properties['sourceColumn']:
-            self.preview.EraseMap()
-            return
-        
-        busy = wx.BusyInfo(message = _("Please wait, loading data from attribute table..."),
-                           parent = self)
-        wx.Yield()
-        
-        columns = self.properties['sourceColumn']
-        if self.properties['loadColumn']:
-            columns += ',' + self.properties['loadColumn']
-            
-        if self.inmap:
-            outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
-            sep = '|'
-            ret = gcmd.RunCommand('v.db.select',
-                                  quiet = True,
-                                  flags = 'c',
-                                  map = self.inmap,
-                                  layer = self.properties['layer'],
-                                  columns = columns,
-                                  fs = sep,
-                                  stdout = outFile)
-        else:
-            self.preview.EraseMap()
-            busy.Destroy()
-            return
-        
-        outFile.seek(0)
-        i = 0
-        minim = maxim = 0.0
-        limit = 1000
-        
-        colvallist = []
-        readvals = False
-        
-        while True:
-            # os.linesep doesn't work here (MSYS)
-            record = outFile.readline().replace('\n', '')
-            if not record:
-                break
-            self.rulesPanel.ruleslines[i] = {}
-            
-            if not self.properties['loadColumn']:
-                col1 = record
-                col2 = None
-            else:
-                col1, col2 = record.split(sep)
-            
-            if float(col1) < minim:
-                minim = float(col1)
-            if float(col1) > maxim:
-                maxim = float(col1)
-
-                
-            # color rules list should only have unique values of col1, not all records
-            if col1 not in colvallist:                
-                self.rulesPanel.ruleslines[i]['value'] = col1
-                self.rulesPanel.ruleslines[i][self.attributeType] = col2
-
-                colvallist.append(col1)            
-                i += 1
-            
-            if i > limit and readvals == False:
-                dlg = wx.MessageDialog (parent = self, message = _(
-                                        "Number of loaded records reached %d, "
-                                        "displaying all the records will be time-consuming "
-                                        "and may lead to computer freezing, "
-                                        "do you still want to continue?") % i,
-                                        caption = _("Too many records"),
-                                        style  =  wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
-                if dlg.ShowModal() == wx.ID_YES:
-                    readvals = True
-                    dlg.Destroy()
-                else:
-                    busy.Destroy()
-                    dlg.Destroy()
-                    self.updateColumn = False
-                    return
-            
-        self.rulesPanel.AddRules(i, start = True)
-        ret = self.rulesPanel.LoadRules()
-        
-        self.properties['min'], self.properties['max'] = minim, maxim
-        self.SetRangeLabel()
-        
-        if ret:
-            self.OnPreview()   
-        else:
-            self.rulesPanel.Clear()
-    
-        busy.Destroy()
-        
-    def SetRangeLabel(self):
-        """!Set labels with info about attribute column range"""
-        
-        if self.properties['sourceColumn']:
-            ctype = self.dbInfo.GetTableDesc(self.properties['table'])[self.properties['sourceColumn']]['ctype']
-        else:
-            ctype = int
-        
-        range = ''
-        if self.properties['min'] or self.properties['max']:
-            if ctype == float:
-                range = _("(range: %.1f to %.1f)") % (self.properties['min'], self.properties['max'])
-            elif ctype == int:
-                range = _("(range: %d to %d)") % (self.properties['min'], self.properties['max'])
-        if range:
-            if self.colorTable:
-                self.cr_label.SetLabel(_("Enter vector attribute values or percents %s:") % range)
-            else:
-                self.cr_label.SetLabel(_("Enter vector attribute values %s:") % range)
-        else:
-            if self.colorTable:
-                self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
-            else:
-                self.cr_label.SetLabel(_("Enter vector attribute values:"))
-                
-    def OnFromColSelection(self, event):
-        """!Selection in combobox (for loading values) changed"""
-        self.properties['loadColumn'] = event.GetString()
-        
-        self.LoadTable()
-    
-    def OnToColSelection(self, event):
-        """!Selection in combobox (for storing values) changed"""
-        self.properties['storeColumn'] = event.GetString()
-    
-    def OnPreview(self, event = None, tmp = True):
-        """!Update preview (based on computational region)"""
-        if self.colorTable:
-            self.OnTablePreview(tmp)
-        else:
-            self.OnColumnPreview() 
-                                 
-    def OnTablePreview(self, tmp):
-        """!Update preview (based on computational region)"""
-        if not self.inmap:
-            self.preview.EraseMap()
-            return
-        
-        ltype = 'vector'
-        cmdlist = ['d.vect',
-                   'map=%s' % self.inmap]
-        
-        # find existing color table and copy to temp file
-        try:
-            name, mapset = self.inmap.split('@')
-        except ValueError:
-            name = self.inmap
-            mapset = grass.find_file(self.inmap, element = 'cell')['mapset']
-            if not mapset:
-                return
-            
-        old_colrtable = None
-        if mapset == grass.gisenv()['MAPSET']:
-            old_colrtable = grass.find_file(name = 'colr', element = os.path.join('vector', name))['file']
-        else:
-            old_colrtable = grass.find_file(name = name, element = os.path.join('vcolr2', mapset))['file']
-            
-        if old_colrtable:
-            colrtemp = utils.GetTempfile()
-            shutil.copyfile(old_colrtable, colrtemp)
-            
-        ColorTable.DoPreview(self, ltype, cmdlist)  
-        
-        # restore previous color table
-        if tmp:
-            if old_colrtable:
-                shutil.copyfile(colrtemp, old_colrtable)
-                os.remove(colrtemp)
-            else:
-                gcmd.RunCommand('v.colors',
-                                parent = self,
-                                flags = 'r',
-                                map = self.inmap)
-    def OnColumnPreview(self):
-        """!Update preview (based on computational region)"""
-        if not self.inmap or not self.properties['tmpColumn']:
-            self.preview.EraseMap()
-            return
-        
-        cmdlist = ['d.vect',
-                   'map=%s' % self.inmap,
-                   'type=point,line,boundary,area']
-                
-        if self.attributeType == 'color':
-            cmdlist.append('flags=a')
-            cmdlist.append('rgb_column=%s' % self.properties['tmpColumn'])
-        elif self.attributeType == 'size':
-            cmdlist.append('size_column=%s' % self.properties['tmpColumn'])
-        elif self.attributeType == 'width':
-            cmdlist.append('width_column=%s' % self.properties['tmpColumn'])
-            
-        ltype = 'vector'
-        
-        ColorTable.DoPreview(self, ltype, cmdlist)
-        
-    def OnHelp(self, event):
-        """!Show GRASS manual page"""
-        cmd = 'v.colors'
-        ColorTable.RunHelp(self, cmd = cmd)
-        
-    def UseAttrColumn(self, useAttrColumn):
-        """!Find layers and apply the changes in d.vect command"""
-        layers = self.parent.curr_page.maptree.FindItemByData(key = 'name', value = self.inmap)
-        if not layers:
-            return
-        for layer in layers:
-            if self.parent.curr_page.maptree.GetPyData(layer)[0]['type'] != 'vector':
-                continue
-            cmdlist = self.parent.curr_page.maptree.GetPyData(layer)[0]['maplayer'].GetCmd()
-            
-            if self.attributeType == 'color':
-                if useAttrColumn:
-                    cmdlist[1].update({'flags': 'a'})
-                    cmdlist[1].update({'rgb_column': self.properties['storeColumn']})
-                else:
-                    if 'flags' in cmdlist[1]:
-                        cmdlist[1]['flags'] = cmdlist[1]['flags'].replace('a', '')
-                    cmdlist[1].pop('rgb_column', None)
-            elif self.attributeType == 'size':
-                cmdlist[1].update({'size_column': self.properties['storeColumn']})
-            elif self.attributeType == 'width':
-                cmdlist[1].update({'width_column' :self.properties['storeColumn']})
-            self.parent.curr_page.maptree.GetPyData(layer)[0]['cmd'] = cmdlist
-        
-    def CreateColorTable(self, tmp = False):
-        """!Create color rules (color table or color column)"""
-        if self.colorTable:
-            ret = ColorTable.CreateColorTable(self)
-        else:
-            if self.updateColumn:
-                ret = self.UpdateColorColumn(tmp)
-            else:
-                ret = True
-        return ret
-        
-    def UpdateColorColumn(self, tmp):
-        """!Creates color table
-
-        @return True on success
-        @return False on failure
-        """
-        rulestxt = ''
-        
-        for rule in self.rulesPanel.ruleslines.itervalues():
-            if 'value' not in rule: # skip empty rules
-                break
-            
-            if tmp:
-                rgb_col = self.properties['tmpColumn']
-            else:
-                rgb_col = self.properties['storeColumn']
-                if not self.properties['storeColumn']:
-                    gcmd.GMessage(self.parent, message = _("Please select column to save values to."))
-                    
-            rulestxt += "UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.properties['table'],
-                                                                rgb_col,
-                                                                rule[self.attributeType],
-                                                                rule['value'])
-        if not rulestxt:
-            return False
-        
-        gtemp = utils.GetTempfile()
-        output = open(gtemp, "w")
-        try:
-            output.write(rulestxt)
-        finally:
-            output.close()
-        
-        gcmd.RunCommand('db.execute',
-                        parent = self,
-                        input = gtemp)
-        return True
-    
-    def OnCancel(self, event):
-        """!Do not apply any changes and close the dialog"""
-        self.DeleteTemporaryColumn()
-        self.Map.Clean()
-        self.Destroy()
-
-    def OnApply(self, event):
-        """!Apply selected color table
-        
-        @return True on success otherwise False
-        """
-        if self.colorTable:
-            self.UseAttrColumn(False)
-        else:
-            self.UseAttrColumn(True)
-        
-        return ColorTable.OnApply(self, event)
-        
-class ThematicVectorTable(VectorColorTable):
-    def __init__(self, parent, vectorType, **kwargs):
-        """!Dialog for interactively entering color/size rules
-            for vector maps for thematic mapping in nviz"""
-        self.vectorType = vectorType
-        VectorColorTable.__init__(self, parent = parent, **kwargs)
-              
-        self.SetTitle(_("Thematic mapping for vector map in 3D view"))       
-                    
-    def _initLayer(self):
-        """!Set initial layer when opening dialog"""
-        self.inmap = self.parent.GetLayerData(nvizType = 'vector', nameOnly = True)
-        self.selectionInput.SetValue(self.inmap)
-        self.selectionInput.Disable()
-        
-    def OnApply(self, event):
-        """!Apply selected color table
-
-        @return True on success otherwise False
-        """
-        ret = self.CreateColorTable()
-        if not ret:
-            gcmd.GMessage(parent = self, message = _("No valid color rules given."))
-        
-        data = self.parent.GetLayerData(nvizType = 'vector')
-        data['vector']['points']['thematic']['layer'] = int(self.properties['layer'])
-        
-        value = None
-        if self.properties['storeColumn']:
-            value = self.properties['storeColumn']
-            
-        if not self.colorTable:
-            if self.attributeType == 'color':
-                data['vector'][self.vectorType]['thematic']['rgbcolumn'] = value
-            else:
-                data['vector'][self.vectorType]['thematic']['sizecolumn'] = value
-        else:
-            if self.attributeType == 'color':
-                data['vector'][self.vectorType]['thematic']['rgbcolumn'] = None
-            else:
-                data['vector'][self.vectorType]['thematic']['sizecolumn'] = None
-        
-        data['vector'][self.vectorType]['thematic']['update'] = None
-        
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.parent.mapWindow, event)
-        self.parent.mapWindow.Refresh(False)
-        
-        return ret
-           
-class BufferedWindow(wx.Window):
-    """!A Buffered window class"""
-    def __init__(self, parent, id,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
-                 Map = None, **kwargs):
-        
-        wx.Window.__init__(self, parent, id, style = style, **kwargs)
-
-        self.parent = parent
-        self.Map = Map
-        
-        # re-render the map from GRASS or just redraw image
-        self.render = True
-        # indicates whether or not a resize event has taken place
-        self.resize = False 
-
-        #
-        # event bindings
-        #
-        self.Bind(wx.EVT_PAINT,        self.OnPaint)
-        self.Bind(wx.EVT_IDLE,         self.OnIdle)
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
-
-        #
-        # render output objects
-        #
-        # image file to be rendered
-        self.mapfile = None 
-        # wx.Image object (self.mapfile)
-        self.img = None
-
-        self.pdc = wx.PseudoDC()
-        # will store an off screen empty bitmap for saving to file
-        self._Buffer = None 
-
-        # make sure that extents are updated at init
-        self.Map.region = self.Map.GetRegion()
-        self.Map.SetRegion()
-
-    def Draw(self, pdc, img = None, pdctype = 'image'):
-        """!Draws preview or clears window"""
-        pdc.BeginDrawing()
-
-        Debug.msg (3, "BufferedWindow.Draw(): pdctype=%s" % (pdctype))
-
-        if pdctype == 'clear': # erase the display
-            bg = wx.WHITE_BRUSH
-            pdc.SetBackground(bg)
-            pdc.Clear()
-            self.Refresh()
-            pdc.EndDrawing()
-            return
-
-        if pdctype == 'image' and img:
-            bg = wx.TRANSPARENT_BRUSH
-            pdc.SetBackground(bg)
-            bitmap = wx.BitmapFromImage(img)
-            w, h = bitmap.GetSize()
-            pdc.DrawBitmap(bitmap, 0, 0, True) # draw the composite map
-            
-        pdc.EndDrawing()
-        self.Refresh()
-
-    def OnPaint(self, event):
-        """!Draw pseudo DC to buffer"""
-        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
-        dc = wx.BufferedPaintDC(self, self._Buffer)
-        
-        # use PrepareDC to set position correctly
-        self.PrepareDC(dc)
-        
-        # we need to clear the dc BEFORE calling PrepareDC
-        bg = wx.Brush(self.GetBackgroundColour())
-        dc.SetBackground(bg)
-        dc.Clear()
-        
-        # create a clipping rect from our position and size
-        # and the Update Region
-        rgn = self.GetUpdateRegion()
-        r = rgn.GetBox()
-        
-        # draw to the dc using the calculated clipping rect
-        self.pdc.DrawToDCClipped(dc, r)
-        
-    def OnSize(self, event):
-        """!Init image size to match window size"""
-        # set size of the input image
-        self.Map.width, self.Map.height = self.GetClientSize()
-
-        # Make new off screen bitmap: this bitmap will always have the
-        # current drawing in it, so it can be used to save the image to
-        # a file, or whatever.
-        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
-
-        # get the image to be rendered
-        self.img = self.GetImage()
-
-        # update map display
-        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
-            self.img = self.img.Scale(self.Map.width, self.Map.height)
-            self.render = False
-            self.UpdatePreview()
-
-        # re-render image on idle
-        self.resize = True
-
-    def OnIdle(self, event):
-        """!Only re-render a preview image from GRASS during
-        idle time instead of multiple times during resizing.
-        """
-        if self.resize:
-            self.render = True
-            self.UpdatePreview()
-        event.Skip()
-
-    def GetImage(self):
-        """!Converts files to wx.Image"""
-        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
-                os.path.getsize(self.Map.mapfile):
-            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
-        else:
-            img = None
-        
-        return img
-    
-    def UpdatePreview(self, img = None):
-        """!Update canvas if window changes geometry"""
-        Debug.msg (2, "BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.render))
-        oldfont = ""
-        oldencoding = ""
-        
-        if self.render:
-            # extent is taken from current map display
-            try:
-                self.Map.region = copy.deepcopy(self.parent.parent.curr_page.maptree.Map.region)
-            except AttributeError:
-                self.Map.region = self.Map.GetRegion()
-            # render new map images
-            self.mapfile = self.Map.Render(force = self.render)
-            self.img = self.GetImage()
-            self.resize = False
-        
-        if not self.img:
-            return
-        
-        # paint images to PseudoDC
-        self.pdc.Clear()
-        self.pdc.RemoveAll()
-        # draw map image background
-        self.Draw(self.pdc, self.img, pdctype = 'image')
-        
-        self.resize = False
-        
-    def EraseMap(self):
-        """!Erase preview"""
-        self.Draw(self.pdc, pdctype = 'clear')
-    

Deleted: grass/trunk/gui/wxpython/gui_modules/dbm.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/dbm.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/dbm.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,3090 +0,0 @@
-"""!
- at package dbm.py
-
- at brief GRASS Attribute Table Manager
-
-This program is based on FileHunter, published in 'The wxPython Linux
-Tutorial' on wxPython WIKI pages.
-
-It also uses some functions at
-http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407
-
- at code
-python dbm.py vector at mapset
- at endcode
-
-List of classes:
- - Log
- - VirtualAttributeList
- - AttributeManager
-
-(C) 2007-2009, 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Jachym Cepicky <jachym.cepicky gmail.com>
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import sys
-import os
-import locale
-import tempfile
-import copy
-import types
-
-import globalvar
-import wx
-import wx.lib.mixins.listctrl as listmix
-import wx.lib.flatnotebook as FN
-
-import grass.script as grass
-
-import sqlbuilder
-import gcmd
-import utils
-import gdialogs
-import dbm_base
-from debug       import Debug
-from dbm_dialogs import ModifyTableRecord
-from preferences import globalSettings as UserSettings
-from menuform    import GNotebook
-class Log:
-    """
-    The log output is redirected to the status bar of the containing frame.
-    """
-    def __init__(self, parent):
-        self.parent = parent
-
-    def write(self, text_string):
-        """!Update status bar"""
-        self.parent.SetStatusText(text_string.strip())
-
-
-class VirtualAttributeList(wx.ListCtrl,
-                           listmix.ListCtrlAutoWidthMixin,
-                           listmix.ColumnSorterMixin):
-    """
-    Support virtual list class
-    """
-    def __init__(self, parent, log, mapDBInfo, layer):
-        #
-        # initialize variables
-        #
-        self.parent  = parent
-        self.log     = log
-        self.mapDBInfo = mapDBInfo
-        self.layer   = layer
-        
-        self.columns = {} # <- LoadData()
-
-        wx.ListCtrl.__init__(self, parent=parent, id=wx.ID_ANY,
-                             style=wx.LC_REPORT | wx.LC_HRULES |
-                             wx.LC_VRULES | wx.LC_VIRTUAL | wx.LC_SORT_ASCENDING)
-        
-        try:
-            keyColumn = self.LoadData(layer)
-        except gcmd.GException, e:
-            GError(parent = self,
-                   message = e.value)
-            return
-        
-        #
-        # add some attributes (colourful background for each item rows)
-        #
-        self.attr1 = wx.ListItemAttr()
-        self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
-        self.attr2 = wx.ListItemAttr()
-        self.attr2.SetBackgroundColour("white")
-        self.il = wx.ImageList(16, 16)
-        self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
-                                                          (16,16)))
-        self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
-                                                          (16,16)))
-        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
-        
-        # setup mixins
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        listmix.ColumnSorterMixin.__init__(self, len(self.columns))
-
-        # sort item by category (id)
-        if keyColumn > -1:
-            self.SortListItems(col=keyColumn, ascending=True) 
-        else:
-            self.SortListItems(col=0, ascending=True) 
-        
-        # events
-        self.Bind(wx.EVT_LIST_ITEM_SELECTED,   self.OnItemSelected)
-        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected)
-        self.Bind(wx.EVT_LIST_COL_CLICK,       self.OnColumnSort)     
-        self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColumnMenu)     
-        
-    def Update(self, mapDBInfo):
-        """!Update list according new mapDBInfo description"""
-        self.mapDBInfo = mapDBInfo
-        self.LoadData(self.layer)
-
-    def LoadData(self, layer, columns=None, where=None, sql=None):
-        """!Load data into list
-
-        @param layer layer number
-        @param columns list of columns for output (-> v.db.select)
-        @param where where statement (-> v.db.select)
-        @param sql full sql statement (-> db.select)
-        
-        @return id of key column 
-        @return -1 if key column is not displayed
-        """
-        self.log.write(_("Loading data..."))
-        
-        tableName    = self.mapDBInfo.layers[layer]['table']
-        keyColumn    = self.mapDBInfo.layers[layer]['key']
-        try:
-            self.columns = self.mapDBInfo.tables[tableName]
-        except KeyError:
-            raise gcmd.GException(_("Attribute table <%s> not found. "
-                                    "For creating the table switch to "
-                                    "'Manage layers' tab.") % tableName)
-        
-        if not columns:
-            columns = self.mapDBInfo.GetColumns(tableName)
-        else:
-            all = self.mapDBInfo.GetColumns(tableName)
-            for col in columns:
-                if col not in all:
-                    wx.MessageBox(parent=self,
-                                  message=_("Column <%(column)s> not found in "
-                                            "in the table <%(table)s>.") % \
-                                      { 'column' : col, 'table' : tableName },
-                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                    return
-        
-        try:
-            # for maps connected via v.external
-            keyId = columns.index(keyColumn)
-        except:
-            keyId = -1
-        
-        #
-        # read data
-        #
-        # FIXME: Max. number of rows, while the GUI is still usable
-
-        # stdout can be very large, do not use PIPE, redirect to temp file
-        # TODO: more effective way should be implemented...
-        outFile = tempfile.NamedTemporaryFile(mode='w+b')
-        
-        if sql:
-            ret = gcmd.RunCommand('db.select',
-                                  quiet = True,
-                                  parent = self,
-                                  flags = 'c',
-                                  sql = sql,
-                                  output = outFile.name)
-        else:
-            if columns:
-                ret = gcmd.RunCommand('v.db.select',
-                                      quiet = True,
-                                      parent = self,
-                                      flags = 'c',
-                                      map = self.mapDBInfo.map,
-                                      layer = layer,
-                                      columns = ','.join(columns),
-                                      where = where,
-                                      stdout = outFile)
-            else:
-                ret = gcmd.RunCommand('v.db.select',
-                                      quiet = True,
-                                      parent = self,
-                                      flags = 'c',
-                                      map = self.mapDBInfo.map,
-                                      layer = layer,
-                                      where = where,
-                                      stdout = outFile) 
-        
-        # These two should probably be passed to init more cleanly
-        # setting the numbers of items = number of elements in the dictionary
-        self.itemDataMap  = {}
-        self.itemIndexMap = []
-        self.itemCatsMap  = {}
-        
-        self.DeleteAllItems()
-        
-        # self.ClearAll()
-        for i in range(self.GetColumnCount()):
-            self.DeleteColumn(0)
-        
-        i = 0
-        info = wx.ListItem()
-        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
-        info.m_image = -1
-        info.m_format = 0
-        for column in columns:
-            info.m_text = column
-            self.InsertColumnInfo(i, info)
-            i += 1
-            
-            if i >= 256:
-                self.log.write(_("Can display only 256 columns."))
-        
-        i = 0
-        outFile.seek(0)
-        
-        while True:
-            # os.linesep doesn't work here (MSYS)
-            record = outFile.readline().replace('\n', '')
-            
-            if not record:
-                break
-           
-            self.AddDataRow(i, record, columns, keyId)
-
-            i += 1
-            if i >= 100000:
-                self.log.write(_("Limit 100000 records."))
-                break
-        
-        self.SetItemCount(i)
-        
-        i = 0
-        for col in columns:
-            width = self.columns[col]['length'] * 6 # FIXME
-            if width < 60:
-                width = 60
-            if width > 300:
-                width = 300
-            self.SetColumnWidth(col=i, width=width)
-            i += 1
-        
-        self.SendSizeEvent()
-        
-        self.log.write(_("Number of loaded records: %d") % \
-                           self.GetItemCount())
-        
-        return keyId
-    
-    def AddDataRow(self, i, record, columns, keyId):
-        """!Add row to the data list"""
-        self.itemDataMap[i] = []
-        keyColumn = self.mapDBInfo.layers[self.layer]['key']
-        j = 0
-        cat = None
-        
-        if keyColumn == 'OGC_FID':
-            self.itemDataMap[i].append(i+1)
-            j += 1
-            cat = i + 1
-        
-        for value in record.split('|'):
-            if self.columns[columns[j]]['ctype'] != types.StringType:
-                try:
-                    ### casting disabled (2009/03)
-                    ### self.itemDataMap[i].append(self.columns[columns[j]]['ctype'](value))
-                    self.itemDataMap[i].append(value)
-                except ValueError:
-                    self.itemDataMap[i].append(_('Unknown value'))
-            else:
-                # encode string values
-                try:
-                    self.itemDataMap[i].append(dbm_base.unicodeValue(value))
-                except UnicodeDecodeError:
-                    self.itemDataMap[i].append(_("Unable to decode value. "
-                                                 "Set encoding in GUI preferences ('Attributes')."))
-                
-            if not cat and keyId > -1 and keyId == j:
-                try:
-                    cat = self.columns[columns[j]]['ctype'] (value)
-                except ValueError, e:
-                    cat = -1
-                    gcmd.GError(parent = self,
-                                message=_("Error loading attribute data. "
-                                          "Record number: %(rec)d. Unable to convert value '%(val)s' in "
-                                          "key column (%(key)s) to integer.\n\n"
-                                          "Details: %(detail)s") % \
-                                    { 'rec' : i + 1, 'val' : value,
-                                      'key' : keyColumn, 'detail' : e})
-            j += 1
-        
-        self.itemIndexMap.append(i)
-        if keyId > -1: # load cats only when LoadData() is called first time
-            self.itemCatsMap[i] = cat
-        
-    def OnItemSelected(self, event):
-        """!Item selected. Add item to selected cats..."""
-        #         cat = int(self.GetItemText(event.m_itemIndex))
-        #         if cat not in self.selectedCats:
-        #             self.selectedCats.append(cat)
-        #             self.selectedCats.sort()
-        
-        event.Skip()
-
-    def OnItemDeselected(self, event):
-        """!Item deselected. Remove item from selected cats..."""
-        #         cat = int(self.GetItemText(event.m_itemIndex))
-        #         if cat in self.selectedCats:
-        #             self.selectedCats.remove(cat)
-        #             self.selectedCats.sort()
-
-        event.Skip()
-
-    def GetSelectedItems(self):
-        """!Return list of selected items (category numbers)"""
-        cats = []
-        item = self.GetFirstSelected()
-        while item != -1:
-            cats.append(self.GetItemText(item))
-            item = self.GetNextSelected(item)
-
-        return cats
-
-    def GetColumnText(self, index, col):
-        """!Return column text"""
-        item = self.GetItem(index, col)
-        return item.GetText()
-
-    def GetListCtrl(self):
-        """!Returt list"""
-        return self
-
-    def OnGetItemText(self, item, col):
-        """!Get item text"""
-        index = self.itemIndexMap[item]
-        s = self.itemDataMap[index][col]
-        return s
-
-    def OnGetItemAttr(self, item):
-        """!Get item attributes"""
-        if ( item % 2) == 0:
-            return self.attr2
-        else:
-            return self.attr1
-
-    def OnColumnMenu(self, event):
-        """!Column heading right mouse button -> pop-up menu"""
-        self._col = event.GetColumn()
-        
-        popupMenu = wx.Menu()
-
-        if not hasattr (self, "popupID1"):
-            self.popupID1 = wx.NewId()
-            self.popupID2 = wx.NewId()
-            self.popupID3 = wx.NewId()
-            self.popupID4 = wx.NewId()
-            self.popupID5 = wx.NewId()
-            self.popupID6 = wx.NewId()
-            self.popupID7 = wx.NewId()
-            self.popupID8 = wx.NewId()
-            self.popupID9 = wx.NewId()
-            self.popupID10 = wx.NewId()
-            self.popupID11 = wx.NewId()
-            self.popupID12 = wx.NewId()
-        
-        popupMenu.Append(self.popupID1, text=_("Sort ascending"))
-        popupMenu.Append(self.popupID2, text=_("Sort descending"))
-        popupMenu.AppendSeparator()
-        subMenu = wx.Menu()
-        popupMenu.AppendMenu(self.popupID3, _("Calculate (only numeric columns)"),
-                             subMenu)
-        if not self.log.parent.editable or \
-                self.columns[self.GetColumn(self._col).GetText()]['ctype'] not in (types.IntType, types.FloatType):
-            popupMenu.Enable(self.popupID3, False)
-        
-        subMenu.Append(self.popupID4,  text=_("Area size"))
-        subMenu.Append(self.popupID5,  text=_("Line length"))
-        subMenu.Append(self.popupID6,  text=_("Compactness of an area"))
-        subMenu.Append(self.popupID7,  text=_("Fractal dimension of boundary defining a polygon"))
-        subMenu.Append(self.popupID8,  text=_("Perimeter length of an area"))
-        subMenu.Append(self.popupID9,  text=_("Number of features for each category"))
-        subMenu.Append(self.popupID10, text=_("Slope steepness of 3D line"))
-        subMenu.Append(self.popupID11, text=_("Line sinuousity"))
-        subMenu.Append(self.popupID12, text=_("Line azimuth"))
-        
-        self.Bind (wx.EVT_MENU, self.OnColumnSortAsc,  id=self.popupID1)
-        self.Bind (wx.EVT_MENU, self.OnColumnSortDesc, id=self.popupID2)
-        for id in (self.popupID4, self.popupID5, self.popupID6,
-                   self.popupID7, self.popupID8, self.popupID9,
-                   self.popupID10, self.popupID11, self.popupID12):
-            self.Bind(wx.EVT_MENU, self.OnColumnCompute, id = id)
-        
-        self.PopupMenu(popupMenu)
-        popupMenu.Destroy()
-
-    def OnColumnSort(self, event):
-        """!Column heading left mouse button -> sorting"""
-        self._col = event.GetColumn()
-        
-        self.ColumnSort()
-        
-        event.Skip()
-
-    def OnColumnSortAsc(self, event):
-        """!Sort values of selected column (ascending)"""
-        self.SortListItems(col = self._col, ascending = True)
-        event.Skip()
-
-    def OnColumnSortDesc(self, event):
-        """!Sort values of selected column (descending)"""
-        self.SortListItems(col = self._col, ascending = False)
-        event.Skip()
-        
-    def OnColumnCompute(self, event):
-        """!Compute values of selected column"""
-        id = event.GetId()
-        
-        option = None
-        if id == self.popupID4:
-            option = 'area'
-        elif id == self.popupID5:
-            option = 'length'
-        elif id == self.popupID6:
-            option = 'compact'
-        elif id == self.popupID7:
-            option = 'fd'
-        elif id == self.popupID8:
-            option = 'perimeter'
-        elif id == self.popupID9:
-            option = 'count'
-        elif id == self.popupID10:
-            option = 'slope'
-        elif id == self.popupID11:
-            option = 'sinuous'
-        elif id == self.popupID12:
-            option = 'azimuth'
-        
-        if not option:
-            return
-        
-        gcmd.RunCommand('v.to.db',
-                        parent = self.parent,
-                        map = self.mapDBInfo.map,
-                        layer = self.layer, 
-                        option = option,
-                        columns = self.GetColumn(self._col).GetText())
-        
-        self.LoadData(self.layer)
-        
-    def ColumnSort(self):
-        """!Sort values of selected column (self._col)"""
-        # remove duplicated arrow symbol from column header
-        # FIXME: should be done automatically
-        info = wx.ListItem()
-        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
-        info.m_image = -1
-        for column in range(self.GetColumnCount()):
-            info.m_text = self.GetColumn(column).GetText()
-            self.SetColumn(column, info)
-        
-    def SortItems(self, sorter=cmp):
-        """!Sort items"""
-        items = list(self.itemDataMap.keys())
-        items.sort(self.Sorter)
-        self.itemIndexMap = items
-
-        # redraw the list
-        self.Refresh()
-        
-    def Sorter(self, key1, key2):
-        colName = self.GetColumn(self._col).GetText()
-        ascending = self._colSortFlag[self._col]
-        try:
-            item1 = self.columns[colName]["ctype"](self.itemDataMap[key1][self._col])
-            item2 = self.columns[colName]["ctype"](self.itemDataMap[key2][self._col])
-        except ValueError:
-            item1 = self.itemDataMap[key1][self._col]
-            item2 = self.itemDataMap[key2][self._col]
-
-        if type(item1) == type('') or type(item2) == type(''):
-            cmpVal = locale.strcoll(str(item1), str(item2))
-        else:
-            cmpVal = cmp(item1, item2)
-
-
-        # If the items are equal then pick something else to make the sort value unique
-        if cmpVal == 0:
-            cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
-        
-        if ascending:
-            return cmpVal
-        else:
-            return -cmpVal
-
-    def GetSortImages(self):
-        """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
-        return (self.sm_dn, self.sm_up)
-
-    def IsEmpty(self):
-        """!Check if list if empty"""
-        if self.columns:
-            return False
-        
-        return True
-    
-class AttributeManager(wx.Frame):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = None, vectorName = None, item = None, log = None,
-                 selection = None, **kwargs):
-        """!GRASS Attribute Table Manager window
-
-        @param parent parent window
-        @parem id window id
-        @param title window title or None for default title
-        @param vetorName name of vector map
-        @param item item from Layer Tree
-        @param log log window
-        @param selection name of page to be selected
-        @param kwagrs other wx.Frame's arguments
-        """
-        self.vectorName = vectorName
-        self.parent     = parent # GMFrame
-        self.treeItem   = item   # item in layer tree
-        if self.parent and self.parent.GetName() == "LayerManager" and \
-                self.treeItem and not self.vectorName:
-            maptree = self.parent.curr_page.maptree
-            name = maptree.GetPyData(self.treeItem)[0]['maplayer'].GetName()
-            self.vectorName = name
-        
-        # vector attributes can be changed only if vector map is in
-        # the current mapset
-        if grass.find_file(name = self.vectorName, element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
-            self.editable = True
-        else:
-            self.editable = False
-        
-        self.cmdLog = log    # self.parent.goutput
-        
-        wx.Frame.__init__(self, parent, id, *kwargs)
-
-        # title
-        if not title:
-            self.SetTitle("%s - <%s>" % (_("GRASS GIS Attribute Table Manager"),
-                                         self.vectorName))
-        else:
-            self.SetTitle(title)
-        
-        # icon
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
-
-        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
-
-        try:
-            self.map        = self.parent.curr_page.maptree.Map
-            self.mapdisplay = self.parent.curr_page.maptree.mapdisplay
-        except:
-            self.map = self.mapdisplay = None
-        
-        # status bar log class
-        self.log = Log(self) # -> statusbar
-
-        # query map layer (if parent (GMFrame) is given)
-        self.qlayer = None
-
-        # -> layers / tables description
-        self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
-
-        # sqlbuilder
-        self.builder = None
-        
-        if len(self.mapDBInfo.layers.keys()) == 0:
-            wx.MessageBox(parent=self.parent,
-                          message=_("Database connection for vector map <%s> "
-                                    "is not defined in DB file. "
-                                    "You can define new connection in "
-                                    "'Manage layers' tab.") % self.vectorName,
-                          caption=_("Attribute Table Manager"),
-                          style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-
-        #
-        # list of command/SQL statements to be performed
-        #
-        self.listOfCommands      = []
-        self.listOfSQLStatements = []
-
-        self.CreateStatusBar(number=1)
-
-        # set up virtual lists (each layer)
-        ### {layer: list, widgets...}
-        self.layerPage = {}
-
-        self.notebook = GNotebook(self.panel, style = globalvar.FNPageDStyle)
-        
-        if globalvar.hasAgw:
-            dbmStyle = { 'agwStyle' : globalvar.FNPageStyle }
-        else:
-            dbmStyle = { 'style' : globalvar.FNPageStyle }
-        
-        self.browsePage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
-                                          **dbmStyle)
-        self.notebook.AddPage(page = self.browsePage, text = _("Browse data"),
-                              name = 'browse')
-        self.browsePage.SetTabAreaColour(globalvar.FNPageColor)
-
-        self.manageTablePage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
-                                               **dbmStyle)
-        self.notebook.AddPage(page = self.manageTablePage, text = _("Manage tables"),
-                              name = 'table')
-        if not self.editable:
-            self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(False)
-        self.manageTablePage.SetTabAreaColour(globalvar.FNPageColor)
-
-        self.manageLayerPage = FN.FlatNotebook(self.panel, id = wx.ID_ANY,
-                                               **dbmStyle)
-        self.notebook.AddPage(page = self.manageLayerPage, text = _("Manage layers"),
-                              name = 'layers')
-        self.manageLayerPage.SetTabAreaColour(globalvar.FNPageColor)
-        if not self.editable:
-            self.notebook.GetPage(self.notebook.GetPageCount()-1).Enable(False)
-        
-        self._createBrowsePage()
-        self._createManageTablePage()
-        self._createManageLayerPage()
-
-        if selection:
-            wx.CallAfter(self.notebook.SetSelectionByName, selection) # select browse tab
-
-        # buttons
-        self.btnQuit   = wx.Button(parent=self.panel, id=wx.ID_EXIT)
-        self.btnQuit.SetToolTipString(_("Close Attribute Table Manager"))
-        self.btnReload = wx.Button(parent=self.panel, id=wx.ID_REFRESH)
-        self.btnReload.SetToolTipString(_("Reload attribute data (selected layer only)"))
-
-        # events
-        self.btnQuit.Bind(wx.EVT_BUTTON,   self.OnCloseWindow)
-        self.btnReload.Bind(wx.EVT_BUTTON, self.OnDataReload)
-        self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
-        self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.browsePage)
-        self.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnLayerPageChanged, self.manageTablePage)
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-
-        # do layout
-        self._layout()
-
-        # self.SetMinSize(self.GetBestSize())
-        self.SetSize((680, 550)) # FIXME hard-coded size
-        self.SetMinSize(self.GetSize())
-
-    def _createBrowsePage(self, onlyLayer=-1):
-        """!Create browse tab page"""
-        for layer in self.mapDBInfo.layers.keys():
-            if onlyLayer > 0 and layer != onlyLayer:
-                continue
-
-            panel = wx.Panel(parent=self.browsePage, id=wx.ID_ANY)
-            
-            #IMPORTANT NOTE: wx.StaticBox MUST be defined BEFORE any of the 
-            #   controls that are placed IN the wx.StaticBox, or it will freeze
-            #   on the Mac
-            
-            listBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
-                       label=" %s " % _("Attribute data - right-click to edit/manage records"))
-            listSizer = wx.StaticBoxSizer(listBox, wx.VERTICAL)
-            
-            win = VirtualAttributeList(panel, self.log,
-                                       self.mapDBInfo, layer)
-            if win.IsEmpty():
-                del panel
-                continue
-            
-            win.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnDataItemActivated)
-
-            self.layerPage[layer] = {'browsePage': panel.GetId()}
-            
-            label = _("Table")
-            if not self.editable:
-                label += _(" (readonly)")
-            self.browsePage.AddPage(page=panel, text=" %d / %s %s" % \
-                                        (layer, label, self.mapDBInfo.layers[layer]['table']))
-
-            pageSizer = wx.BoxSizer(wx.VERTICAL)
-
-            # attribute data            
-            sqlBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
-                                  label=" %s " % _("SQL Query"))
-
-            sqlSizer = wx.StaticBoxSizer(sqlBox, wx.VERTICAL)
-
-            win.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnDataRightUp) #wxMSW
-            win.Bind(wx.EVT_RIGHT_UP,            self.OnDataRightUp) #wxGTK
-            if UserSettings.Get(group='atm', key='leftDbClick', subkey='selection') == 0:
-                win.Bind(wx.EVT_LEFT_DCLICK, self.OnDataItemEdit)
-                win.Bind(wx.EVT_COMMAND_LEFT_DCLICK, self.OnDataItemEdit)
-            else:
-                win.Bind(wx.EVT_LEFT_DCLICK, self.OnDataDrawSelected)
-                win.Bind(wx.EVT_COMMAND_LEFT_DCLICK, self.OnDataDrawSelected)
-                
-            
-            listSizer.Add(item=win, proportion=1,
-                          flag=wx.EXPAND | wx.ALL,
-                          border=3)
-
-            # sql statement box
-            btnApply = wx.Button(parent=panel, id=wx.ID_APPLY)
-            btnApply.SetToolTipString(_("Apply SELECT statement and reload data records"))
-            btnApply.Bind(wx.EVT_BUTTON, self.OnApplySqlStatement)
-            btnSqlBuilder = wx.Button(parent=panel, id=wx.ID_ANY, label=_("SQL Builder"))
-            btnSqlBuilder.Bind(wx.EVT_BUTTON, self.OnBuilder)
-
-            sqlSimple = wx.RadioButton(parent=panel, id=wx.ID_ANY,
-                                       label=_("Simple"))
-            sqlSimple.SetValue(True)
-            sqlAdvanced = wx.RadioButton(parent=panel, id=wx.ID_ANY,
-                                         label=_("Advanced"))
-            sqlSimple.Bind(wx.EVT_RADIOBUTTON,   self.OnChangeSql)
-            sqlAdvanced.Bind(wx.EVT_RADIOBUTTON, self.OnChangeSql)
-
-            sqlWhereColumn = wx.Choice(parent=panel, id=wx.ID_ANY,
-                                       size=(100,-1),
-                                       choices=self.mapDBInfo.GetColumns(self.mapDBInfo.layers[layer]['table']))
-            sqlWhereValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value="",
-                                        style=wx.TE_PROCESS_ENTER)
-            sqlWhereValue.SetToolTipString(_("Example: %s") % "MULTILANE = 'no' AND OBJECTID < 10")
-
-            sqlStatement = wx.TextCtrl(parent=panel, id=wx.ID_ANY,
-                                       value="SELECT * FROM %s" % \
-                                           self.mapDBInfo.layers[layer]['table'],
-                                       style=wx.TE_PROCESS_ENTER)
-            sqlStatement.SetToolTipString(_("Example: %s") % "SELECT * FROM roadsmajor WHERE MULTILANE = 'no' AND OBJECTID < 10")
-            sqlWhereValue.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement)
-            sqlStatement.Bind(wx.EVT_TEXT_ENTER, self.OnApplySqlStatement)
-
-            sqlLabel = wx.StaticText(parent=panel, id=wx.ID_ANY,
-                                     label="SELECT * FROM %s WHERE " % \
-                                         self.mapDBInfo.layers[layer]['table'])
-            label_query = wx.StaticText(parent=panel, id=wx.ID_ANY,
-                                        label="")
-
-            sqlFlexSizer = wx.FlexGridSizer (cols=3, hgap=5, vgap=5)
-            sqlFlexSizer.AddGrowableCol(1)
-
-            sqlFlexSizer.Add(item=sqlSimple,
-                             flag=wx.ALIGN_CENTER_VERTICAL)
-            sqlSimpleSizer = wx.BoxSizer(wx.HORIZONTAL)
-            sqlSimpleSizer.Add(item=sqlLabel,
-                               flag=wx.ALIGN_CENTER_VERTICAL)
-            sqlSimpleSizer.Add(item=sqlWhereColumn,
-                               flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-            sqlSimpleSizer.Add(item=sqlWhereValue, proportion=1,
-                               flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-            sqlFlexSizer.Add(item=sqlSimpleSizer,
-                             flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
-            sqlFlexSizer.Add(item=btnApply,
-                             flag=wx.ALIGN_RIGHT)
-            sqlFlexSizer.Add(item=sqlAdvanced,
-                             flag=wx.ALIGN_CENTER_VERTICAL)
-            sqlFlexSizer.Add(item=sqlStatement,
-                             flag=wx.EXPAND)
-            sqlFlexSizer.Add(item=btnSqlBuilder,
-                             flag=wx.ALIGN_RIGHT)
-
-            sqlSizer.Add(item=sqlFlexSizer,
-                         flag=wx.ALL | wx.EXPAND,
-                         border=3)
-
-            pageSizer.Add(item=listSizer,
-                          proportion=1,
-                          flag=wx.ALL | wx.EXPAND,
-                          border=5)
-
-            pageSizer.Add(item=sqlSizer,
-                          proportion=0,
-                          flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.EXPAND,
-                          border=5)
-
-            panel.SetSizer(pageSizer)
-
-            self.layerPage[layer]['data']      = win.GetId()
-            self.layerPage[layer]['simple']    = sqlSimple.GetId()
-            self.layerPage[layer]['advanced']  = sqlAdvanced.GetId()
-            self.layerPage[layer]['whereColumn'] = sqlWhereColumn.GetId()
-            self.layerPage[layer]['where']     = sqlWhereValue.GetId()
-            self.layerPage[layer]['builder']   = btnSqlBuilder.GetId()
-            self.layerPage[layer]['statement'] = sqlStatement.GetId()
-
-
-        self.browsePage.SetSelection(0) # select first layer
-        try:
-            self.layer = self.mapDBInfo.layers.keys()[0]
-            self.OnChangeSql(None)
-            self.log.write(_("Number of loaded records: %d") % \
-                           self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount())
-        except (IndexError, KeyError):
-            self.layer = None
-        
-    def _createManageTablePage(self, onlyLayer=-1):
-        """!Create manage page (create/link and alter tables)"""
-        for layer in self.mapDBInfo.layers.keys():
-            if onlyLayer > 0 and layer != onlyLayer:
-                continue
-            
-            if not layer in self.layerPage:
-                continue
-            
-            panel = wx.Panel(parent=self.manageTablePage, id=wx.ID_ANY)
-            self.layerPage[layer]['tablePage'] = panel.GetId()
-            label = _("Table")
-            if not self.editable:
-                label += _(" (readonly)")
-            self.manageTablePage.AddPage(page=panel,
-                                         text=" %d / %s %s" % (layer, label,
-                                                               self.mapDBInfo.layers[layer]['table']))
-            
-            pageSizer = wx.BoxSizer(wx.VERTICAL)
-            
-            #
-            # dbInfo
-            #
-            dbBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
-                                          label=" %s " % _("Database connection"))
-            dbSizer = wx.StaticBoxSizer(dbBox, wx.VERTICAL)
-            dbSizer.Add(item=dbm_base.createDbInfoDesc(panel, self.mapDBInfo, layer),
-                        proportion=1,
-                        flag=wx.EXPAND | wx.ALL,
-                        border=3)
-            
-            #
-            # table description
-            #
-            table = self.mapDBInfo.layers[layer]['table']
-            tableBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
-                                    label=" %s " % _("Table <%s> - right-click to delete column(s)") % table)
-            
-            tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
-            
-            list = self._createTableDesc(panel, table)
-            list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnTableRightUp) #wxMSW
-            list.Bind(wx.EVT_RIGHT_UP,            self.OnTableRightUp) #wxGTK
-            self.layerPage[layer]['tableData'] = list.GetId()
-            
-            #
-            # add column
-            #
-            columnBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
-                                     label=" %s " % _("Manage columns"))
-            
-            columnSizer = wx.StaticBoxSizer(columnBox, wx.VERTICAL)
-            
-            addSizer = wx.FlexGridSizer (cols=5, hgap=3, vgap=3)
-            addSizer.AddGrowableCol(3)
-            
-            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Column name"))
-            column = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value='',
-                                 size=(150, -1), style=wx.TE_PROCESS_ENTER)
-            column.Bind(wx.EVT_TEXT,       self.OnTableAddColumnName)
-            column.Bind(wx.EVT_TEXT_ENTER, self.OnTableItemAdd)
-            self.layerPage[layer]['addColName'] = column.GetId()
-            addSizer.Add(item=label,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            addSizer.Add(item=column,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            # data type
-            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Data type"))
-            addSizer.Add(item=label,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            
-            subSizer = wx.BoxSizer(wx.HORIZONTAL)
-            type = wx.Choice (parent=panel, id=wx.ID_ANY,
-                              choices = ["integer",
-                                         "double",
-                                         "varchar",
-                                         "date"]) # FIXME
-            type.SetSelection(0)
-            type.Bind(wx.EVT_CHOICE, self.OnTableChangeType)
-            self.layerPage[layer]['addColType'] = type.GetId()
-            subSizer.Add(item=type,
-                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
-                         border=3)
-            # length
-            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Data length"))
-            length = wx.SpinCtrl(parent=panel, id=wx.ID_ANY, size=(65, -1),
-                                 initial=250,
-                                 min=1, max=1e6)
-            length.Enable(False)
-            self.layerPage[layer]['addColLength'] = length.GetId()
-            subSizer.Add(item=label,
-                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
-                         border=3)
-            subSizer.Add(item=length,
-                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
-                         border=3)
-            
-            addSizer.Add(item=subSizer,
-                         flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
-                         border=3)
-            
-            btnAddCol = wx.Button(parent=panel, id=wx.ID_ANY, label=_("Add"))
-            btnAddCol.Bind(wx.EVT_BUTTON, self.OnTableItemAdd)
-            btnAddCol.Enable(False)
-            self.layerPage[layer]['addColButton'] = btnAddCol.GetId()
-            addSizer.Add(item=btnAddCol,
-                         proportion=0,
-                         flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE |
-                         wx.ALIGN_CENTER_VERTICAL )
-            
-            # rename col
-            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("Rename column"))
-            column = wx.ComboBox(parent=panel, id=wx.ID_ANY, size=(150, -1),
-                                 style=wx.CB_SIMPLE | wx.CB_READONLY,
-                                 choices=self.mapDBInfo.GetColumns(table))
-            column.SetSelection(0)
-            self.layerPage[layer]['renameCol'] = column.GetId()
-            addSizer.Add(item=label,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            addSizer.Add(item=column,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            label  = wx.StaticText(parent=panel, id=wx.ID_ANY, label=_("To"))
-            columnTo = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value='',
-                                   size=(150, -1), style=wx.TE_PROCESS_ENTER)
-            columnTo.Bind(wx.EVT_TEXT,       self.OnTableRenameColumnName)
-            columnTo.Bind(wx.EVT_TEXT_ENTER, self.OnTableItemChange)
-            self.layerPage[layer]['renameColTo'] = columnTo.GetId()
-            addSizer.Add(item=label,
-                         flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
-            addSizer.Add(item=columnTo,
-                         flag=wx.ALIGN_CENTER_VERTICAL)
-            btnRenameCol = wx.Button(parent=panel, id=wx.ID_ANY, label=_("&Rename"))
-            btnRenameCol.Bind(wx.EVT_BUTTON, self.OnTableItemChange)
-            btnRenameCol.Enable(False)
-            self.layerPage[layer]['renameColButton'] = btnRenameCol.GetId()
-            
-            addSizer.Add(item=btnRenameCol,
-                         proportion=0,
-                         flag=wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE |
-                         wx.ALIGN_CENTER_VERTICAL)
-
-            columnSizer.Add(item=addSizer, proportion=1,
-                            flag=wx.ALL | wx.EXPAND, border=3)
-            
-            tableSizer.Add(item=list,
-                           flag=wx.ALL | wx.EXPAND,
-                           proportion=1,
-                           border=3)
-            
-            pageSizer.Add(item=dbSizer,
-                          flag=wx.ALL | wx.EXPAND,
-                          proportion=0,
-                          border=3)
-            
-            pageSizer.Add(item=tableSizer,
-                          flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-                          proportion=1,
-                          border=3)
- 
-            pageSizer.Add(item=columnSizer,
-                          flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-                          proportion=0,
-                          border=3)
-            
-            panel.SetSizer(pageSizer)
-        
-        self.manageTablePage.SetSelection(0) # select first layer
-        try:
-            self.layer = self.mapDBInfo.layers.keys()[0]
-        except IndexError:
-            self.layer = None
-        
-    def _createTableDesc(self, parent, table):
-        """!Create list with table description"""
-        list = TableListCtrl(parent=parent, id=wx.ID_ANY,
-                             table=self.mapDBInfo.tables[table],
-                             columns=self.mapDBInfo.GetColumns(table))
-        list.Populate()
-        # sorter
-        # itemDataMap = list.Populate()
-        # listmix.ColumnSorterMixin.__init__(self, 2)
-
-        return list
-
-    def _createManageLayerPage(self):
-        """!Create manage page"""
-        splitterWin = wx.SplitterWindow(parent=self.manageLayerPage, id=wx.ID_ANY)
-        splitterWin.SetMinimumPaneSize(100)
-        
-        label = _("Layers of vector map")
-        if not self.editable:
-            label += _(" (readonly)")
-        self.manageLayerPage.AddPage(page=splitterWin,
-                                     text=label) # dummy page
-        
-        #
-        # list of layers
-        #
-        panelList = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
-
-        panelListSizer  = wx.BoxSizer(wx.VERTICAL)
-        layerBox = wx.StaticBox(parent=panelList, id=wx.ID_ANY,
-                                label=" %s " % _("List of layers"))
-        layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
-
-        self.layerList = self._createLayerDesc(panelList)
-        self.layerList.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnLayerRightUp) #wxMSW
-        self.layerList.Bind(wx.EVT_RIGHT_UP,            self.OnLayerRightUp) #wxGTK
-        
-        layerSizer.Add(item=self.layerList,
-                       flag=wx.ALL | wx.EXPAND,
-                       proportion=1,
-                       border=3)
-
-        panelListSizer.Add(item=layerSizer,
-                           flag=wx.ALL | wx.EXPAND,
-                           proportion=1,
-                           border=3)
-
-        panelList.SetSizer(panelListSizer)
-
-        #
-        # manage part
-        #
-        panelManage = wx.Panel(parent=splitterWin, id=wx.ID_ANY)
-         
-        manageSizer = wx.BoxSizer(wx.VERTICAL)
-
-        self.manageLayerBook = LayerBook(parent=panelManage, id=wx.ID_ANY,
-                                         parentDialog=self)
-
-        manageSizer.Add(item=self.manageLayerBook,
-                        proportion=1,
-                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-                        border=5)
-
-        panelManage.SetSizer(manageSizer)
-        splitterWin.SplitHorizontally(panelList, panelManage, 100) 
-        splitterWin.Fit()
-
-    def _createLayerDesc(self, parent):
-        """!Create list of linked layers"""
-        list = LayerListCtrl(parent=parent, id=wx.ID_ANY,
-                             layers=self.mapDBInfo.layers)
-        
-        list.Populate()
-        # sorter
-        # itemDataMap = list.Populate()
-        # listmix.ColumnSorterMixin.__init__(self, 2)
-
-        return list
-
-    def _layout(self):
-        """!Do layout"""
-        # frame body
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-
-        # buttons
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item=self.btnReload, proportion=1,
-                     flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
-        btnSizer.Add(item=self.btnQuit, proportion=1,
-                     flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
-
-        mainSizer.Add(item=self.notebook, proportion=1, flag=wx.EXPAND)
-        mainSizer.Add(item=btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
-
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(mainSizer)
-        mainSizer.Fit(self.panel)
-        self.Layout()
-        
-    def OnDataRightUp(self, event):
-        """!Table description area, context menu"""
-        if not hasattr(self, "popupDataID1"):
-            self.popupDataID1 = wx.NewId()
-            self.popupDataID2 = wx.NewId()
-            self.popupDataID3 = wx.NewId()
-            self.popupDataID4 = wx.NewId()
-            self.popupDataID5 = wx.NewId()
-            self.popupDataID6 = wx.NewId()
-            self.popupDataID7 = wx.NewId()
-            self.popupDataID8 = wx.NewId()
-            self.popupDataID9 = wx.NewId()
-            self.popupDataID10 = wx.NewId()
-            self.popupDataID11 = wx.NewId()
-
-            self.Bind(wx.EVT_MENU, self.OnDataItemEdit,       id=self.popupDataID1)
-            self.Bind(wx.EVT_MENU, self.OnDataItemAdd,        id=self.popupDataID2)
-            self.Bind(wx.EVT_MENU, self.OnDataItemDelete,     id=self.popupDataID3)
-            self.Bind(wx.EVT_MENU, self.OnDataItemDeleteAll,  id=self.popupDataID4)
-            self.Bind(wx.EVT_MENU, self.OnDataSelectAll,      id=self.popupDataID5)
-            self.Bind(wx.EVT_MENU, self.OnDataSelectNone,     id=self.popupDataID6)
-            self.Bind(wx.EVT_MENU, self.OnDataDrawSelected,   id=self.popupDataID7)
-            self.Bind(wx.EVT_MENU, self.OnDataDrawSelectedZoom, id=self.popupDataID8)
-            self.Bind(wx.EVT_MENU, self.OnExtractSelected,    id=self.popupDataID9)
-            self.Bind(wx.EVT_MENU, self.OnDeleteSelected,     id=self.popupDataID11)
-            self.Bind(wx.EVT_MENU, self.OnDataReload,         id=self.popupDataID10)
-
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupDataID1, _("Edit selected record"))
-        selected = list.GetFirstSelected()
-        if not self.editable or selected == -1 or list.GetNextSelected(selected) != -1:
-            menu.Enable(self.popupDataID1, False)
-        menu.Append(self.popupDataID2, _("Insert new record"))
-        menu.Append(self.popupDataID3, _("Delete selected record(s)"))
-        menu.Append(self.popupDataID4, _("Delete all records"))
-        if not self.editable:
-            menu.Enable(self.popupDataID2, False)
-            menu.Enable(self.popupDataID3, False)
-            menu.Enable(self.popupDataID4, False)
-        menu.AppendSeparator()
-        menu.Append(self.popupDataID5, _("Select all"))
-        menu.Append(self.popupDataID6, _("Deselect all"))
-        menu.AppendSeparator()
-        menu.Append(self.popupDataID7, _("Highlight selected features"))
-        menu.Append(self.popupDataID8, _("Highlight selected features and zoom"))
-        if not self.map or len(list.GetSelectedItems()) == 0:
-            menu.Enable(self.popupDataID7, False)
-            menu.Enable(self.popupDataID8, False)
-        menu.Append(self.popupDataID9, _("Extract selected features"))
-        menu.Append(self.popupDataID11, _("Delete selected features"))
-        if not self.editable:
-            menu.Enable(self.popupDataID11, False)
-        if list.GetFirstSelected() == -1:
-            menu.Enable(self.popupDataID3, False)
-            menu.Enable(self.popupDataID9, False)
-            menu.Enable(self.popupDataID11, False)
-        menu.AppendSeparator()
-        menu.Append(self.popupDataID10, _("Reload"))
-
-        self.PopupMenu(menu)
-        menu.Destroy()
-
-        # update statusbar
-        self.log.write(_("Number of loaded records: %d") % \
-                           list.GetItemCount())
-
-    def OnDataItemDelete(self, event):
-        """!Delete selected item(s) from the list (layer/category pair)"""
-        dlist = self.FindWindowById(self.layerPage[self.layer]['data'])
-        item = dlist.GetFirstSelected()
-        
-        table    = self.mapDBInfo.layers[self.layer]["table"]
-        key      = self.mapDBInfo.layers[self.layer]["key"]
-        
-        indeces = []
-        # collect SQL statements
-        while item != -1:
-            index = dlist.itemIndexMap[item]
-            indeces.append(index)
-            
-            cat = dlist.itemCatsMap[index]
-            
-            self.listOfSQLStatements.append('DELETE FROM %s WHERE %s=%d' % \
-                                                (table, key, cat))
-            
-            item = dlist.GetNextSelected(item)
-        
-        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
-            deleteDialog = wx.MessageBox(parent=self,
-                                         message=_("Selected data records (%d) will permanently deleted "
-                                                   "from table. Do you want to delete them?") % \
-                                             (len(self.listOfSQLStatements)),
-                                         caption=_("Delete records"),
-                                         style=wx.YES_NO | wx.CENTRE)
-            if deleteDialog != wx.YES:
-                self.listOfSQLStatements = []
-                return False
-        
-        # restore maps
-        i = 0
-        indexTemp = copy.copy(dlist.itemIndexMap)
-        dlist.itemIndexMap = []
-        dataTemp = copy.deepcopy(dlist.itemDataMap)
-        dlist.itemDataMap = {}
-        catsTemp = copy.deepcopy(dlist.itemCatsMap)
-        dlist.itemCatsMap = {}
-        
-        i = 0
-        for index in indexTemp:
-            if index in indeces:
-                continue
-            dlist.itemIndexMap.append(i)
-            dlist.itemDataMap[i] = dataTemp[index]
-            dlist.itemCatsMap[i] = catsTemp[index]
-            
-            i += 1
-            
-        dlist.SetItemCount(len(dlist.itemIndexMap))
-        
-        # deselect items
-        item = dlist.GetFirstSelected()
-        while item != -1:
-            dlist.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
-            item = dlist.GetNextSelected(item)
-        
-        # submit SQL statements
-        self.ApplyCommands()
-        
-        return True
-
-    def OnDataItemDeleteAll(self, event):
-        """!Delete all items from the list"""
-        dlist = self.FindWindowById(self.layerPage[self.layer]['data'])
-        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
-            deleteDialog = wx.MessageBox(parent=self,
-                                         message=_("All data records (%d) will permanently deleted "
-                                                   "from table. Do you want to delete them?") % \
-                                             (len(dlist.itemIndexMap)),
-                                         caption=_("Delete records"),
-                                         style=wx.YES_NO | wx.CENTRE)
-            if deleteDialog != wx.YES:
-                return
-
-        dlist.DeleteAllItems()
-        dlist.itemDataMap  = {}
-        dlist.itemIndexMap = []
-        dlist.SetItemCount(0)
-
-        table = self.mapDBInfo.layers[self.layer]["table"]
-        self.listOfSQLStatements.append('DELETE FROM %s' % table)
-
-        self.ApplyCommands()
-        
-        event.Skip()
-
-    def _drawSelected(self, zoom):
-        """!Highlight selected features"""
-        if not self.map or not self.mapdisplay:
-            return
-        
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        cats = map(int, list.GetSelectedItems())
-
-        digitToolbar = None
-        if 'vdigit' in self.mapdisplay.toolbars:
-            digitToolbar = self.mapdisplay.toolbars['vdigit']
-        if digitToolbar and digitToolbar.GetLayer() and \
-                digitToolbar.GetLayer().GetName() == self.vectorName:
-
-            self.mapdisplay.digit.driver.SetSelected(cats, field=self.layer)
-            if zoom:
-                n, s, w, e = self.mapdisplay.digit.driver.GetRegionSelected()
-                self.mapdisplay.Map.GetRegion(n=n, s=s, w=w, e=e,
-                                              update=True)
-        else:
-            # add map layer with higlighted vector features
-            self.AddQueryMapLayer() # -> self.qlayer
-
-            # set opacity based on queried layer
-            if self.parent and self.parent.GetName() == "LayerManager" and \
-                    self.treeItem:
-                maptree = self.parent.curr_page.maptree
-                opacity = maptree.GetPyData(self.treeItem)[0]['maplayer'].GetOpacity(float=True)
-                self.qlayer.SetOpacity(opacity)
-            if zoom:
-                keyColumn = self.mapDBInfo.layers[self.layer]['key']
-                where = ''
-                for range in utils.ListOfCatsToRange(cats).split(','):
-                    if '-' in range:
-                        min, max = range.split('-')
-                        where += '%s >= %d and %s <= %d or ' % \
-                            (keyColumn, int(min),
-                             keyColumn, int(max))
-                    else:
-                        where += '%s = %d or ' % (keyColumn, int(range))
-                where = where.rstrip('or ')
-                
-                select = gcmd.RunCommand('v.db.select',
-                                         parent = self,
-                                         read = True,
-                                         quiet = True,
-                                         flags = 'r',
-                                         map = self.mapDBInfo.map,
-                                         layer = int(self.layer),
-                                         where = where)
-                
-                region = {}
-                for line in select.splitlines():
-                    key, value = line.split('=')
-                    region[key.strip()] = float(value.strip())
-                
-                self.mapdisplay.Map.GetRegion(n=region['n'], s=region['s'],
-                                              w=region['w'], e=region['e'],
-                                              update=True)
-        
-        if zoom:
-            self.mapdisplay.Map.AdjustRegion() # adjust resolution
-            self.mapdisplay.Map.AlignExtentFromDisplay() # adjust extent
-            self.mapdisplay.MapWindow.UpdateMap(render=True, renderVector=True)
-        else:
-            self.mapdisplay.MapWindow.UpdateMap(render=False, renderVector=True)
-        
-    def OnDataDrawSelected(self, event):
-        """!Reload table description"""
-        self._drawSelected(zoom=False)
-        event.Skip()
-
-    def OnDataDrawSelectedZoom(self, event):
-        self._drawSelected(zoom=True)
-        event.Skip()
-        
-    def OnDataItemAdd(self, event):
-        """!Add new record to the attribute table"""
-        list      = self.FindWindowById(self.layerPage[self.layer]['data'])
-        table     = self.mapDBInfo.layers[self.layer]['table']
-        keyColumn = self.mapDBInfo.layers[self.layer]['key']
-        
-        # (column name, value)
-        data = []
-
-        # collect names of all visible columns
-        columnName = []
-        for i in range(list.GetColumnCount()): 
-            columnName.append(list.GetColumn(i).GetText())
-
-        # maximal category number
-        if len(list.itemCatsMap.values()) > 0:
-            maxCat = max(list.itemCatsMap.values())
-        else:
-            maxCat = 0 # starting category '1'
-        
-        # key column must be always presented
-        if keyColumn not in columnName:
-            columnName.insert(0, keyColumn) # insert key column on first position
-            data.append((keyColumn, str(maxCat + 1)))
-            missingKey = True
-        else:
-            missingKey = False
-            
-        # add other visible columns
-        colIdx = 0
-        keyId = -1
-        for col in columnName:
-            if col == keyColumn: # key 
-                if missingKey is False: 
-                    data.append((col, str(maxCat + 1)))
-                    keyId = colIdx
-            else:
-                data.append((col, ''))
-            colIdx += 1
-                
-        dlg = ModifyTableRecord(parent = self,
-                                title = _("Insert new record"),
-                                data = data, keyEditable = (keyId, True))
-
-        if dlg.ShowModal() == wx.ID_OK:
-            try: # get category number
-                cat = int(dlg.GetValues(columns=[keyColumn])[0])
-            except:
-                cat = -1
-
-            try:
-                if cat in list.itemCatsMap.values():
-                    raise ValueError(_("Record with category number %d "
-                                       "already exists in the table.") % cat)
-
-                values = dlg.GetValues() # values (need to be casted)
-                columnsString = ''
-                valuesString   = ''
-                
-                for i in range(len(values)):
-                    if len(values[i]) == 0: # NULL
-                        if columnName[i] == keyColumn:
-                            raise ValueError(_("Category number (column %s)"
-                                               " is missing.") % keyColumn)
-                        else:
-                            continue
-
-                    try:
-                        if list.columns[columnName[i]]['ctype'] == int:
-                            # values[i] is stored as text. 
-                            value = float(values[i])
-                        else:
-                            value = values[i]
-                        values[i] = list.columns[columnName[i]]['ctype'] (value)
-
-                    except:
-                        raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") % 
-                                         {'value' : str(values[i]),
-                                          'type' : list.columns[columnName[i]]['type']})
-                    columnsString += '%s,' % columnName[i]
-                    if list.columns[columnName[i]]['ctype'] == str:
-                        valuesString += "'%s'," % values[i]
-                    else:
-                        valuesString += "%s," % values[i]
-
-            except ValueError, err:
-                wx.MessageBox(parent=self,
-                              message="%s%s%s" % (_("Unable to insert new record."),
-                                                    os.linesep, err),
-                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                return
-
-            # remove category if need 
-            if missingKey is True:
-                del values[0]
-                
-            # add new item to the list
-            if len(list.itemIndexMap) > 0:
-                index = max(list.itemIndexMap) + 1
-            else:
-                index = 0
-            
-            list.itemIndexMap.append(index)
-            list.itemDataMap[index] = values
-            list.itemCatsMap[index] = cat
-            list.SetItemCount(list.GetItemCount() + 1)
-
-            self.listOfSQLStatements.append('INSERT INTO %s (%s) VALUES(%s)' % \
-                                                (table,
-                                                 columnsString.strip(','),
-                                                 valuesString.strip(',')))
-            self.ApplyCommands()
-            
-    def OnDataItemEdit(self, event):
-        """!Edit selected record of the attribute table"""
-        list      = self.FindWindowById(self.layerPage[self.layer]['data'])
-        item      = list.GetFirstSelected()
-        if item == -1:
-            return
-
-        table     = self.mapDBInfo.layers[self.layer]['table']
-        keyColumn = self.mapDBInfo.layers[self.layer]['key']
-        cat       = list.itemCatsMap[list.itemIndexMap[item]]
-
-        # (column name, value)
-        data = []
-
-        # collect names of all visible columns
-        columnName = []
-        for i in range(list.GetColumnCount()): 
-            columnName.append(list.GetColumn(i).GetText())
-
-
-        # key column must be always presented
-        if keyColumn not in columnName:
-            columnName.insert(0, keyColumn) # insert key column on first position
-            data.append((keyColumn, str(cat)))
-            keyId = 0
-            missingKey = True
-        else:
-            missingKey = False
-            
-        # add other visible columns
-        for i in range(len(columnName)):
-            if columnName[i] == keyColumn: # key 
-                if missingKey is False: 
-                    data.append((columnName[i], str(cat)))
-                    keyId = i
-            else:
-                if missingKey is True:
-                    value = list.GetItem(item, i-1).GetText()
-                else:
-                    value = list.GetItem(item, i).GetText()
-                data.append((columnName[i], value))
-
-        dlg = ModifyTableRecord(parent = self, 
-                                title = _("Update existing record"),
-                                data = data, keyEditable = (keyId, False))
-
-        if dlg.ShowModal() == wx.ID_OK:
-            values = dlg.GetValues() # string
-            updateString = ''
-            try:
-                for i in range(len(values)): 
-                    if i == keyId: # skip key column
-                        continue
-                    if list.GetItem(item, i).GetText() != values[i]:
-                        if len(values[i]) > 0:
-                            try:
-                                if missingKey is True:
-                                    idx = i - 1
-                                else:
-                                    idx = i
-                                if list.columns[columnName[i]]['ctype'] != type(''):
-                                    if list.columns[columnName[i]]['ctype'] == int:
-                                        value = float(values[i])
-                                    else:
-                                        value = values[i]
-                                    list.itemDataMap[item][idx] = \
-                                        list.columns[columnName[i]]['ctype'] (value)
-                                else:
-                                    list.itemDataMap[item][idx] = values[i]
-                            except:
-                                raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") % \
-                                                     {'value' : str(values[i]),
-                                                      'type' : list.columns[columnName[i]]['type']})
-
-                            if list.columns[columnName[i]]['ctype'] == str:
-                                updateString += "%s='%s'," % (columnName[i], values[i])
-                            else:
-                                updateString += "%s=%s," % (columnName[i], values[i])
-                        else: # NULL
-                            updateString += "%s=NULL," % (columnName[i])
-                            
-            except ValueError, err:
-                wx.MessageBox(parent=self,
-                              message="%s%s%s" % (_("Unable to update existing record."),
-                                                  os.linesep, err),
-                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                return
-            
-            if len(updateString) > 0:
-                self.listOfSQLStatements.append('UPDATE %s SET %s WHERE %s=%d' % \
-                                                    (table, updateString.strip(','),
-                                                     keyColumn, cat))
-                self.ApplyCommands()
-
-            list.Update(self.mapDBInfo)
-                        
-    def OnDataReload(self, event):
-        """!Reload list of records"""
-        self.OnApplySqlStatement(None)
-        self.listOfSQLStatements = []
-
-    def OnDataSelectAll(self, event):
-        """!Select all items"""
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        item = -1
-
-        while True:
-            item = list.GetNextItem(item)
-            if item == -1:
-                break
-            list.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
-
-        event.Skip()
-
-    def OnDataSelectNone(self, event):
-        """!Deselect items"""
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        item = -1
-
-        while True:
-            item = list.GetNextItem(item, wx.LIST_STATE_SELECTED)
-            if item == -1:
-                break
-            list.SetItemState(item, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
-
-        event.Skip()
-
-
-    def OnTableChangeType(self, event):
-        """!Data type for new column changed. Enable or disable
-        data length widget"""
-        win = self.FindWindowById(self.layerPage[self.layer]['addColLength'])
-        if event.GetString() == "varchar":
-            win.Enable(True)
-        else:
-            win.Enable(False)
-
-    def OnTableRenameColumnName(self, event):
-        """!Editing column name to be added to the table"""
-        btn  = self.FindWindowById(self.layerPage[self.layer]['renameColButton'])
-        col  = self.FindWindowById(self.layerPage[self.layer]['renameCol'])
-        colTo = self.FindWindowById(self.layerPage[self.layer]['renameColTo'])
-        if len(col.GetValue()) > 0 and len(colTo.GetValue()) > 0:
-            btn.Enable(True)
-        else:
-            btn.Enable(False)
-
-        event.Skip()
-
-    def OnTableAddColumnName(self, event):
-        """!Editing column name to be added to the table"""
-        btn = self.FindWindowById(self.layerPage[self.layer]['addColButton'])
-        if len(event.GetString()) > 0:
-            btn.Enable(True)
-        else:
-            btn.Enable(False)
-
-        event.Skip()
-
-    def OnTableItemChange(self, event):
-        """!Rename column in the table"""
-        list   = self.FindWindowById(self.layerPage[self.layer]['tableData'])
-        name   = self.FindWindowById(self.layerPage[self.layer]['renameCol']).GetValue()
-        nameTo = self.FindWindowById(self.layerPage[self.layer]['renameColTo']).GetValue()
-
-        table = self.mapDBInfo.layers[self.layer]["table"]
-
-        if not name or not nameTo:
-            wx.MessageBox(self=self,
-                          message=_("Unable to rename column. "
-                                    "No column name defined."),
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return
-        else:
-            item = list.FindItem(start=-1, str=name)
-            if item > -1:
-                if list.FindItem(start=-1, str=nameTo) > -1:
-                    wx.MessageBox(parent=self,
-                                  message=_("Unable to rename column <%(column)s> to "
-                                            "<%(columnTo)s>. Column already exists "
-                                            "in the table <%(table)s>.") % \
-                                      {'column' : name, 'columnTo' : nameTo,
-                                       'table' : table},
-                                  caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                    return
-                else:
-                    list.SetItemText(item, nameTo)
-
-                    self.listOfCommands.append(('v.db.renamecolumn',
-                                                { 'map'    : self.vectorName,
-                                                  'layer'  : self.layer,
-                                                  'column' : '%s,%s' % (name, nameTo) }
-                                                ))
-            else:
-                wx.MessageBox(parent=self,
-                              message=_("Unable to rename column. "
-                                        "Column <%(column)s> doesn't exist in the table <%(table)s>.") % 
-                              {'column' : name, 'table' : table},
-                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                return
-            
-        # apply changes
-        self.ApplyCommands()
-
-        # update widgets
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
-        self.FindWindowById(self.layerPage[self.layer]['renameColTo']).SetValue('')
-
-        event.Skip()
-
-    def OnTableRightUp(self, event):
-        """!Table description area, context menu"""
-        if not hasattr(self, "popupTableID"):
-            self.popupTableID1 = wx.NewId()
-            self.popupTableID2 = wx.NewId()
-            self.popupTableID3 = wx.NewId()
-            self.Bind(wx.EVT_MENU, self.OnTableItemDelete,    id=self.popupTableID1)
-            self.Bind(wx.EVT_MENU, self.OnTableItemDeleteAll, id=self.popupTableID2)
-            self.Bind(wx.EVT_MENU, self.OnTableReload,        id=self.popupTableID3)
-
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupTableID1, _("Drop selected column"))
-        if self.FindWindowById(self.layerPage[self.layer]['tableData']).GetFirstSelected() == -1:
-            menu.Enable(self.popupTableID1, False)
-        menu.Append(self.popupTableID2, _("Drop all columns"))
-        menu.AppendSeparator()
-        menu.Append(self.popupTableID3, _("Reload"))
-
-        self.PopupMenu(menu)
-        menu.Destroy()
-
-    def OnTableItemDelete(self, event):
-        """!Delete selected item(s) from the list"""
-        list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
-        
-        item = list.GetFirstSelected()
-        
-        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
-            deleteDialog = wx.MessageBox(parent=self,
-                                         message=_("Selected column '%s' will PERMANENTLY removed "
-                                                   "from table. Do you want to drop the column?") % \
-                                             (list.GetItemText(item)),
-                                         caption=_("Drop column(s)"),
-                                         style=wx.YES_NO | wx.CENTRE)
-            if deleteDialog != wx.YES:
-                return False
-        
-        while item != -1:
-            self.listOfCommands.append(('v.db.dropcolumn',
-                                        { 'map' : self.vectorName,
-                                          'layer' : self.layer,
-                                          'column' : list.GetItemText(item) }
-                                        ))
-            list.DeleteItem(item)
-            item = list.GetFirstSelected()
-        
-        # apply changes
-        self.ApplyCommands()
-        
-        # update widgets
-        table = self.mapDBInfo.layers[self.layer]['table']
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
-        
-        event.Skip()
-
-    def OnTableItemDeleteAll(self, event):
-        """!Delete all items from the list"""
-        table     = self.mapDBInfo.layers[self.layer]['table']
-        cols      = self.mapDBInfo.GetColumns(table)
-        keyColumn = self.mapDBInfo.layers[self.layer]['key']
-        if keyColumn in cols:
-            cols.remove(keyColumn)
-        
-        if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
-            deleteDialog = wx.MessageBox(parent=self,
-                                         message=_("Selected columns\n%s\nwill PERMANENTLY removed "
-                                                   "from table. Do you want to drop the columns?") % \
-                                             ('\n'.join(cols)),
-                                         caption=_("Drop column(s)"),
-                                         style=wx.YES_NO | wx.CENTRE)
-            if deleteDialog != wx.YES:
-                return False
-        
-        for col in cols:
-            self.listOfCommands.append(('v.db.dropcolumn',
-                                        { 'map' : self.vectorName,
-                                          'layer' : self.layer,
-                                          'column' : col }
-                                        ))
-        self.FindWindowById(self.layerPage[self.layer]['tableData']).DeleteAllItems()
-
-        # apply changes
-        self.ApplyCommands()
-
-        # update widgets
-        table = self.mapDBInfo.layers[self.layer]['table']
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
-
-        event.Skip()
-
-    def OnTableReload(self, event=None):
-        """!Reload table description"""
-        self.FindWindowById(self.layerPage[self.layer]['tableData']).Populate(update=True)
-        self.listOfCommands = []
-
-    def OnTableItemAdd(self, event):
-        """!Add new column to the table"""
-	table = self.mapDBInfo.layers[self.layer]['table']
-        name = self.FindWindowById(self.layerPage[self.layer]['addColName']).GetValue()
-        
-        if not name:
-            gcmd.GError(parent = self,
-                        message = _("Unable to add column to the table. "
-                                    "No column name defined."))
-            return
-        
-        ctype = self.FindWindowById(self.layerPage[self.layer]['addColType']). \
-            GetStringSelection()
-        
-        # cast type if needed
-        if ctype == 'double':
-            ctype = 'double precision'
-        if ctype == 'varchar':
-            length = int(self.FindWindowById(self.layerPage[self.layer]['addColLength']). \
-                             GetValue())
-        else:
-            length = '' # FIXME
-        
-        # add item to the list of table columns
-        tlist = self.FindWindowById(self.layerPage[self.layer]['tableData'])
-        # check for duplicate items
-        if tlist.FindItem(start=-1, str=name) > -1:
-            gcmd.GError(parent = self,
-                        message = _("Column <%(column)s> already exists in table <%(table)s>.") % \
-                            {'column' : name, 'table' : self.mapDBInfo.layers[self.layer]["table"]}
-                        )
-            return
-        index = tlist.InsertStringItem(sys.maxint, str(name))
-        tlist.SetStringItem(index, 0, str(name))
-        tlist.SetStringItem(index, 1, str(ctype))
-        tlist.SetStringItem(index, 2, str(length))
-        
-        # add v.db.addcolumn command to the list
-        if ctype == 'varchar':
-            ctype += ' (%d)' % length
-        self.listOfCommands.append(('v.db.addcolumn',
-                                    { 'map'     : self.vectorName,
-                                      'layer'   : self.layer,
-                                      'columns' : '%s %s' % (name, ctype) }
-                                    ))
-        # apply changes
-        self.ApplyCommands()
-        
-        # update widgets
-        self.FindWindowById(self.layerPage[self.layer]['addColName']).SetValue('')
-	self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetItems(self.mapDBInfo.GetColumns(table))
-        self.FindWindowById(self.layerPage[self.layer]['renameCol']).SetSelection(0)
-        
-        event.Skip()
-        
-    def OnLayerPageChanged(self, event):
-        """!Layer tab changed"""
-        pageNum = event.GetSelection()
-        self.layer = self.mapDBInfo.layers.keys()[pageNum]
-        
-        try:
-            idCol = self.layerPage[self.layer]['whereColumn']
-        except KeyError:
-            idCol = None
-        
-        try:
-            self.OnChangeSql(None)
-            # update statusbar
-            self.log.write(_("Number of loaded records: %d") % \
-                               self.FindWindowById(self.layerPage[self.layer]['data']).\
-                               GetItemCount())
-        except:
-            pass
-        
-        if idCol:
-            winCol = self.FindWindowById(idCol)
-            table = self.mapDBInfo.layers[self.layer]["table"]
-            self.mapDBInfo.GetColumns(table)
-        
-        event.Skip()
-        
-    def OnPageChanged(self, event):
-        try:
-            id = self.layerPage[self.layer]['data']
-        except KeyError:
-            id = None
-        
-        if event.GetSelection() == 0 and id:
-            win = self.FindWindowById(id)
-            if win:
-                self.log.write(_("Number of loaded records: %d") % win.GetItemCount())
-            else:
-                self.log.write("")
-            self.btnReload.Enable()
-        else:
-            self.log.write("")
-            self.btnReload.Enable(False)
-        
-        event.Skip()
-        
-    def OnLayerRightUp(self, event):
-        """!Layer description area, context menu"""
-        pass
-
-    def OnChangeSql(self, event):
-        """!Switch simple/advanced sql statement"""
-        if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue():
-            self.FindWindowById(self.layerPage[self.layer]['where']).Enable(True)
-            self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(False)
-            self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(False)
-        else:
-            self.FindWindowById(self.layerPage[self.layer]['where']).Enable(False)
-            self.FindWindowById(self.layerPage[self.layer]['statement']).Enable(True)
-            self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(True)
-
-    def ApplyCommands(self):
-        """!Apply changes"""
-        # perform GRASS commands (e.g. v.db.addcolumn)
-        wx.BeginBusyCursor()
-        
-        if len(self.listOfCommands) > 0:
-            for cmd in self.listOfCommands:
-                gcmd.RunCommand(prog = cmd[0],
-                                quiet = True,
-                                parent = self,
-                                **cmd[1])
-            
-            self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
-            table = self.mapDBInfo.layers[self.layer]['table']
-
-            # update table description
-            list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
-            list.Update(table=self.mapDBInfo.tables[table],
-                        columns=self.mapDBInfo.GetColumns(table))
-            self.OnTableReload(None)
-
-            # update data list
-            list = self.FindWindowById(self.layerPage[self.layer]['data'])
-            list.Update(self.mapDBInfo)
-
-            # reset list of commands
-            self.listOfCommands = []
-        
-        # perform SQL non-select statements (e.g. 'delete from table where cat=1')
-        if len(self.listOfSQLStatements) > 0:
-            sqlFile = tempfile.NamedTemporaryFile(mode="wt")
-            for sql in self.listOfSQLStatements:
-                enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
-                if not enc and 'GRASS_DB_ENCODING' in os.environ:
-                    enc = os.environ['GRASS_DB_ENCODING']
-                if enc:
-                    sqlFile.file.write(sql.encode(enc) + ';')
-                else:
-                    sqlFile.file.write(sql + ';')
-                sqlFile.file.write(os.linesep)
-                sqlFile.file.flush()
-
-            driver   = self.mapDBInfo.layers[self.layer]["driver"]
-            database = self.mapDBInfo.layers[self.layer]["database"]
-            
-            Debug.msg(3, 'AttributeManger.ApplyCommands(): %s' %
-                      ';'.join(["%s" % s for s in self.listOfSQLStatements]))
-            
-            gcmd.RunCommand('db.execute',
-                            parent = self,
-                            input = sqlFile.name,
-                            driver = driver,
-                            database = database)
-            
-            # reset list of statements
-            self.listOfSQLStatements = []
-            
-        wx.EndBusyCursor()
-        
-    def OnApplySqlStatement(self, event):
-        """!Apply simple/advanced sql statement"""
-        keyColumn = -1 # index of key column
-        listWin = self.FindWindowById(self.layerPage[self.layer]['data'])
-        sql = None
-        
-        wx.BeginBusyCursor()
-        
-        if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue():
-            # simple sql statement
-            whereCol = self.FindWindowById(self.layerPage[self.layer]['whereColumn']).GetStringSelection()
-            whereVal = self.FindWindowById(self.layerPage[self.layer]['where']).GetValue().strip()
-            try:
-                if len(whereVal) > 0:
-                    keyColumn = listWin.LoadData(self.layer, where=whereCol + whereVal)
-                else:
-                    keyColumn = listWin.LoadData(self.layer)
-            except gcmd.GException, e:
-                gcmd.GError(parent = self,
-                            message = _("Loading attribute data failed.\n\n%s") % e.value)
-                self.FindWindowById(self.layerPage[self.layer]['where']).SetValue('')
-        else:
-            # advanced sql statement
-            win = self.FindWindowById(self.layerPage[self.layer]['statement'])
-            try:
-                cols, where = self.ValidateSelectStatement(win.GetValue())
-                if cols is None and where is None:
-                    sql = win.GetValue()
-            except TypeError:
-                wx.MessageBox(parent=self,
-                              message=_("Loading attribute data failed.\n"
-                                        "Invalid SQL select statement.\n\n%s") % win.GetValue(),
-                              caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                win.SetValue("SELECT * FROM %s" % self.mapDBInfo.layers[self.layer]['table'])
-                cols = None
-                where = None
-            
-            if cols or where or sql:
-                try:
-                    keyColumn = listWin.LoadData(self.layer, columns=cols,
-                                                 where=where, sql=sql)
-                except gcmd.GException, e:
-                    gcmd.GError(parent = self,
-                                message = _("Loading attribute data failed.\n\n%s") % e.value)
-                    win.SetValue("SELECT * FROM %s" % self.mapDBInfo.layers[self.layer]['table'])
-        
-        # sort by key column
-        if sql and 'order by' in sql.lower():
-            pass # don't order by key column
-        else:
-            if keyColumn > -1:
-                listWin.SortListItems(col=keyColumn, ascending=True)
-            else:
-                listWin.SortListItems(col=0, ascending=True) 
-        
-        wx.EndBusyCursor()
-        
-        # update statusbar
-        self.log.write(_("Number of loaded records: %d") % \
-                           self.FindWindowById(self.layerPage[self.layer]['data']).GetItemCount())
-
-    def ValidateSelectStatement(self, statement):
-        """!Validate SQL select statement
-
-        @return (columns, where)
-        @return None on error
-        """
-        if statement[0:7].lower() != 'select ':
-            return None
-        
-        cols = ''
-        index = 7
-        for c in statement[index:]:
-            if c == ' ':
-                break
-            cols += c
-            index += 1
-        if cols == '*':
-            cols = None
-        else:
-            cols = cols.split(',')
-        
-        tablelen = len(self.mapDBInfo.layers[self.layer]['table'])
-        
-        if statement[index+1:index+6].lower() != 'from ' or \
-                statement[index+6:index+6+tablelen] != '%s' % \
-                (self.mapDBInfo.layers[self.layer]['table']):
-            return None
-        
-        if len(statement[index+7+tablelen:]) > 0:
-            index = statement.lower().find('where ')
-            if index > -1:
-                where = statement[index+6:]
-            else:
-                where = None
-        else:
-            where = None
-        
-        return (cols, where)
-    
-    def OnCloseWindow(self, event):
-        """!Cancel button pressed"""
-        if self.parent and self.parent.GetName() == 'LayerManager':
-            # deregister ATM
-            self.parent.dialogs['atm'].remove(self)
-                    
-        if not isinstance(event, wx.CloseEvent):
-            self.Destroy()
-        
-        event.Skip()
-
-    def OnBuilder(self,event):
-        """!SQL Builder button pressed -> show the SQLBuilder dialog"""
-        if not self.builder:
-            self.builder = sqlbuilder.SQLFrame(parent = self, id = wx.ID_ANY,
-                                               title = _("SQL Builder"),
-                                               vectmap = self.vectorName,
-                                               evtheader = self.OnBuilderEvt)
-            self.builder.Show()
-        else:
-            self.builder.Raise()
-        
-    def OnBuilderEvt(self, event):
-        if event == 'apply':
-            sqlstr = self.builder.GetSQLStatement()
-            self.FindWindowById(self.layerPage[self.layer]['statement']).SetValue(sqlstr)
-            if self.builder.CloseOnApply():
-                self.builder = None
-        elif event == 'close':
-            self.builder = None
-        
-    def OnTextEnter(self, event):
-        pass
-    
-    def OnDataItemActivated(self, event):
-        """!Item activated, highlight selected item"""
-        self.OnDataDrawSelected(event)
-
-        event.Skip()
-
-    def OnExtractSelected(self, event):
-        """!Extract vector objects selected in attribute browse window
-        to new vector map
-        """
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        # cats = list.selectedCats[:]
-        cats = list.GetSelectedItems()
-        if len(cats) == 0:
-            wx.MessageBox(parent=self,
-                          message=_('Nothing to extract.'),
-                          caption=_('Message'), style=wx.CENTRE)
-            return
-        else:
-            # dialog to get file name
-            dlg = gdialogs.CreateNewVector(parent = self, title = _('Extract selected features'),
-                                           log = self.cmdLog,
-                                           cmd = (('v.extract',
-                                                   { 'input' : self.vectorName,
-                                                     'cats' : utils.ListOfCatsToRange(cats) },
-                                                   'output')),
-                                           disableTable = True)
-            if not dlg:
-                return
-            
-            name = dlg.GetName(full = True)
-            if name and dlg.IsChecked('add'):
-                # add layer to map layer tree
-                self.parent.curr_page.maptree.AddLayer(ltype = 'vector',
-                                                       lname = name,
-                                                       lcmd = ['d.vect', 'map=%s' % name])
-            dlg.Destroy()
-            
-    def OnDeleteSelected(self, event):
-        """!Delete vector objects selected in attribute browse window
-        (attribures and geometry)
-        """
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        cats = list.GetSelectedItems()
-        if len(cats) == 0:
-            wx.MessageBox(parent=self,
-                          message=_('Nothing to delete.'),
-                          caption=_('Message'), style=wx.CENTRE)
-        
-        if self.OnDataItemDelete(None):
-            digitToolbar = self.mapdisplay.toolbars['vdigit']
-            if digitToolbar and digitToolbar.GetLayer() and \
-                    digitToolbar.GetLayer().GetName() == self.vectorName:
-                self.mapdisplay.digit.driver.SetSelected(map(int, cats), field=self.layer)
-                self.mapdisplay.digit.DeleteSelectedLines()
-            else:
-                gcmd.RunCommand('v.edit',
-                                parent = self,
-                                quiet = True,
-                                map = self.vectorName,
-                                tool = 'delete',
-                                cats = utils.ListOfCatsToRange(cats))
-                
-            self.mapdisplay.MapWindow.UpdateMap(render=True, renderVector=True)
-        
-    def AddQueryMapLayer(self):
-        """!Redraw a map
-
-        Return True if map has been redrawn, False if no map is given
-        """
-        list = self.FindWindowById(self.layerPage[self.layer]['data'])
-        cats = { 
-            self.layer : list.GetSelectedItems()
-            }
-        
-        if self.mapdisplay.Map.GetLayerIndex(self.qlayer) < 0:
-            self.qlayer = None
-            
-        if self.qlayer:
-            self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats, addLayer=False))
-        else:
-            self.qlayer = self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats)
-
-        return self.qlayer
-    
-    def UpdateDialog(self, layer):
-        """!Updates dialog layout for given layer"""
-        # delete page
-        if layer in self.mapDBInfo.layers.keys():
-            # delete page
-            # draging pages disallowed
-            # if self.browsePage.GetPageText(page).replace('Layer ', '').strip() == str(layer):
-            # self.browsePage.DeletePage(page)
-            # break
-            self.browsePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
-            self.manageTablePage.DeletePage(self.mapDBInfo.layers.keys().index(layer))
-            # set current page selection
-            self.notebook.SetSelectionByName('layers')
-            
-        # fetch fresh db info
-        self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)    
-
-        #
-        # add new page
-        #
-        if layer in self.mapDBInfo.layers.keys():
-            # 'browse data' page
-            self._createBrowsePage(layer)
-            # 'manage tables' page
-            self._createManageTablePage(layer)
-            # set current page selection
-            self.notebook.SetSelectionByName('layers')
-            
-        #
-        # 'manage layers' page
-        #
-        # update list of layers
-        self.layerList.Update(self.mapDBInfo.layers)
-        self.layerList.Populate(update=True)
-        # update selected widgets
-        listOfLayers = map(str, self.mapDBInfo.layers.keys())
-        ### delete layer page
-        self.manageLayerBook.deleteLayer.SetItems(listOfLayers)
-        if len(listOfLayers) > 0:
-            self.manageLayerBook.deleteLayer.SetStringSelection(listOfLayers[0])
-            tableName = self.mapDBInfo.layers[int(listOfLayers[0])]['table']
-            maxLayer = max(self.mapDBInfo.layers.keys())
-        else:
-            tableName = ''
-            maxLayer = 0
-        self.manageLayerBook.deleteTable.SetLabel( \
-            _('Drop also linked attribute table (%s)') % \
-                tableName)
-        ### add layer page
-        self.manageLayerBook.addLayerWidgets['layer'][1].SetValue(\
-            maxLayer+1)
-        ### modify layer
-        self.manageLayerBook.modifyLayerWidgets['layer'][1].SetItems(listOfLayers)
-        self.manageLayerBook.OnChangeLayer(event=None)
-
-    def GetVectorName(self):
-        """!Get vector name"""
-        return self.vectorName
-    
-    def LoadData(self, layer, columns=None, where=None, sql=None):
-        """!Load data into list
-
-        @param layer layer number
-        @param columns list of columns for output
-        @param where where statement
-        @param sql full sql statement
-
-        @return id of key column 
-        @return -1 if key column is not displayed
-        """
-        listWin = self.FindWindowById(self.layerPage[layer]['data'])
-        return listWin.LoadData(layer, columns, where, sql)
-    
-class TableListCtrl(wx.ListCtrl,
-                    listmix.ListCtrlAutoWidthMixin):
-                    #                    listmix.TextEditMixin):
-    """!Table description list"""
-
-    def __init__(self, parent, id, table, columns, pos=wx.DefaultPosition,
-                 size=wx.DefaultSize):
-
-        self.parent  = parent
-        self.table   = table
-        self.columns = columns
-        wx.ListCtrl.__init__(self, parent, id, pos, size,
-                             style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
-                             wx.BORDER_NONE)
-
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        # listmix.TextEditMixin.__init__(self)
-
-    def Update(self, table, columns):
-        """!Update column description"""
-        self.table   = table
-        self.columns = columns
-
-    def Populate(self, update=False):
-        """!Populate the list"""
-        itemData = {} # requested by sorter
-
-        if not update:
-            headings = [_("Column name"), _("Data type"), _("Data length")]
-            i = 0
-            for h in headings:
-                self.InsertColumn(col=i, heading=h)
-                self.SetColumnWidth(col=i, width=150)
-                i += 1
-        else:
-            self.DeleteAllItems()
-
-        i = 0
-        for column in self.columns:
-            index = self.InsertStringItem(sys.maxint, str(column))
-            self.SetStringItem(index, 0, str(column))
-            self.SetStringItem(index, 1, str(self.table[column]['type']))
-            self.SetStringItem(index, 2, str(self.table[column]['length']))
-            self.SetItemData(index, i)
-            itemData[i] = (str(column),
-                           str(self.table[column]['type']),
-                           int(self.table[column]['length']))
-            i = i + 1
-
-        self.SendSizeEvent()
-        
-        return itemData
-
-class LayerListCtrl(wx.ListCtrl,
-                    listmix.ListCtrlAutoWidthMixin):
-                    # listmix.ColumnSorterMixin):
-                    # listmix.TextEditMixin):
-    """!Layer description list"""
-
-    def __init__(self, parent, id, layers,
-                 pos=wx.DefaultPosition,
-                 size=wx.DefaultSize):
-
-        self.parent = parent
-        self.layers = layers
-        wx.ListCtrl.__init__(self, parent, id, pos, size,
-                             style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES |
-                             wx.BORDER_NONE)
-
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        # listmix.TextEditMixin.__init__(self)
-
-    def Update(self, layers):
-        """!Update description"""
-        self.layers = layers
-
-    def Populate(self, update=False):
-        """!Populate the list"""
-        itemData = {} # requested by sorter
-
-        if not update:
-            headings = [_("Layer"),  _("Driver"), _("Database"), _("Table"), _("Key")]
-            i = 0
-            for h in headings:
-                self.InsertColumn(col=i, heading=h)
-                i += 1
-        else:
-            self.DeleteAllItems()
-
-        i = 0
-        for layer in self.layers.keys():
-            index = self.InsertStringItem(sys.maxint, str(layer))
-            self.SetStringItem(index, 0, str(layer))
-            database = str(self.layers[layer]['database'])
-            driver   = str(self.layers[layer]['driver'])
-            table    = str(self.layers[layer]['table'])
-            key      = str(self.layers[layer]['key'])
-            self.SetStringItem(index, 1, driver)
-            self.SetStringItem(index, 2, database)
-            self.SetStringItem(index, 3, table)
-            self.SetStringItem(index, 4, key)
-            self.SetItemData(index, i)
-            itemData[i] = (str(layer),
-                           driver,
-                           database,
-                           table,
-                           key)
-            i += 1
-
-        for i in range(self.GetColumnCount()):
-            self.SetColumnWidth(col=i, width=wx.LIST_AUTOSIZE)
-            if self.GetColumnWidth(col=i) < 60:
-                self.SetColumnWidth(col=i, width=60)
-
-        self.SendSizeEvent()
-        
-        return itemData
-
-class LayerBook(wx.Notebook):
-    """!Manage layers (add, delete, modify)"""
-    def __init__(self, parent, id,
-                 parentDialog,
-                 style=wx.BK_DEFAULT):
-        wx.Notebook.__init__(self, parent, id, style=style)
-
-        self.parent       = parent
-        self.parentDialog = parentDialog
-        self.mapDBInfo    = self.parentDialog.mapDBInfo
-
-        #
-        # drivers
-        #
-        drivers = gcmd.RunCommand('db.drivers',
-                                  quiet = True,
-                                  read = True,
-                                  flags = 'p')
-        
-        self.listOfDrivers = []
-        for drv in drivers.splitlines():
-            self.listOfDrivers.append(drv.strip())
-        
-        #
-        # get default values
-        #
-        self.defaultConnect = {}
-        connect = gcmd.RunCommand('db.connect',
-                                  flags = 'p',
-                                  read = True,
-                                  quiet = True)
-        
-        for line in connect.splitlines():
-            item, value = line.split(':', 1)
-            self.defaultConnect[item.strip()] = value.strip()
-        
-        if len(self.defaultConnect['driver']) == 0 or \
-               len(self.defaultConnect['database']) == 0:
-            wx.MessageBox(parent=self.parent,
-                          message=_("Unknown default DB connection. "
-                                    "Please define DB connection using db.connect module."),
-                          caption=_("Warning"),
-                          style=wx.OK | wx.ICON_WARNING | wx.CENTRE)
-        
-        self.defaultTables = self._getTables(self.defaultConnect['driver'],
-                                              self.defaultConnect['database'])
-        try:
-            self.defaultColumns = self._getColumns(self.defaultConnect['driver'],
-                                                    self.defaultConnect['database'],
-                                                    self.defaultTables[0])
-        except IndexError:
-            self.defaultColumns = []
-
-        self._createAddPage()
-        self._createDeletePage()
-        self._createModifyPage()
-
-    def _createAddPage(self):
-        """!Add new layer"""
-        self.addPanel = wx.Panel(parent=self, id=wx.ID_ANY)
-        self.AddPage(page=self.addPanel, text=_("Add layer"))
-        
-        try:
-            maxLayer = max(self.mapDBInfo.layers.keys())
-        except ValueError:
-            maxLayer = 0
-
-        # layer description
-        
-        layerBox = wx.StaticBox (parent=self.addPanel, id=wx.ID_ANY,
-                                 label=" %s " % (_("Layer description")))
-        layerSizer = wx.StaticBoxSizer(layerBox, wx.VERTICAL)
-        
-        #
-        # list of layer widgets (label, value)
-        #
-        self.addLayerWidgets = {'layer':
-                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Layer")),
-                                     wx.SpinCtrl(parent=self.addPanel, id=wx.ID_ANY, size=(65, -1),
-                                                 initial=maxLayer+1,
-                                                 min=1, max=1e6)),
-                                'driver':
-                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Driver")),
-                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
-                                               choices=self.listOfDrivers)),
-                                'database':
-                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Database")),
-                                     wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
-                                                 value='',
-                                                 style=wx.TE_PROCESS_ENTER)),
-                                'table':
-                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Table")),
-                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
-                                               choices=self.defaultTables)),
-                                'key':
-                                    (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Key column")),
-                                     wx.Choice(parent=self.addPanel, id=wx.ID_ANY, size=(200, -1),
-                                               choices=self.defaultColumns)),
-                                'addCat':
-                                    (wx.CheckBox(parent=self.addPanel, id=wx.ID_ANY,
-                                                 label=_("Insert record for each category into table")),
-                                     None),
-                                }
-        
-        # set default values for widgets
-        self.addLayerWidgets['driver'][1].SetStringSelection(self.defaultConnect['driver'])
-        self.addLayerWidgets['database'][1].SetValue(self.defaultConnect['database'])
-        self.addLayerWidgets['table'][1].SetSelection(0)
-        self.addLayerWidgets['key'][1].SetSelection(0)
-        # events
-        self.addLayerWidgets['driver'][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
-        self.addLayerWidgets['database'][1].Bind(wx.EVT_TEXT_ENTER, self.OnDatabaseChanged)
-        self.addLayerWidgets['table'][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
-        
-        # tooltips
-        self.addLayerWidgets['addCat'][0].SetToolTipString(_("You need to add categories "
-                                                             "by v.category module."))
-        #
-        # list of table widgets
-        #
-        keyCol = UserSettings.Get(group='atm', key='keycolumn', subkey='value')
-        self.tableWidgets = {'table': (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                     label='%s:' % _("Table name")),
-                                       wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
-                                                   value='',
-                                                   style=wx.TE_PROCESS_ENTER)),
-                             'key': (wx.StaticText(parent=self.addPanel, id=wx.ID_ANY,
-                                                   label='%s:' % _("Key column")),
-                                     wx.TextCtrl(parent=self.addPanel, id=wx.ID_ANY,
-                                                 value=keyCol,
-                                                 style=wx.TE_PROCESS_ENTER))}
-        # events
-        self.tableWidgets['table'][1].Bind(wx.EVT_TEXT_ENTER, self.OnCreateTable)
-        self.tableWidgets['key'][1].Bind(wx.EVT_TEXT_ENTER, self.OnCreateTable)
-        
-        btnTable   = wx.Button(self.addPanel, wx.ID_ANY, _("&Create table"),
-                             size=(125,-1))
-        btnTable.Bind(wx.EVT_BUTTON, self.OnCreateTable)
-        
-        btnLayer   = wx.Button(self.addPanel, wx.ID_ANY, _("&Add layer"),
-                             size=(125,-1))
-        btnLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
-        
-        btnDefault = wx.Button(self.addPanel, wx.ID_ANY, _("&Set default"),
-                               size=(125,-1))
-        btnDefault.Bind(wx.EVT_BUTTON, self.OnSetDefault)
-        
-        # do layout
-        
-        pageSizer = wx.BoxSizer(wx.HORIZONTAL)
-                
-        # data area
-        dataSizer = wx.GridBagSizer(hgap=5, vgap=5)
-        dataSizer.AddGrowableCol(1)
-        row = 0
-        for key in ('layer', 'driver', 'database', 'table', 'key', 'addCat'):
-            label, value = self.addLayerWidgets[key]
-            if not value:
-                span = (1, 2)
-            else:
-                span = (1, 1)
-            dataSizer.Add(item=label,
-                          flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0),
-                          span=span)
-            
-            if not value:
-                row += 1
-                continue
-
-            if label.GetLabel() == "Layer:":
-                style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT
-            else:
-                style = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND
-            
-            dataSizer.Add(item=value,
-                          flag=style, pos=(row, 1))
-            
-            row += 1
-        
-        layerSizer.Add(item=dataSizer,
-                       proportion=1,
-                       flag=wx.ALL | wx.EXPAND,
-                       border=5)
-        
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item=btnDefault,
-                     proportion=0,
-                     flag=wx.ALL | wx.ALIGN_LEFT,
-                     border=5)
-        
-        btnSizer.Add(item=(5, 5),
-                     proportion=1,
-                     flag=wx.ALL | wx.EXPAND,
-                     border=5)
-        
-        btnSizer.Add(item=btnLayer,
-                     proportion=0,
-                     flag=wx.ALL | wx.ALIGN_RIGHT,
-                     border=5)
-        
-        layerSizer.Add(item=btnSizer,
-                       proportion=0,
-                       flag=wx.ALL | wx.EXPAND,
-                       border=0)
-                
-        # table description
-        tableBox = wx.StaticBox (parent=self.addPanel, id=wx.ID_ANY,
-                                 label=" %s " % (_("Table description")))
-        tableSizer = wx.StaticBoxSizer(tableBox, wx.VERTICAL)
-        
-        # data area
-        dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
-        dataSizer.AddGrowableCol(1)
-        for key in ['table', 'key']:
-            label, value = self.tableWidgets[key]
-            dataSizer.Add(item=label,
-                          flag=wx.ALIGN_CENTER_VERTICAL)
-            dataSizer.Add(item=value,
-                          flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
-
-        tableSizer.Add(item=dataSizer,
-                       proportion=1,
-                       flag=wx.ALL | wx.EXPAND,
-                       border=5)
-
-        tableSizer.Add(item=btnTable,
-                       proportion=0,
-                       flag=wx.ALL | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT,
-                       border=5)
-
-        pageSizer.Add(item=layerSizer,
-                      proportion=3,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=3)
-        
-        pageSizer.Add(item=tableSizer,
-                      proportion=2,
-                      flag=wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND,
-                      border=3)
-        
-        self.addPanel.SetAutoLayout(True)
-        self.addPanel.SetSizer(pageSizer)
-        pageSizer.Fit(self.addPanel)
-        
-    def _createDeletePage(self):
-        """!Delete layer"""
-        self.deletePanel = wx.Panel(parent=self, id=wx.ID_ANY)
-        self.AddPage(page=self.deletePanel, text=_("Remove layer"))
-
-        label = wx.StaticText(parent=self.deletePanel, id=wx.ID_ANY,
-                              label='%s:' % _("Layer to remove"))
-
-        self.deleteLayer = wx.ComboBox(parent=self.deletePanel, id=wx.ID_ANY, size=(100, -1),
-                                       style=wx.CB_SIMPLE | wx.CB_READONLY,
-                                       choices=map(str, self.mapDBInfo.layers.keys()))
-        self.deleteLayer.SetSelection(0)           
-        self.deleteLayer.Bind(wx.EVT_COMBOBOX, self.OnChangeLayer)
-
-        try:
-            tableName = self.mapDBInfo.layers[int(self.deleteLayer.GetStringSelection())]['table']
-        except ValueError:
-            tableName = ''
-            
-        self.deleteTable = wx.CheckBox(parent=self.deletePanel, id=wx.ID_ANY,
-                                       label=_('Drop also linked attribute table (%s)') % \
-                                       tableName)
-
-        if tableName == '':
-            self.deleteLayer.Enable(False)
-            self.deleteTable.Enable(False)
-            
-        btnDelete   = wx.Button(self.deletePanel, wx.ID_DELETE, _("&Remove layer"),
-                                size=(125,-1))
-        btnDelete.Bind(wx.EVT_BUTTON, self.OnDeleteLayer)
-
-        #
-        # do layout
-        #
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-
-        dataSizer = wx.BoxSizer(wx.VERTICAL)
-
-        flexSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
-        flexSizer.AddGrowableCol(2)
-
-        flexSizer.Add(item=label,
-                      flag=wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item=self.deleteLayer,
-                      flag=wx.ALIGN_CENTER_VERTICAL)
-
-        dataSizer.Add(item=flexSizer,
-                      proportion=0,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=1)
-
-        dataSizer.Add(item=self.deleteTable,
-                      proportion=0,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=1)
-
-        pageSizer.Add(item=dataSizer,
-                      proportion=1,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=5)
-
-        pageSizer.Add(item=btnDelete,
-                      proportion=0,
-                      flag=wx.ALL | wx.ALIGN_RIGHT,
-                      border=5)
-
-        self.deletePanel.SetSizer(pageSizer)
-
-    def _createModifyPage(self):
-        """!Modify layer"""
-        self.modifyPanel = wx.Panel(parent=self, id=wx.ID_ANY)
-        self.AddPage(page=self.modifyPanel, text=_("Modify layer"))
-
-        #
-        # list of layer widgets (label, value)
-        #
-        self.modifyLayerWidgets = {'layer':
-                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                      label='%s:' % _("Layer")),
-                                        wx.ComboBox(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                    size=(100, -1),
-                                                    style=wx.CB_SIMPLE | wx.CB_READONLY,
-                                                    choices=map(str, 
-                                                                self.mapDBInfo.layers.keys()))),
-                                   'driver':
-                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                      label='%s:' % _("Driver")),
-                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                  size=(200, -1),
-                                                  choices=self.listOfDrivers)),
-                                   'database':
-                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                      label='%s:' % _("Database")),
-                                        wx.TextCtrl(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                    value='', size=(350, -1),
-                                                    style=wx.TE_PROCESS_ENTER)),
-                                   'table':
-                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                      label='%s:' % _("Table")),
-                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                  size=(200, -1),
-                                                  choices=self.defaultTables)),
-                                   'key':
-                                       (wx.StaticText(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                      label='%s:' % _("Key column")),
-                                        wx.Choice(parent=self.modifyPanel, id=wx.ID_ANY,
-                                                  size=(200, -1),
-                                                  choices=self.defaultColumns))}
-        
-        # set default values for widgets
-        self.modifyLayerWidgets['layer'][1].SetSelection(0)
-        try:
-            layer = int(self.modifyLayerWidgets['layer'][1].GetStringSelection())
-        except ValueError:
-            layer = None
-            for label in self.modifyLayerWidgets.keys():
-                self.modifyLayerWidgets[label][1].Enable(False)
-
-        if layer:
-            driver   = self.mapDBInfo.layers[layer]['driver']
-            database = self.mapDBInfo.layers[layer]['database']
-            table    = self.mapDBInfo.layers[layer]['table']
-
-            listOfColumns = self._getColumns(driver, database, table)
-            self.modifyLayerWidgets['driver'][1].SetStringSelection(driver)
-            self.modifyLayerWidgets['database'][1].SetValue(database)
-            if table in self.modifyLayerWidgets['table'][1].GetItems():
-                self.modifyLayerWidgets['table'][1].SetStringSelection(table)
-            else:
-                if self.defaultConnect['schema'] != '':
-                    table = self.defaultConnect['schema'] + table # try with default schema
-                else:
-                    table = 'public.' + table # try with 'public' schema
-                self.modifyLayerWidgets['table'][1].SetStringSelection(table)
-            self.modifyLayerWidgets['key'][1].SetItems(listOfColumns)
-            self.modifyLayerWidgets['key'][1].SetSelection(0)
-
-        # events
-        self.modifyLayerWidgets['layer'][1].Bind(wx.EVT_COMBOBOX, self.OnChangeLayer)
-        # self.modifyLayerWidgets['driver'][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
-        # self.modifyLayerWidgets['database'][1].Bind(wx.EVT_TEXT_ENTER, self.OnDatabaseChanged)
-        # self.modifyLayerWidgets['table'][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
-
-        btnModify = wx.Button(self.modifyPanel, wx.ID_DELETE, _("&Modify layer"),
-                              size=(125,-1))
-        btnModify.Bind(wx.EVT_BUTTON, self.OnModifyLayer)
-
-        #
-        # do layout
-        #
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-
-        # data area
-        dataSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
-        dataSizer.AddGrowableCol(1)
-        for key in ('layer', 'driver', 'database', 'table', 'key'):
-            label, value = self.modifyLayerWidgets[key]
-            dataSizer.Add(item=label,
-                          flag=wx.ALIGN_CENTER_VERTICAL)
-            if label.GetLabel() == "Layer:":
-                dataSizer.Add(item=value,
-                              flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-            else:
-                dataSizer.Add(item=value,
-                              flag=wx.ALIGN_CENTER_VERTICAL)
-
-        pageSizer.Add(item=dataSizer,
-                      proportion=1,
-                      flag=wx.ALL | wx.EXPAND,
-                      border=5)
-
-        pageSizer.Add(item=btnModify,
-                      proportion=0,
-                      flag=wx.ALL | wx.ALIGN_RIGHT,
-                      border=5)
-
-        self.modifyPanel.SetSizer(pageSizer)
-
-    def _getTables(self, driver, database):
-        """!Get list of tables for given driver and database"""
-        tables = []
-
-        ret = gcmd.RunCommand('db.tables',
-                              parent = self,
-                              read = True,
-                              flags = 'p',
-                              driver = driver,
-                              database = database)
-        
-        if ret is None:
-            wx.MessageBox(parent=self,
-                          message=_("Unable to get list of tables.\n"
-                                    "Please use db.connect to set database parameters."),
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            
-            return tables
-        
-        for table in ret.splitlines():
-            tables.append(table)
-        
-        return tables
-
-    def _getColumns(self, driver, database, table):
-        """!Get list of column of given table"""
-        columns = []
-
-        ret = gcmd.RunCommand('db.columns',
-                              parent = self,
-                              quiet = True,
-                              read = True,
-                              driver = driver,
-                              database = database,
-                              table = table)
-        
-        if ret == None:
-            return columns
-        
-        for column in ret.splitlines():
-            columns.append(column)
-        
-        return columns
-
-    def OnDriverChanged(self, event):
-        """!Driver selection changed, update list of tables"""
-        driver = event.GetString()
-        database = self.addLayerWidgets['database'][1].GetValue()
-
-        winTable = self.addLayerWidgets['table'][1]
-        winKey   = self.addLayerWidgets['key'][1]
-        tables   = self._getTables(driver, database)
-
-        winTable.SetItems(tables)
-        winTable.SetSelection(0)
-
-        if len(tables) == 0:
-            winKey.SetItems([])
-
-        event.Skip()
-
-    def OnDatabaseChanged(self, event):
-        """!Database selection changed, update list of tables"""
-        event.Skip()
-
-    def OnTableChanged(self, event):
-        """!Table name changed, update list of columns"""
-        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
-        database = self.addLayerWidgets['database'][1].GetValue()
-        table    = event.GetString()
-
-        win  = self.addLayerWidgets['key'][1]
-        cols = self._getColumns(driver, database, table)
-        win.SetItems(cols)
-        win.SetSelection(0)
-
-        event.Skip()
-
-    def OnSetDefault(self, event):
-        """!Set default values"""
-        driver   = self.addLayerWidgets['driver'][1]
-        database = self.addLayerWidgets['database'][1]
-        table    = self.addLayerWidgets['table'][1]
-        key      = self.addLayerWidgets['key'][1]
-
-        driver.SetStringSelection(self.defaultConnect['driver'])
-        database.SetValue(self.defaultConnect['database'])
-        tables = self._getTables(self.defaultConnect['driver'],
-                                  self.defaultConnect['database'])
-        table.SetItems(tables)
-        table.SetSelection(0)
-        if len(tables) == 0:
-            key.SetItems([])
-        else:
-            cols = self._getColumns(self.defaultConnect['driver'],
-                                     self.defaultConnect['database'],
-                                     tables[0])
-            key.SetItems(cols)
-            key.SetSelection(0)
-
-        event.Skip()
-
-    def OnCreateTable(self, event):
-        """!Create new table (name and key column given)"""
-        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
-        database = self.addLayerWidgets['database'][1].GetValue()
-        table    = self.tableWidgets['table'][1].GetValue()
-        key      = self.tableWidgets['key'][1].GetValue()
-        
-        if not table or not key:
-            wx.MessageBox(parent=self,
-                          message=_("Unable to create new table. "
-                                    "Table name or key column name is missing."),
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return
-
-        if table in self.addLayerWidgets['table'][1].GetItems():
-            wx.MessageBox(parent=self,
-                          message=_("Unable to create new table. "
-                                    "Table <%s> already exists in the database.") % table,
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return
-        
-        # create table
-        sql = 'CREATE TABLE %s (%s INTEGER)' % (table, key)
-
-        gcmd.RunCommand('db.execute',
-                        quiet = True,
-                        parent = self,
-                        stdin = sql,
-                        input = '-',
-                        driver = driver,
-                        database = database)
-        
-        # update list of tables
-        tableList = self.addLayerWidgets['table'][1]
-        tableList.SetItems(self._getTables(driver, database))
-        tableList.SetStringSelection(table)
-
-        # update key column selection
-        keyList = self.addLayerWidgets['key'][1]
-        keyList.SetItems(self._getColumns(driver, database, table))
-        keyList.SetStringSelection(key)
-        
-        event.Skip()
-
-    def OnAddLayer(self, event):
-        """!Add new layer to vector map"""
-        layer    = int(self.addLayerWidgets['layer'][1].GetValue())
-        layerWin = self.addLayerWidgets['layer'][1]
-        driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
-        database = self.addLayerWidgets['database'][1].GetValue()
-        table    = self.addLayerWidgets['table'][1].GetStringSelection()
-        key      = self.addLayerWidgets['key'][1].GetStringSelection()
-        
-        if layer in self.mapDBInfo.layers.keys():
-            wx.MessageBox(parent=self,
-                          message=_("Unable to add new layer to vector map <%(vector)s>. "
-                                    "Layer %(layer)d already exists.") % 
-                          {'vector' : self.mapDBInfo.map, 'layer' : layer},
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return
-
-        # add new layer
-        ret = gcmd.RunCommand('v.db.connect',
-                              parent = self,
-                              quiet = True,
-                              map = self.mapDBInfo.map,
-                              driver = driver,
-                              database = database,
-                              table = table,
-                              key = key,
-                              layer = layer)
-        
-        # insert records into table if required
-        if self.addLayerWidgets['addCat'][0].IsChecked():
-            gcmd.RunCommand('v.to.db',
-                            parent = self,
-                            quiet = True,
-                            map = self.mapDBInfo.map,
-                            layer = layer,
-                            qlayer = layer,
-                            option = 'cat',
-                            columns = key)
-
-        if ret == 0:
-            # update dialog (only for new layer)
-            self.parentDialog.UpdateDialog(layer=layer) 
-            # update db info
-            self.mapDBInfo = self.parentDialog.mapDBInfo
-            # increase layer number
-            layerWin.SetValue(layer+1)
-
-        if len(self.mapDBInfo.layers.keys()) == 1:
-            # first layer add --- enable previously disabled widgets
-            self.deleteLayer.Enable()
-            self.deleteTable.Enable()
-            for label in self.modifyLayerWidgets.keys():
-                self.modifyLayerWidgets[label][1].Enable()
-            
-    def OnDeleteLayer(self, event):
-        """!Delete layer"""
-        try:
-            layer = int(self.deleteLayer.GetValue())
-        except:
-            return
-
-        gcmd.RunCommand('v.db.connect',
-                        parent = self,
-                        flags = 'd',
-                        map = self.mapDBInfo.map,
-                        layer = layer)
-
-        # drop also table linked to layer which is deleted
-        if self.deleteTable.IsChecked():
-            driver   = self.addLayerWidgets['driver'][1].GetStringSelection()
-            database = self.addLayerWidgets['database'][1].GetValue()
-            table    = self.mapDBInfo.layers[layer]['table']
-            sql      = 'DROP TABLE %s' % (table)
-
-            gcmd.RunCommand('db.execute',
-                            parent = self,
-                            stdin = sql,
-                            quiet = True,
-                            driver = driver,
-                            database = database)
-            
-            # update list of tables
-            tableList = self.addLayerWidgets['table'][1]
-            tableList.SetItems(self._getTables(driver, database))
-            tableList.SetStringSelection(table)
-        
-        # update dialog
-        self.parentDialog.UpdateDialog(layer=layer) 
-        # update db info
-        self.mapDBInfo = self.parentDialog.mapDBInfo
-
-        if len(self.mapDBInfo.layers.keys()) == 0:
-            # disable selected widgets
-            self.deleteLayer.Enable(False)
-            self.deleteTable.Enable(False)
-            for label in self.modifyLayerWidgets.keys():
-                self.modifyLayerWidgets[label][1].Enable(False)
-            
-        event.Skip()
-
-    def OnChangeLayer(self, event):
-        """!Layer number of layer to be deleted is changed"""
-        try:
-            layer = int(event.GetString())
-        except:
-            try:
-                layer = self.mapDBInfo.layers.keys()[0]
-            except:
-                return
-
-        if self.GetCurrentPage() == self.modifyPanel:
-            driver   = self.mapDBInfo.layers[layer]['driver']
-            database = self.mapDBInfo.layers[layer]['database']
-            table    = self.mapDBInfo.layers[layer]['table']
-            listOfColumns = self._getColumns(driver, database, table)
-            self.modifyLayerWidgets['driver'][1].SetStringSelection(driver)
-            self.modifyLayerWidgets['database'][1].SetValue(database)
-            self.modifyLayerWidgets['table'][1].SetStringSelection(table)
-            self.modifyLayerWidgets['key'][1].SetItems(listOfColumns)
-            self.modifyLayerWidgets['key'][1].SetSelection(0)
-        else:
-            self.deleteTable.SetLabel(_('Drop also linked attribute table (%s)') % \
-                                          self.mapDBInfo.layers[layer]['table'])
-        if event:
-            event.Skip()
-
-    def OnModifyLayer(self, event):
-        """!Modify layer connection settings"""
-
-        layer = int(self.modifyLayerWidgets['layer'][1].GetStringSelection())
-
-        modify = False
-        if self.modifyLayerWidgets['driver'][1].GetStringSelection() != \
-                self.mapDBInfo.layers[layer]['driver'] or \
-                self.modifyLayerWidgets['database'][1].GetStringSelection() != \
-                self.mapDBInfo.layers[layer]['database'] or \
-                self.modifyLayerWidgets['table'][1].GetStringSelection() != \
-                self.mapDBInfo.layers[layer]['table'] or \
-                self.modifyLayerWidgets['key'][1].GetStringSelection() != \
-                self.mapDBInfo.layers[layer]['key']:
-            modify = True
-
-        if modify:
-            # delete layer
-            gcmd.RunCommand('v.db.connect',
-                            parent = self,
-                            quiet = True,
-                            flag = 'd',
-                            map = self.mapDBInfo.map,
-                            layer = layer)
-
-            # add modified layer
-            gcmd.RunCommand('v.db.connect',
-                            quiet = True,
-                            map = self.mapDBInfo.map,
-                            driver = self.modifyLayerWidgets['driver'][1].GetStringSelection(),
-                            database = self.modifyLayerWidgets['database'][1].GetValue(),
-                            table = self.modifyLayerWidgets['table'][1].GetStringSelection(),
-                            key = self.modifyLayerWidgets['key'][1].GetStringSelection(),
-                            layer = int(layer))
-            
-            # update dialog (only for new layer)
-            self.parentDialog.UpdateDialog(layer=layer) 
-            # update db info
-            self.mapDBInfo = self.parentDialog.mapDBInfo
-
-        event.Skip()
-
-def main(argv = None):
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
-    
-    if argv is None:
-        argv = sys.argv
-    
-    if len(argv) != 2:
-        print >> sys.stderr, __doc__
-        sys.exit()
-    
-    #some applications might require image handlers
-    wx.InitAllImageHandlers()
-    
-    app = wx.PySimpleApp()
-    f = AttributeManager(parent=None, id=wx.ID_ANY,
-                         title="%s - <%s>" % (_("GRASS GIS Attribute Table Manager"),
-                                              argv[1]),
-                         size=(900,600), vectorName=argv[1])
-    f.Show()
-    
-    app.MainLoop()
-    
-if __name__ == '__main__':
-    main()

Deleted: grass/trunk/gui/wxpython/gui_modules/dbm_base.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/dbm_base.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/dbm_base.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,165 +0,0 @@
-"""
- at package dbm_base.py
-
- at brief Support classes for dbm.py
-
-List of classes:
- - VectorDBInfo
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import types
-
-import wx
-
-import gselect
-import gcmd
-from preferences import globalSettings as UserSettings
-
-import grass.script as grass
-
-def unicodeValue(value):
-    """!Encode value"""
-    if type(value) == types.UnicodeType:
-        return value
-    
-    enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
-    if enc:
-        value = unicode(value, enc)
-    elif 'GRASS_DB_ENCODING' in os.environ:
-        value = unicode(value, os.environ['GRASS_DB_ENCODING'])
-    else:
-        try:
-            value = unicode(value, 'ascii')
-        except UnicodeDecodeError:
-            value = _("Unable to decode value. Set encoding in GUI preferences ('Attributes').")
-    
-    return value
-
-def createDbInfoDesc(panel, mapDBInfo, layer):
-    """!Create database connection information content"""
-    infoFlexSizer = wx.FlexGridSizer (cols = 2, hgap = 1, vgap = 1)
-    infoFlexSizer.AddGrowableCol(1)
-    
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "Driver:"))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = mapDBInfo.layers[layer]['driver']))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "Database:"))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = mapDBInfo.layers[layer]['database']))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "Table:"))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = mapDBInfo.layers[layer]['table']))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "Key:"))
-    infoFlexSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = mapDBInfo.layers[layer]['key']))
-    
-    return infoFlexSizer
-        
-class VectorDBInfo(gselect.VectorDBInfo):
-    """!Class providing information about attribute tables
-    linked to the vector map"""
-    def __init__(self, map):
-        gselect.VectorDBInfo.__init__(self, map)
-        
-    def GetColumns(self, table):
-        """!Return list of columns names (based on their index)"""
-        try:
-            names = [''] * len(self.tables[table].keys())
-        except KeyError:
-            return []
-        
-        for name, desc in self.tables[table].iteritems():
-            names[desc['index']] = name
-        
-        return names
-
-    def SelectByPoint(self, queryCoords, qdist):
-        """!Get attributes by coordinates (all available layers)
-
-        Return line id or None if no line is found"""
-        line = None
-        nselected = 0
-
-        data = grass.vector_what(map = self.map,
-                                 coord = (float(queryCoords[0]), float(queryCoords[1])),
-                                 distance = float(qdist))
-
-        if len(data) < 1 or 'Table' not in data[0]:
-            return None
-        
-        # process attributes
-        table = data[0]['Table']
-        for key, value in data[0]['Attributes'].iteritems():
-            if len(value) < 1:
-                value = None
-            else:
-                if self.tables[table][key]['ctype'] != types.StringType:
-                    value = self.tables[table][key]['ctype'] (value)
-                else:
-                    value = unicodeValue(value)
-            self.tables[table][key]['values'].append(value)
-        
-        ret = dict()
-        for key, value in data[0].iteritems():
-            if key == 'Attributes':
-                continue
-            ret[key] = list()
-            ret[key].append(value)
-        
-        return ret
-    
-    def SelectFromTable(self, layer, cols = '*', where = None):
-        """!Select records from the table
-
-        Return number of selected records, -1 on error
-        """
-        if layer <= 0:
-            return -1
-
-        nselected = 0
-
-        table = self.layers[layer]["table"] # get table desc
-        # select values (only one record)
-        if where is None or where is '':
-            sql = "SELECT %s FROM %s" % (cols, table)
-        else:
-            sql = "SELECT %s FROM %s WHERE %s" % (cols, table, where)
-        
-        ret = gcmd.RunCommand('db.select',
-                              parent = self,
-                              read = True,
-                              quiet = True,
-                              flags = 'v',
-                              sql= sql,
-                              database = self.layers[layer]["database"],
-                              driver = self.layers[layer]["driver"])
-        
-        # self.tables[table][key][1] = str(cat)
-        if ret:
-            for line in ret.splitlines():
-                name, value = line.split('|')
-                # casting ...
-                if value:
-                    if self.tables[table][name]['ctype'] != type(''):
-                        value = self.tables[table][name]['ctype'] (value)
-                    else:
-                        value = unicodeValue(value)
-                else:
-                    value = None
-                self.tables[table][name]['values'].append(value)
-                nselected = 1
-
-        return nselected

Deleted: grass/trunk/gui/wxpython/gui_modules/dbm_dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/dbm_dialogs.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/dbm_dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,670 +0,0 @@
-"""!
- at package dbm_dialogs.py
-
- at brief DBM-related dialogs
-
-List of classes:
- - DisplayAttributesDialog
- - ModifyTableRecord
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-
-import globalvar
-import wx
-import wx.lib.scrolledpanel as scrolled
-
-import gcmd
-from debug import Debug
-from preferences import globalSettings as UserSettings
-from dbm_base    import VectorDBInfo
-
-class DisplayAttributesDialog(wx.Dialog):
-    def __init__(self, parent, map,
-                 query = None, cats = None, line = None,
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
-                 pos = wx.DefaultPosition,
-                 action = "add", ignoreError = False):
-        """!Standard dialog used to add/update/display attributes linked
-        to the vector map.
-        
-        Attribute data can be selected based on layer and category number
-        or coordinates.
-        
-        @param parent
-        @param map vector map
-        @param query query coordinates and distance (used for v.edit)
-        @param cats {layer: cats}
-        @param line feature id (requested for cats)
-        @param style
-        @param pos
-        @param action (add, update, display)
-        @param ignoreError True to ignore errors
-        """
-        self.parent = parent # mapdisplay.BufferedWindow
-        self.map    = map
-        self.action = action
-
-        # ids/cats of selected features
-        # fid : {layer : cats}
-        self.cats = {}
-        self.fid = -1 # feature id
-        
-        # get layer/table/column information
-        self.mapDBInfo = VectorDBInfo(self.map)
-        
-        layers = self.mapDBInfo.layers.keys() # get available layers
-
-        # check if db connection / layer exists
-        if len(layers) <= 0:
-            if not ignoreError:
-                dlg = wx.MessageDialog(parent = self.parent,
-                                       message = _("No attribute table found.\n\n"
-                                                   "Do you want to create a new attribute table "
-                                                   "and defined a link to vector map <%s>?") % self.map,
-                                       caption = _("Create table?"),
-                                       style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
-                if dlg.ShowModal() == wx.ID_YES:
-                    lmgr = self.parent.lmgr
-                    lmgr.OnShowAttributeTable(event = None, selection = 'layers')
-                
-                dlg.Destroy()
-            
-            self.mapDBInfo = None
-        
-        wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY,
-                           title = "", style = style, pos = pos)
-
-        # dialog body
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-
-        # notebook
-        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-
-        self.closeDialog = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                       label = _("Close dialog on submit"))
-        self.closeDialog.SetValue(True)
-        if self.action == 'display':
-            self.closeDialog.Enable(False)
-        
-        # feature id (text/choice for duplicates)
-        self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
-                                  size = (150, -1))
-        self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
-        self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
-
-        self.noFoundMsg = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                        label = _("No attributes found"))
-        
-        self.UpdateDialog(query = query, cats = cats)
-
-        # set title
-        if self.action == "update":
-            self.SetTitle(_("Update attributes"))
-        elif self.action == "add":
-            self.SetTitle(_("Define attributes"))
-        else:
-            self.SetTitle(_("Display attributes"))
-
-        # buttons
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnReset  = wx.Button(self, wx.ID_UNDO, _("&Reload"))
-        btnSubmit = wx.Button(self, wx.ID_OK, _("&Submit"))
-        if self.action == 'display':
-            btnSubmit.Enable(False)
-        
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        btnSizer.AddButton(btnReset)
-        btnSizer.SetNegativeButton(btnReset)
-        btnSubmit.SetDefault()
-        btnSizer.AddButton(btnSubmit)
-        btnSizer.Realize()
-
-        mainSizer.Add(item = self.noFoundMsg, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = self.notebook, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        fidSizer = wx.BoxSizer(wx.HORIZONTAL)
-        fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                        label = _("Feature id:")),
-                     proportion = 0, border = 5,
-                     flag = wx.ALIGN_CENTER_VERTICAL)
-        fidSizer.Add(item = self.fidMulti, proportion = 0,
-                     flag = wx.EXPAND | wx.ALL,  border = 5)
-        fidSizer.Add(item = self.fidText, proportion = 0,
-                     flag = wx.EXPAND | wx.ALL,  border = 5)
-        mainSizer.Add(item = fidSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
-        mainSizer.Add(item = self.closeDialog, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
-                      border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        # bindigs
-        btnReset.Bind(wx.EVT_BUTTON, self.OnReset)
-        btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit)
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-        # set min size for dialog
-        w, h = self.GetBestSize()
-        if h < 200:
-            self.SetMinSize((w, 200))
-        else:
-            self.SetMinSize(self.GetBestSize())
-
-        if self.notebook.GetPageCount() == 0:
-            Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
-            ### self.mapDBInfo = None
-        
-    def OnSQLStatement(self, event):
-        """!Update SQL statement"""
-        pass
-
-    def IsFound(self):
-        """!Check for status
-
-        @return True on attributes found
-        @return False attributes not found
-        """
-        return bool(self.mapDBInfo and self.notebook.GetPageCount() > 0)
-    
-    def GetSQLString(self, updateValues = False):
-        """!Create SQL statement string based on self.sqlStatement
-
-        If updateValues is True, update dataFrame according to values
-        in textfields.
-        """
-        sqlCommands = []
-        # find updated values for each layer/category
-        for layer in self.mapDBInfo.layers.keys(): # for each layer
-            table = self.mapDBInfo.GetTable(layer)
-            key = self.mapDBInfo.GetKeyColumn(layer)
-            columns = self.mapDBInfo.GetTableDesc(table)
-            for idx in range(len(columns[key]['values'])): # for each category
-                updatedColumns = []
-                updatedValues = []
-                for name in columns.keys():
-                    if name == key:
-                        cat = columns[name]['values'][idx]
-                        continue
-                    type  = columns[name]['type']
-                    value = columns[name]['values'][idx]
-                    id    = columns[name]['ids'][idx]
-                    try:
-                        newvalue = self.FindWindowById(id).GetValue()
-                    except:
-                        newvalue = self.FindWindowById(id).GetLabel()
-
-                    if newvalue == '':
-                        newvalue = None
-                    
-                    if newvalue != value:
-                        updatedColumns.append(name)
-                        if newvalue is None:
-                            updatedValues.append('NULL')
-                        else:
-                            if type != 'character':
-                                updatedValues.append(newvalue)
-                            else:
-                                updatedValues.append("'" + newvalue + "'")
-                        columns[name]['values'][idx] = newvalue
-
-                if self.action != "add" and len(updatedValues) == 0:
-                    continue
-
-                if self.action == "add":
-                    sqlString = "INSERT INTO %s (%s," % (table, key)
-                else:
-                    sqlString = "UPDATE %s SET " % table
-
-                for idx in range(len(updatedColumns)):
-                    name = updatedColumns[idx]
-                    if self.action == "add":
-                        sqlString += name + ","
-                    else:
-                        sqlString += name + "=" + updatedValues[idx] + ","
-
-                sqlString = sqlString[:-1] # remove last comma
-
-                if self.action == "add":
-                    sqlString += ") VALUES (%s," % cat
-                    for value in updatedValues:
-                        sqlString += str(value) + ","
-                    sqlString = sqlString[:-1] # remove last comma
-                    sqlString += ")"
-                else:
-                    sqlString += " WHERE %s=%s" % (key, cat)
-                sqlCommands.append(sqlString)
-            # for each category
-        # for each layer END
-
-        Debug.msg(3, "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
-
-        return sqlCommands
-
-    def OnReset(self, event = None):
-        """!Reset form"""
-        for layer in self.mapDBInfo.layers.keys():
-            table = self.mapDBInfo.layers[layer]["table"]
-            key = self.mapDBInfo.layers[layer]["key"]
-            columns = self.mapDBInfo.tables[table]
-            for idx in range(len(columns[key]['values'])):
-                for name in columns.keys():
-                    type  = columns[name]['type']
-                    value = columns[name]['values'][idx]
-                    if value is None:
-                        value = ''
-                    try:
-                        id = columns[name]['ids'][idx]
-                    except IndexError:
-                        id = wx.NOT_FOUND
-                    
-                    if name != key and id != wx.NOT_FOUND:
-                        self.FindWindowById(id).SetValue(str(value))
-
-    def OnCancel(self, event):
-        """!Cancel button pressed
-        """
-        self.parent.parent.dialogs['attributes'] = None
-        
-        if hasattr(self, "digit"):
-            self.parent.digit.GetDisplay().SetSelected([])
-            self.parent.UpdateMap(render = False)
-        else:
-            self.parent.parent.OnRender(None)
-        
-        self.Close()
-
-    def OnSubmit(self, event):
-        """!Submit records"""
-        layer = 1
-        for sql in self.GetSQLString(updateValues = True):
-            enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
-            if not enc and 'GRASS_DB_ENCODING' in os.environ:
-                enc = os.environ['GRASS_DB_ENCODING']
-            if enc:
-                sql = sql.encode(enc)
-
-            driver, database = self.mapDBInfo.GetDbSettings(layer)
-            Debug.msg(1, "SQL: %s" % sql)
-            gcmd.RunCommand('db.execute',
-                            parent = self,
-                            quiet = True,
-                            input = '-',
-                            stdin = sql,
-                            driver = driver,
-                            database = database)
-            
-            layer += 1
-        
-        if self.closeDialog.IsChecked():
-            self.OnCancel(event)
-
-    def OnFeature(self, event):
-        self.fid = int(event.GetString())
-        self.UpdateDialog(cats = self.cats, fid = self.fid)
-        
-    def GetCats(self):
-        """!Get id of selected vector object or 'None' if nothing selected
-
-        @param id if true return ids otherwise cats
-        """
-        if self.fid < 0:
-            return None
-        
-        return self.cats[self.fid]
-
-    def GetFid(self):
-        """!Get selected feature id"""
-        return self.fid
-    
-    def UpdateDialog(self, map = None, query = None, cats = None, fid = -1,
-                     action = None):
-        """!Update dialog
-        
-        @param map name of vector map
-        @param query
-        @param cats
-        @param fid feature id
-        @param action add, update, display or None
-        
-        @return True if updated
-        @return False
-        """
-        if action:
-            self.action = action
-            if action == 'display':
-                enabled = False
-            else:
-                enabled = True
-            self.closeDialog.Enable(enabled)
-            self.FindWindowById(wx.ID_OK).Enable(enabled)
-        
-        if map:
-            self.map = map
-            # get layer/table/column information
-            self.mapDBInfo = VectorDBInfo(self.map)
-        
-        if not self.mapDBInfo:
-            return False
-        
-        self.mapDBInfo.Reset()
-        
-        layers = self.mapDBInfo.layers.keys() # get available layers
-        
-        # id of selected line
-        if query: # select by position
-            data = self.mapDBInfo.SelectByPoint(query[0],
-                                                query[1])
-            self.cats = {}
-            if data and 'Layer' in data:
-                idx = 0
-                for layer in data['Layer']:
-                    layer = int(layer)
-                    if 'Id' in data:
-                        tfid = int(data['Id'][idx])
-                    else:
-                        tfid = 0 # Area / Volume
-                    if not tfid in self.cats:
-                        self.cats[tfid] = {}
-                    if not layer in self.cats[tfid]:
-                        self.cats[tfid][layer] = []
-                    cat = int(data['Category'][idx])
-                    self.cats[tfid][layer].append(cat)
-                    idx += 1
-        else:
-            self.cats = cats
-        
-        if fid > 0:
-            self.fid = fid
-        elif len(self.cats.keys()) > 0:
-            self.fid = self.cats.keys()[0]
-        else:
-            self.fid = -1
-        
-        if len(self.cats.keys()) == 1:
-            self.fidMulti.Show(False)
-            self.fidText.Show(True)
-            if self.fid > 0:
-                self.fidText.SetLabel("%d" % self.fid)
-            else:
-                self.fidText.SetLabel(_("Unknown"))
-        else:
-            self.fidMulti.Show(True)
-            self.fidText.Show(False)
-            choices = []
-            for tfid in self.cats.keys():
-                choices.append(str(tfid))
-            self.fidMulti.SetItems(choices)
-            self.fidMulti.SetStringSelection(str(self.fid))
-        
-        # reset notebook
-        self.notebook.DeleteAllPages()
-        
-        for layer in layers: # for each layer
-            if not query: # select by layer/cat
-                if self.fid > 0 and layer in self.cats[self.fid]:
-                    for cat in self.cats[self.fid][layer]:
-                        nselected = self.mapDBInfo.SelectFromTable(layer,
-                                                                   where = "%s=%d" % \
-                                                                   (self.mapDBInfo.layers[layer]['key'],
-                                                                    cat))
-                else:
-                    nselected = 0
-            
-            # if nselected <= 0 and self.action != "add":
-            #    continue # nothing selected ...
-            
-            if self.action == "add":
-                if nselected <= 0:
-                    if layer in self.cats[self.fid]:
-                        table = self.mapDBInfo.layers[layer]["table"]
-                        key = self.mapDBInfo.layers[layer]["key"]
-                        columns = self.mapDBInfo.tables[table]
-                        for name in columns.keys():
-                            if name == key:
-                                for cat in self.cats[self.fid][layer]:
-                                    self.mapDBInfo.tables[table][name]['values'].append(cat)
-                            else:
-                                self.mapDBInfo.tables[table][name]['values'].append(None)
-                else: # change status 'add' -> 'update'
-                    self.action = "update"
-            
-            table   = self.mapDBInfo.layers[layer]["table"]
-            key   = self.mapDBInfo.layers[layer]["key"]
-            columns = self.mapDBInfo.tables[table]
-            
-            for idx in range(len(columns[key]['values'])):
-                for name in columns.keys():
-                    if name == key:
-                        cat = int(columns[name]['values'][idx])
-                        break
-
-                # use scrolled panel instead (and fix initial max height of the window to 480px)
-                panel = scrolled.ScrolledPanel(parent = self.notebook, id = wx.ID_ANY,
-                                               size = (-1, 150))
-                panel.SetupScrolling(scroll_x = False)
-                
-                self.notebook.AddPage(page = panel, text = " %s %d / %s %d" % (_("Layer"), layer,
-                                                                           _("Category"), cat))
-                
-                # notebook body
-                border = wx.BoxSizer(wx.VERTICAL)
-                
-                flexSizer = wx.FlexGridSizer (cols = 4, hgap = 3, vgap = 3)
-                flexSizer.AddGrowableCol(3)
-                # columns (sorted by index)
-                names = [''] * len(columns.keys())
-                for name in columns.keys():
-                    names[columns[name]['index']] = name
-                
-                for name in names:
-                    if name == key: # skip key column (category)
-                        continue
-                    
-                    vtype  = columns[name]['type']
-                    
-                    if columns[name]['values'][idx] is not None:
-                        if columns[name]['ctype'] != type(''):
-                            value = str(columns[name]['values'][idx])
-                        else:
-                            value = columns[name]['values'][idx]
-                    else:
-                        value = ''
-                    
-                    colName = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                            label = name)
-                    colType = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                            label = "[" + vtype.lower() + "]")
-                    delimiter = wx.StaticText(parent = panel, id = wx.ID_ANY, label = ":")
-                    
-                    colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
-                    colValue.SetName(name)
-                    self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
-                    if self.action == 'display':
-                        colValue.SetWindowStyle(wx.TE_READONLY)
-                    
-                    flexSizer.Add(colName, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-                    flexSizer.Add(colType, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-                    flexSizer.Add(delimiter, proportion = 0,
-                                  flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-                    flexSizer.Add(colValue, proportion = 1,
-                                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-                    # add widget reference to self.columns
-                    columns[name]['ids'].append(colValue.GetId()) # name, type, values, id
-                # for each attribute (including category) END
-                border.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-                panel.SetSizer(border)
-            # for each category END
-        # for each layer END
-        
-        if self.notebook.GetPageCount() == 0:
-            self.noFoundMsg.Show(True)
-        else:
-            self.noFoundMsg.Show(False)
-        
-        self.Layout()
-        
-        return True
-
-    def SetColumnValue(self, layer, column, value):
-        """!Set attrbute value
-
-        @param column column name
-        @param value value
-        """
-        table = self.mapDBInfo.GetTable(layer)
-        columns = self.mapDBInfo.GetTableDesc(table)
-        
-        for key, col in columns.iteritems():
-            if key == column:
-                col['values'] = [col['ctype'](value),]
-                break
-        
-class ModifyTableRecord(wx.Dialog):
-    def __init__(self, parent, title, data, keyEditable = (-1, True),
-                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        """!Dialog for inserting/updating table record
-        
-        @param data a list: [(column, value)]
-        @param KeyEditable (id, editable?) indicates if textarea for key column
-        is editable(True) or not
-        """
-        # parent -> VDigitWindow
-        wx.Dialog.__init__(self, parent, id, title, style = style)
-        
-        self.CenterOnParent()
-        
-        self.keyId = keyEditable[0]
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY)
-        box.Hide()
-        self.dataPanel = scrolled.ScrolledPanel(parent = self.panel, id = wx.ID_ANY,
-                                                style = wx.TAB_TRAVERSAL)
-        self.dataPanel.SetupScrolling(scroll_x = False)
-        
-        # buttons
-        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
-        self.btnSubmit = wx.Button(self.panel, wx.ID_OK, _("&Submit"))
-        self.btnSubmit.SetDefault()
-        
-        # data area
-        self.widgets = []
-        cId = 0
-        self.usebox = False
-        self.cat = None
-        winFocus = False
-        for column, value in data:
-            if self.keyId == cId:
-                self.cat = int(value)
-                if not keyEditable[1]:
-                    self.usebox = True
-                    box.SetLabel(" %s %d " % (_("Category"), self.cat))
-                    box.Show()
-                    self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-                    cId += 1
-                    continue
-                else:
-                    valueWin = wx.SpinCtrl(parent = self.dataPanel, id = wx.ID_ANY,
-                                           value = value, min = -1e9, max = 1e9, size = (250, -1))
-            else:
-                valueWin = wx.TextCtrl(parent = self.dataPanel, id = wx.ID_ANY,
-                                       value = value, size = (250, -1))
-                if not winFocus:
-                    wx.CallAfter(valueWin.SetFocus)
-                    winFocus = True
-            
-            label = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
-                                  label = column + ":")
-            
-            self.widgets.append((label.GetId(), valueWin.GetId()))
-            
-            cId += 1
-        
-        self._layout()
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # data area
-        dataSizer = wx.FlexGridSizer (cols = 2, hgap = 3, vgap = 3)
-        dataSizer.AddGrowableCol(1)
-        
-        for labelId, valueId in self.widgets:
-            label = self.FindWindowById(labelId)
-            value = self.FindWindowById(valueId)
-            
-            dataSizer.Add(label, proportion = 0,
-                          flag = wx.ALIGN_CENTER_VERTICAL)
-            dataSizer.Add(value, proportion = 0,
-                          flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-        
-        self.dataPanel.SetAutoLayout(True)
-        self.dataPanel.SetSizer(dataSizer)
-        dataSizer.Fit(self.dataPanel)
-        
-        if self.usebox:
-            self.boxSizer.Add(item = self.dataPanel, proportion = 1,
-                              flag = wx.EXPAND | wx.ALL, border = 5)
-            
-        # buttons
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnSubmit)
-        btnSizer.Realize()
-        
-        if not self.usebox:
-            sizer.Add(item = self.dataPanel, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        else:
-            sizer.Add(item = self.boxSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL, border = 5)
-        
-        framewidth = self.GetSize()[0]
-        self.SetMinSize((framewidth,150))
-        self.SetMaxSize((framewidth,300))
-        
-        # sizer.SetSizeHints(self.panel)
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        
-        self.Layout()
-        
-    def GetValues(self, columns = None):
-        """!Return list of values (casted to string).
-        
-        If columns is given (list), return only values of given columns.
-        """
-        valueList = []
-        for labelId, valueId in self.widgets:
-            column = self.FindWindowById(labelId).GetLabel().replace(':', '')
-            if columns is None or column in columns:
-                value = str(self.FindWindowById(valueId).GetValue())
-                valueList.append(value)
-        
-        # add key value
-        if self.usebox:
-            valueList.insert(self.keyId, str(self.cat))
-                             
-        return valueList

Deleted: grass/trunk/gui/wxpython/gui_modules/debug.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/debug.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/debug.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,77 +0,0 @@
-"""!
- at package debug
-
- at brief Debugging
-
-Classes:
- - DebugMsg
-
- at code
-from debug import Debug as Debug
-Debug.msg (3, 'debug message')
- at endcode
-         
-COPYRIGHT: (C) 2007-2009, 2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-
-import globalvar
-
-import grass.script as grass
-
-class DebugMsg:
-    """!wxGUI debugging
-
-    @code
-    g.gisenv set=WX_DEBUG=[0-5]
-    @endcode
-    """
-    def __init__(self):
-        # default level
-        self.debuglevel = 0
-        
-        self.SetLevel()
-
-    def SetLevel(self):
-        """!Initialize gui debug level
-        """
-        self.debuglevel = int(grass.gisenv().get('WX_DEBUG', 0))
-        
-    def msg(self, level, message, *args):
-        """!Print debug message
-
-        @param level debug level (0-5)
-        @param message message to be printed
-        @param *args formatting params
-        """
-        # self.SetLevel()
-        if self.debuglevel > 0 and level > 0 and level <= self.debuglevel:
-            if args:
-                sys.stderr.write("GUI D%d/%d: " % (level, self.debuglevel) + \
-                    message % args + os.linesep)
-            else:
-                sys.stderr.write("GUI D%d/%d: " % (level, self.debuglevel) + \
-                                     message + os.linesep)
-            sys.stderr.flush() # force flush (required for MS Windows)
-        
-    def GetLevel(self):
-        """!Return current GUI debug level"""
-        return self.debuglevel
-
-# Debug instance
-Debug = DebugMsg()
-
-# testing
-if __name__ == "__main__":
-    import gcmd
-    gcmd.RunCommand('g.gisenv',
-                    set = 'DEBUG=3')
-                
-    for level in range (4):
-        Debug.msg (level, "message level=%d" % level)

Deleted: grass/trunk/gui/wxpython/gui_modules/disp_print.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/disp_print.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/disp_print.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,158 +0,0 @@
-"""
-MODULE:     disp_print.py
-
-CLASSES:
-    * MapPrint
-    * PrintOptions
-
-PURPOSE:    Print context and utility functions for printing
-            contents of map display window.
-
-AUTHORS:    The GRASS Development Team
-            Michael Barton (Arizona State University)
-            Based on generic example code from wxPython
-            demo program by Robin Dunn
-
-COPYRIGHT:  (C) 2007 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.
-
-"""
-
-import  wx
-
-
-class MapPrint(wx.Printout):
-    def __init__(self, canvas):
-        wx.Printout.__init__(self)
-        self.canvas = canvas
-
-    def OnBeginDocument(self, start, end):
-        return super(MapPrint, self).OnBeginDocument(start, end)
-
-    def OnEndDocument(self):
-        super(MapPrint, self).OnEndDocument()
-
-    def OnBeginPrinting(self):
-        super(MapPrint, self).OnBeginPrinting()
-
-    def OnEndPrinting(self):
-        super(MapPrint, self).OnEndPrinting()
-
-    def OnPreparePrinting(self):
-        super(MapPrint, self).OnPreparePrinting()
-
-    def HasPage(self, page):
-        if page <= 2:
-            return True
-        else:
-            return False
-
-    def GetPageInfo(self):
-        return (1, 2, 1, 2)
-
-    def OnPrintPage(self, page):
-        dc = self.GetDC()
-
-        #-------------------------------------------
-        # One possible method of setting scaling factors...
-        maxX, maxY = self.canvas.GetSize()
-
-        # Let's have at least 50 device units margin
-        marginX = 10
-        marginY = 10
-
-        # Add the margin to the graphic size
-        maxX = maxX + (2 * marginX)
-        maxY = maxY + (2 * marginY)
-
-        # Get the size of the DC in pixels
-        (w, h) = dc.GetSizeTuple()
-
-        # Calculate a suitable scaling factor
-        scaleX = float(w) / maxX
-        scaleY = float(h) / maxY
-
-        # Use x or y scaling factor, whichever fits on the DC
-        actualScale = min(scaleX, scaleY)
-
-        # Calculate the position on the DC for centering the graphic
-        posX = (w - (self.canvas.GetSize()[0] * actualScale)) / 2.0
-        posY = (h - (self.canvas.GetSize()[1] * actualScale)) / 2.0
-
-        # Set the scale and origin
-        dc.SetUserScale(actualScale, actualScale)
-        dc.SetDeviceOrigin(int(posX), int(posY))
-
-        #-------------------------------------------
-
-        self.canvas.pdc.DrawToDC(dc)
-
-        # prints a page number on the page
-#        dc.DrawText("Page: %d" % page, marginX/2, maxY-marginY)
-
-        return True
-
-class PrintOptions:
-    def __init__(self, parent, mapwin):
-        self.mapframe = parent
-        self.mapwin = mapwin
-	#self.frame = frame
-
-	self.printData = None
-
-	#self.canvas = ScrolledWindow.MyCanvas(self)
-
-    def setup(self):
-	if self.printData:
-	    return
-        self.printData = wx.PrintData()
-        self.printData.SetPaperId(wx.PAPER_LETTER)
-        self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
-
-    def OnPageSetup(self, event):
-	self.setup()
-        psdd = wx.PageSetupDialogData(self.printData)
-        psdd.CalculatePaperSizeFromId()
-        dlg = wx.PageSetupDialog(self.mapwin, psdd)
-        dlg.ShowModal()
-
-        # this makes a copy of the wx.PrintData instead of just saving
-        # a reference to the one inside the PrintDialogData that will
-        # be destroyed when the dialog is destroyed
-        self.printData = wx.PrintData( dlg.GetPageSetupData().GetPrintData() )
-
-        dlg.Destroy()
-
-    def OnPrintPreview(self, event):
-	self.setup()
-        data = wx.PrintDialogData(self.printData)
-        printout = MapPrint(self.mapwin)
-        printout2 = MapPrint(self.mapwin)
-        self.preview = wx.PrintPreview(printout, printout2, data)
-
-        if not self.preview.Ok():
-            wx.MessageBox("There was a problem printing this display\n", wx.OK)
-            return
-
-        pfrm = wx.PreviewFrame(self.preview, self.mapframe, "Print preview")
-
-        pfrm.Initialize()
-        pfrm.SetPosition(self.mapframe.GetPosition())
-        pfrm.SetSize(self.mapframe.GetClientSize())
-        pfrm.Show(True)
-
-    def OnDoPrint(self, event):
-	self.setup()
-        pdd = wx.PrintDialogData(self.printData)
-        # set number of pages/copies
-        pdd.SetToPage(1)
-        printer = wx.Printer(pdd)
-        printout = MapPrint(self.mapwin)
-
-        if not printer.Print(self.mapframe, printout, True):
-            wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
-        else:
-            self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
-        printout.Destroy()

Deleted: grass/trunk/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gcmd.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gcmd.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,645 +0,0 @@
-"""!
- at package gcmd
-
- at brief wxGUI command interface
-
-Classes:
- - GError
- - GWarning
- - GMessage
- - GException
- - Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
- - Command
- - CommandThread
-
-Functions:
- - RunCommand
-
-(C) 2007-2008, 2010-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import time
-import errno
-import signal
-import locale
-import traceback
-import types
-import time
-
-import wx
-
-try:
-    import subprocess
-except:
-    compatPath = os.path.join(globalvar.ETCWXDIR, "compat")
-    sys.path.append(compatPath)
-    import subprocess
-if subprocess.mswindows:
-    from win32file import ReadFile, WriteFile
-    from win32pipe import PeekNamedPipe
-    import msvcrt
-else:
-    import select
-    import fcntl
-from threading import Thread
-
-import globalvar
-grassPath = os.path.join(globalvar.ETCDIR, "python")
-sys.path.append(grassPath)
-from grass.script import core as grass
-
-import utils
-from debug import Debug as Debug
-
-class GError:
-    def __init__(self, message, parent = None, caption = None, showTraceback = True):
-        if not caption:
-            caption = _('Error')
-        style = wx.OK | wx.ICON_ERROR | wx.CENTRE
-        exc_type, exc_value, exc_traceback = sys.exc_info()
-        if exc_traceback:
-            exception = traceback.format_exc()
-            reason = exception.splitlines()[-1].split(':', 1)[-1].strip()
-        
-        if Debug.GetLevel() > 0 and exc_traceback:
-            sys.stderr.write(exception)
-        
-        if showTraceback and exc_traceback:
-            wx.MessageBox(parent = parent,
-                          message = message + '\n\n%s: %s\n\n%s' % \
-                              (_('Reason'),
-                               reason, exception),
-                          caption = caption,
-                          style = style)
-        else:
-            wx.MessageBox(parent = parent,
-                          message = message,
-                          caption = caption,
-                          style = style)
-
-class GWarning:
-    def __init__(self, message, parent = None):
-        caption = _('Warning')
-        style = wx.OK | wx.ICON_WARNING | wx.CENTRE
-        wx.MessageBox(parent = parent,
-                      message = message,
-                      caption = caption,
-                      style = style)
-        
-class GMessage:
-    def __init__(self, message, parent = None):
-        caption = _('Message')
-        style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE
-        wx.MessageBox(parent = parent,
-                      message = message,
-                      caption = caption,
-                      style = style)
-
-class GException(Exception):
-    def __init__(self, value = ''):
-        self.value = value
-
-    def __str__(self):
-        return str(self.value)
-
-class Popen(subprocess.Popen):
-    """!Subclass subprocess.Popen"""
-    def __init__(self, args, **kwargs):
-        if subprocess.mswindows:
-            args = map(utils.EncodeString, args)
-        
-        subprocess.Popen.__init__(self, args, **kwargs)
-        
-    def recv(self, maxsize = None):
-        return self._recv('stdout', maxsize)
-    
-    def recv_err(self, maxsize = None):
-        return self._recv('stderr', maxsize)
-
-    def send_recv(self, input = '', maxsize = None):
-        return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
-
-    def get_conn_maxsize(self, which, maxsize):
-        if maxsize is None:
-            maxsize = 1024
-        elif maxsize < 1:
-            maxsize = 1
-        return getattr(self, which), maxsize
-    
-    def _close(self, which):
-        getattr(self, which).close()
-        setattr(self, which, None)
-
-    def kill(self):
-        """!Try to kill running process"""
-        if subprocess.mswindows:
-            import win32api
-            handle = win32api.OpenProcess(1, 0, self.pid)
-            return (0 != win32api.TerminateProcess(handle, 0))
-	else:
-            try:
-                os.kill(-self.pid, signal.SIGTERM) # kill whole group
-            except OSError:
-                pass
-
-    if subprocess.mswindows:
-        def send(self, input):
-            if not self.stdin:
-                return None
-
-            try:
-                x = msvcrt.get_osfhandle(self.stdin.fileno())
-                (errCode, written) = WriteFile(x, input)
-            except ValueError:
-                return self._close('stdin')
-            except (subprocess.pywintypes.error, Exception), why:
-                if why[0] in (109, errno.ESHUTDOWN):
-                    return self._close('stdin')
-                raise
-
-            return written
-
-        def _recv(self, which, maxsize):
-            conn, maxsize = self.get_conn_maxsize(which, maxsize)
-            if conn is None:
-                return None
-            
-            try:
-                x = msvcrt.get_osfhandle(conn.fileno())
-                (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
-                if maxsize < nAvail:
-                    nAvail = maxsize
-                if nAvail > 0:
-                    (errCode, read) = ReadFile(x, nAvail, None)
-            except ValueError:
-                return self._close(which)
-            except (subprocess.pywintypes.error, Exception), why:
-                if why[0] in (109, errno.ESHUTDOWN):
-                    return self._close(which)
-                raise
-            
-            if self.universal_newlines:
-                read = self._translate_newlines(read)
-            return read
-
-    else:
-        def send(self, input):
-            if not self.stdin:
-                return None
-
-            if not select.select([], [self.stdin], [], 0)[1]:
-                return 0
-
-            try:
-                written = os.write(self.stdin.fileno(), input)
-            except OSError, why:
-                if why[0] == errno.EPIPE: #broken pipe
-                    return self._close('stdin')
-                raise
-
-            return written
-
-        def _recv(self, which, maxsize):
-            conn, maxsize = self.get_conn_maxsize(which, maxsize)
-            if conn is None:
-                return None
-            
-            flags = fcntl.fcntl(conn, fcntl.F_GETFL)
-            if not conn.closed:
-                fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-            
-            try:
-                if not select.select([conn], [], [], 0)[0]:
-                    return ''
-                
-                r = conn.read(maxsize)
-                
-                if not r:
-                    return self._close(which)
-    
-                if self.universal_newlines:
-                    r = self._translate_newlines(r)
-                return r
-            finally:
-                if not conn.closed:
-                    fcntl.fcntl(conn, fcntl.F_SETFL, flags)
-
-message = "Other end disconnected!"
-
-def recv_some(p, t = .1, e = 1, tr = 5, stderr = 0):
-    if tr < 1:
-        tr = 1
-    x = time.time()+t
-    y = []
-    r = ''
-    pr = p.recv
-    if stderr:
-        pr = p.recv_err
-    while time.time() < x or r:
-        r = pr()
-        if r is None:
-            if e:
-                raise Exception(message)
-            else:
-                break
-        elif r:
-            y.append(r)
-        else:
-            time.sleep(max((x-time.time())/tr, 0))
-    return ''.join(y)
-    
-def send_all(p, data):
-    while len(data):
-        sent = p.send(data)
-        if sent is None:
-            raise Exception(message)
-        data = buffer(data, sent)
-
-class Command:
-    """!Run command in separate thread. Used for commands launched
-    on the background.
-
-    If stdout/err is redirected, write() method is required for the
-    given classes.
-
-    @code
-        cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
-
-        if cmd.returncode == None:
-            print 'RUNNING?'
-        elif cmd.returncode == 0:
-            print 'SUCCESS'
-        else:
-            print 'FAILURE (%d)' % cmd.returncode
-    @endcode
-    """
-    def __init__ (self, cmd, stdin = None,
-                  verbose = None, wait = True, rerr = False,
-                  stdout = None, stderr = None):
-        """
-        @param cmd     command given as list
-        @param stdin   standard input stream
-        @param verbose verbose level [0, 3] (--q, --v)
-        @param wait    wait for child execution terminated
-        @param rerr    error handling (when GException raised).
-        True for redirection to stderr, False for GUI dialog,
-        None for no operation (quiet mode)
-        @param stdout  redirect standard output or None
-        @param stderr  redirect standard error output or None
-        """
-        Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
-        self.cmd = cmd
-        self.stderr = stderr
-	
-        #
-        # set verbosity level
-        #
-        verbose_orig = None
-        if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
-                ('--v' not in self.cmd and '--verbose' not in self.cmd):
-            if verbose is not None:
-                if verbose == 0:
-                    self.cmd.append('--quiet')
-                elif verbose == 3:
-                    self.cmd.append('--verbose')
-                else:
-                    verbose_orig = os.getenv("GRASS_VERBOSE")
-                    os.environ["GRASS_VERBOSE"] = str(verbose)
-
-        #
-        # create command thread
-        #
-        self.cmdThread = CommandThread(cmd, stdin,
-                                       stdout, stderr)
-        self.cmdThread.start()
-        
-        if wait:
-            self.cmdThread.join()
-            if self.cmdThread.module:
-                self.cmdThread.module.wait()
-                self.returncode = self.cmdThread.module.returncode
-            else:
-                self.returncode = 1
-        else:
-            self.cmdThread.join(0.5)
-            self.returncode = None
-
-        if self.returncode is not None:
-            Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % \
-                           (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
-            if rerr is not None and self.returncode != 0:
-                if rerr is False: # GUI dialog
-                    raise GException("%s '%s'%s%s%s %s%s" % \
-                                         (_("Execution failed:"),
-                                          ' '.join(self.cmd),
-                                          os.linesep, os.linesep,
-                                          _("Details:"),
-                                          os.linesep,
-                                          _("Error: ") + self.__GetError()))
-                elif rerr == sys.stderr: # redirect message to sys
-                    stderr.write("Execution failed: '%s'" % (' '.join(self.cmd)))
-                    stderr.write("%sDetails:%s%s" % (os.linesep,
-                                                     _("Error: ") + self.__GetError(),
-                                                     os.linesep))
-            else:
-                pass # nop
-        else:
-            Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % \
-                           (' '.join(cmd), wait, self.cmdThread.isAlive()))
-
-        if verbose_orig:
-            os.environ["GRASS_VERBOSE"] = verbose_orig
-        elif "GRASS_VERBOSE" in os.environ:
-            del os.environ["GRASS_VERBOSE"]
-            
-    def __ReadOutput(self, stream):
-        """!Read stream and return list of lines
-
-        @param stream stream to be read
-        """
-        lineList = []
-
-        if stream is None:
-            return lineList
-
-        while True:
-            line = stream.readline()
-            if not line:
-                break
-            line = line.replace('%s' % os.linesep, '').strip()
-            lineList.append(line)
-
-        return lineList
-                    
-    def __ReadErrOutput(self):
-        """!Read standard error output and return list of lines"""
-        return self.__ReadOutput(self.cmdThread.module.stderr)
-
-    def __ProcessStdErr(self):
-        """
-        Read messages/warnings/errors from stderr
-
-        @return list of (type, message)
-        """
-        if self.stderr is None:
-            lines = self.__ReadErrOutput()
-        else:
-            lines = self.cmdThread.error.strip('%s' % os.linesep). \
-                split('%s' % os.linesep)
-        
-        msg = []
-
-        type    = None
-        content = ""
-        for line in lines:
-            if len(line) == 0:
-                continue
-            if 'GRASS_' in line: # error or warning
-                if 'GRASS_INFO_WARNING' in line: # warning
-                    type = "WARNING"
-                elif 'GRASS_INFO_ERROR' in line: # error
-                    type = "ERROR"
-                elif 'GRASS_INFO_END': # end of message
-                    msg.append((type, content))
-                    type = None
-                    content = ""
-                
-                if type:
-                    content += line.split(':', 1)[1].strip()
-            else: # stderr
-                msg.append((None, line.strip()))
-
-        return msg
-
-    def __GetError(self):
-        """!Get error message or ''"""
-        if not self.cmdThread.module:
-            return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
-
-        for type, msg in self.__ProcessStdErr():
-            if type == 'ERROR':
-                enc = locale.getdefaultlocale()[1]
-                if enc:
-                    return unicode(msg, enc)
-                else:
-                    return msg
-        
-        return ''
-    
-class CommandThread(Thread):
-    """!Create separate thread for command. Used for commands launched
-    on the background."""
-    def __init__ (self, cmd, stdin = None,
-                  stdout = sys.stdout, stderr = sys.stderr):
-        """
-        @param cmd command (given as list)
-        @param stdin standard input stream 
-        @param stdout redirect standard output or None
-        @param stderr redirect standard error output or None
-        """
-        Thread.__init__(self)
-        
-        self.cmd    = cmd
-        self.stdin  = stdin
-        self.stdout = stdout
-        self.stderr = stderr
-        
-        self.module = None
-        self.error  = ''
-        
-        self._want_abort = False
-        self.aborted = False
-        
-        self.setDaemon(True)
-        
-        # set message formatting
-        self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
-        os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
-        
-    def __del__(self):
-        if self.message_format:
-            os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
-        else:
-            del os.environ["GRASS_MESSAGE_FORMAT"]
-        
-    def run(self):
-        """!Run command"""
-        if len(self.cmd) == 0:
-            return
-
-        Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
-
-        self.startTime = time.time()
-        try:
-            self.module = Popen(self.cmd,
-                                stdin = subprocess.PIPE,
-                                stdout = subprocess.PIPE,
-                                stderr = subprocess.PIPE,
-                                shell = sys.platform == "win32")
-        except OSError, e:
-            self.error = str(e)
-            return 1
-        
-        if self.stdin: # read stdin if requested ...
-            self.module.stdin.write(self.stdin)
-            self.module.stdin.close()
-            
-        # redirect standard outputs...
-        self._redirect_stream()
-        
-    def _redirect_stream(self):
-        """!Redirect stream"""
-        if self.stdout:
-            # make module stdout/stderr non-blocking
-            out_fileno = self.module.stdout.fileno()
-	    if not subprocess.mswindows:
-                flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
-                fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-                
-        if self.stderr:
-            # make module stdout/stderr non-blocking
-            out_fileno = self.module.stderr.fileno()
-	    if not subprocess.mswindows:
-                flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
-                fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-        
-        # wait for the process to end, sucking in stuff until it does end
-        while self.module.poll() is None:
-            if self._want_abort: # abort running process
-                self.module.kill()
-                self.aborted = True
-                return 
-            if self.stdout:
-                line = recv_some(self.module, e = 0, stderr = 0)
-                self.stdout.write(line)
-            if self.stderr:
-                line = recv_some(self.module, e = 0, stderr = 1)
-                self.stderr.write(line)
-                if len(line) > 0:
-                    self.error = line
-
-        # get the last output
-        if self.stdout:
-            line = recv_some(self.module, e = 0, stderr = 0)
-            self.stdout.write(line)
-        if self.stderr:
-            line = recv_some(self.module, e = 0, stderr = 1)
-            self.stderr.write(line)
-            if len(line) > 0:
-                self.error = line
-            
-    def abort(self):
-        """!Abort running process, used by main thread to signal an abort"""
-        self._want_abort = True
-    
-def _formatMsg(text):
-    """!Format error messages for dialogs
-    """
-    message = ''
-    for line in text.splitlines():
-        if len(line) == 0:
-            continue
-        elif 'GRASS_INFO_MESSAGE' in line:
-            message += line.split(':', 1)[1].strip() + '\n'
-        elif 'GRASS_INFO_WARNING' in line:
-            message += line.split(':', 1)[1].strip() + '\n'
-        elif 'GRASS_INFO_ERROR' in line:
-            message += line.split(':', 1)[1].strip() + '\n'
-        elif 'GRASS_INFO_END' in line:
-            return message
-        else:
-            message += line.strip() + '\n'
-    
-    return message
-
-def RunCommand(prog, flags = "", overwrite = False, quiet = False, verbose = False,
-               parent = None, read = False, parse = None, stdin = None, getErrorMsg = False, **kwargs):
-    """!Run GRASS command
-
-    @param prog program to run
-    @param flags flags given as a string
-    @param overwrite, quiet, verbose flags
-    @param parent parent window for error messages
-    @param read fetch stdout
-    @param parse fn to parse stdout (e.g. grass.parse_key_val) or None
-    @param stdin stdin or None
-    @param getErrorMsg get error messages on failure
-    @param kwargs program parameters
-    
-    @return returncode (read == False and getErrorMsg == False)
-    @return returncode, messages (read == False and getErrorMsg == True)
-    @return stdout (read == True and getErrorMsg == False)
-    @return returncode, stdout, messages (read == True and getErrorMsg == True)
-    @return stdout, stderr
-    """
-    cmdString = ' '.join(grass.make_command(prog, flags, overwrite,
-                                            quiet, verbose, **kwargs))
-    
-    Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
-    
-    kwargs['stderr'] = subprocess.PIPE
-    
-    if read:
-        kwargs['stdout'] = subprocess.PIPE
-    
-    if stdin:
-        kwargs['stdin'] = subprocess.PIPE
-
-    Debug.msg(2, "gcmd.RunCommand(): command started")
-    start = time.time()
-    
-    ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
-    
-    if stdin:
-        ps.stdin.write(stdin)
-        ps.stdin.close()
-        ps.stdin = None
-    
-    Debug.msg(3, "gcmd.RunCommand(): decoding string")
-    stdout, stderr = map(utils.DecodeString, ps.communicate())
-    
-    ret = ps.returncode
-    Debug.msg(1, "gcmd.RunCommand(): get return code %d (%.6f sec)" % \
-                  (ret, (time.time() - start)))
-    
-    Debug.msg(3, "gcmd.RunCommand(): print error")
-    if ret != 0 and parent:
-        Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr)
-        if (stderr == None):
-            Debug.msg(2, "gcmd.RunCommand(): nothing to print ???")
-        else:
-            GError(parent = parent,
-                   message = stderr)
-    
-    Debug.msg(3, "gcmd.RunCommand(): print read error")
-    if not read:
-        if not getErrorMsg:
-            return ret
-        else:
-            return ret, _formatMsg(stderr)
-
-    if stdout:
-        Debug.msg(2, "gcmd.RunCommand(): return stdout\n'%s'" % stdout)
-    else:
-        Debug.msg(2, "gcmd.RunCommand(): return stdout = None")
-    
-    if parse:
-        stdout = parse(stdout)
-    
-    if not getErrorMsg:
-        return stdout
-    
-    Debug.msg(2, "gcmd.RunCommand(): return ret, stdout")
-    if read and getErrorMsg:
-        return ret, stdout, _formatMsg(stderr)
-    
-    Debug.msg(2, "gcmd.RunCommand(): return result")
-    return stdout, _formatMsg(stderr)

Deleted: grass/trunk/gui/wxpython/gui_modules/gcpmanager.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gcpmanager.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gcpmanager.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2796 +0,0 @@
-"""!
- 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-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author 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 gdialogs
-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
-
-sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
-
-#
-# global variables
-#
-global src_map
-global tgt_map
-global maptype
-
-src_map = ''
-tgt_map = ''
-maptype = 'cell'
-
-def getSmallUpArrowImage():
-    stream = open(os.path.join(globalvar.ETCIMGDIR, 'small_up_arrow.png'), 'rb')
-    try:
-        img = wx.ImageFromStream(stream)
-    finally:
-        stream.close()
-    return img
-
-def getSmallDnArrowImage():
-    stream = open(os.path.join(globalvar.ETCIMGDIR, '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:
-                gcmd.GMessage(parent = self.parent,
-                              message = _("Georectifying setup canceled."))
-                self.Cleanup()
-        else:
-            gcmd.GMessage(parent = self.parent,
-                          message = _("Georectifying setup canceled."))
-            self.Cleanup()
-
-        #
-        # start GCP display
-        #
-        if success != False:
-            # instance of render.Map to be associated with display
-            self.SwitchEnv('source')
-            self.SrcMap = 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')
-            name, found = utils.GetLayerNameFromCmd(cmdlist)
-            self.SrcMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
-                                 name=name, 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')
-                name, found = utils.GetLayerNameFromCmd(cmdlist)
-                self.TgtMap.AddLayer(type=rendertype, command=cmdlist, l_active=True,
-                                     name=name, 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 == '':
-            gcmd.GMessage(_('You must select a valid location '
-                            'before selecting a mapset'),
-                          parent = self)
-            return
-
-        self.xymapset = event.GetString()
-        
-        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-    def OnPageChanging(self, event=None):
-        if event.GetDirection() and \
-               (self.xylocation == '' or self.xymapset == ''):
-            gcmd.GMessage(_('You must select a valid location '
-                            'and mapset in order to continue'),
-                          parent = self)
-            event.Veto()
-            return
-        
-        self.parent.SetSrcEnv(self.xylocation, self.xymapset)
-        
-    def OnEnterPage(self, event=None):
-        if self.xylocation == '' or self.xymapset == '':
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-class GroupPage(TitledPage):
-    """
-    Set group to georectify. Create group if desired.
-    """
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Select image/map group to georectify"))
-
-        self.parent = parent
-        
-        self.grassdatabase = self.parent.grassdatabase
-        self.groupList = []
-        
-        self.xylocation = ''
-        self.xymapset = ''
-        self.xygroup = ''
-
-        # default extension
-        self.extension = '.georect' + str(os.getpid())
-
-        #
-        # layout
-        #
-        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"""
-        dlg = gdialogs.GroupDialog(parent = self, defaultGroup = self.xygroup)
-
-        dlg.ShowModal()
-        gr = dlg.GetSelectedGroup()
-        if gr in dlg.GetExistGroups():
-            self.xygroup = gr
-        else:
-            gr = ''
-        dlg.Destroy()
-        
-        self.OnEnterPage()
-        self.Update()
-        
-    def OnVGroup(self, event):
-        """!Add vector maps to group"""
-        dlg = VectGroup(parent = self,
-                        id = wx.ID_ANY,
-                        grassdb = self.grassdatabase,
-                        location = self.xylocation,
-                        mapset = self.xymapset,
-                        group = self.xygroup)
-
-        if dlg.ShowModal() != wx.ID_OK:
-            return
-
-        dlg.MakeVGroup()
-        self.OnEnterPage()
-        
-    def OnExtension(self, event):
-        self.extension = event.GetString()
-
-    def OnPageChanging(self, event=None):
-        if event.GetDirection() and self.xygroup == '':
-            gcmd.GMessage(_('You must select a valid image/map '
-                            'group in order to continue'),
-                          parent = self)
-            event.Veto()
-            return
-
-        if event.GetDirection() and self.extension == '':
-            gcmd.GMessage(_('You must enter an map name '
-                            'extension in order to continue'),
-                          parent = self)
-            event.Veto()
-            return
-
-    def OnEnterPage(self, event=None):
-        global maptype
-        
-        self.groupList = []
-
-        self.xylocation = self.parent.gisrc_dict['LOCATION_NAME']
-        self.xymapset = self.parent.gisrc_dict['MAPSET']
-
-        # create a list of groups in selected mapset
-        if os.path.isdir(os.path.join(self.grassdatabase,
-                                      self.xylocation,
-                                      self.xymapset,
-                                      'group')):
-            tmplist = os.listdir(os.path.join(self.grassdatabase,
-                                              self.xylocation,
-                                              self.xymapset,
-                                              'group'))
-            for item in tmplist:
-                if os.path.isdir(os.path.join(self.grassdatabase,
-                                              self.xylocation,
-                                              self.xymapset,
-                                              'group',
-                                              item)):
-                    self.groupList.append(item)
-        
-        if maptype == '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:
-            if self.xygroup and self.xygroup in self.groupList:
-                self.cb_group.SetStringSelection(self.xygroup)
-            else:
-                self.cb_group.SetSelection(0)
-                self.xygroup = self.groupList[0]
-        
-        if self.xygroup == '' or \
-                self.extension == '':
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-        
-        # switch to source
-        self.parent.SwitchEnv('source')
-    
-class DispMapPage(TitledPage):
-    """
-    Select ungeoreferenced map to display for interactively
-    setting ground control points (GCPs).
-    """
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard,
-                            _("Select maps to display for ground control point (GCP) creation"))
-
-        self.parent = parent
-        global maptype
-
-        #
-        # layout
-        #
-        self.sizer.Add(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 == ''):
-            gcmd.GMessage(_('You must select a source map '
-                            'in order to continue'),
-                          parent = self)
-            event.Veto()
-            return
-
-        self.parent.SwitchEnv('target')
-        
-    def OnEnterPage(self, event=None):
-        global maptype
-        global src_map
-        global tgt_map
-
-        self.srcselection.SetElementList(maptype)
-        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:
-            gcmd.GError(parent = self,
-                        message = _('No maps in selected group <%s>.\n'
-                                    'Please edit group or select another group.') %
-                        self.parent.grouppage.xygroup)
-            return
-
-        # filter out all maps not in group
-        self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
-        src_map = self.parent.src_maps[0]
-        self.srcselection.SetValue(src_map)
-
-        self.parent.SwitchEnv('target')
-        self.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, 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 = parent, title = title, size = size,
-                            Map = Map, toolbars = toolbars, 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 
-        # interpolation method for georectification
-        self.gr_method = 'nearest'
-        # region clipping for georectified map
-        self.clip_to_region = False
-        # number of GCPs selected to be used for georectification (checked)
-        self.GCPcount = 0
-        # forward RMS error
-        self.fwd_rmserror = 0.0
-        # backward RMS error
-        self.bkw_rmserror = 0.0
-        # list map coords and ID of map display they came from
-        self.mapcoordlist = []
-        self.mapcoordlist.append([ 0,        # GCP number
-                                   0.0,      # source east
-                                   0.0,      # source north
-                                   0.0,      # 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)
-
-        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
-        #
-        if self.show_target:
-            self.MapWindow = self.TgtMapWindow
-            self.Map = self.TgtMap
-            self.OnZoomToMap(None)
-
-        self.MapWindow = self.SrcMapWindow
-        self.Map = self.SrcMap
-        self.OnZoomToMap(None)
-
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
-        self.Bind(wx.EVT_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
-        
-    def GetMapCoordList(self):
-        return self.mapcoordlist
-
-    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
-    def GetSortImages(self):
-        return (self.sm_dn, self.sm_up)
-
-    def GetFwdError(self):
-        return self.fwd_rmserror
-        
-    def GetBkwError(self):
-        return self.bkw_rmserror
-                
-    def InitMapDisplay(self):
-        self.list.LoadData()
-        
-        # initialize column sorter
-        self.itemDataMap = self.mapcoordlist
-        ncols = self.list.GetColumnCount()
-        ColumnSorterMixin.__init__(self, ncols)
-        # init to ascending sort on first click
-        self._colSortFlag = [1] * ncols
-
-    def SetTarget(self, tgroup, tlocation, tmapset):
-        """
-        Sets rectification target to current location and mapset
-        """
-        # check to see if we are georectifying map in current working location/mapset
-        if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
-            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.statusbarManager.GetMode() == 8: # go to
-            self.StatusbarUpdate()
-
-    def DeleteGCP(self, event):
-        """
-        Deletes selected item in GCP list
-        """
-        minNumOfItems = self.OnGROrder(None)
-
-        if self.list.GetItemCount() <= minNumOfItems:
-            gcmd.GMessage(parent = self,
-                          message=_("At least %d GCPs required. Operation cancelled.") % minNumOfItems)
-            return
-
-        key = self.list.DeleteGCPItem()
-        del self.mapcoordlist[key]
-
-        # update key and GCP number
-        for newkey in range(key, len(self.mapcoordlist)):
-            index = self.list.FindItemData(-1, newkey + 1)
-            self.mapcoordlist[newkey][0] = newkey
-            self.list.SetStringItem(index, 0, str(newkey))
-            self.list.SetItemData(index, newkey)
-
-        # update selected
-        if self.list.GetItemCount() > 0:
-            if self.list.selected < self.list.GetItemCount():
-                self.list.selectedkey = self.list.GetItemData(self.list.selected)
-            else:
-                self.list.selected = self.list.GetItemCount() - 1
-                self.list.selectedkey = self.list.GetItemData(self.list.selected)
-                
-            self.list.SetItemState(self.list.selected,
-                              wx.LIST_STATE_SELECTED,
-                              wx.LIST_STATE_SELECTED)
-        else:
-            self.list.selected = wx.NOT_FOUND
-            self.list.selectedkey = -1
-
-        self.UpdateColours()
-
-        if self.statusbarManager.GetMode() == 8: # go to
-            self.StatusbarUpdate()
-            if self.list.selectedkey > 0:
-                self.statusbarManager.SetProperty('gotoGCP', self.list.selectedkey)
-
-    def ClearGCP(self, event):
-        """
-        Clears all values in selected item of GCP list and unchecks it
-        """
-        index = self.list.GetSelected()
-
-        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:
-            gcmd.GError(parent = self,
-                        message="%s%s." % (_("mapwin not defined for "),
-                                           str(idx)))
-            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 %(coor)s coordinates for GCP No. %(key)s? \n\n'
-                                          'East: %(coor0)s \n'
-                                          'North: %(coor1)s') % \
-                                    { 'coor' : currloc,
-                                      'key' : str(key),
-                                      'coor0' : str(coord0),
-                                      'coor1' : str(coord1) },
-                                style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
-
-            # for wingrass
-            if os.name == 'nt':
-                self.MapWindow.SetFocus()
-            if ret == wx.NO:
-                return
-            
-        if coordtype == 'source':
-            self.list.SetStringItem(index, 1, str(coord0))
-            self.list.SetStringItem(index, 2, str(coord1))
-            self.mapcoordlist[key][1] = coord[0]
-            self.mapcoordlist[key][2] = coord[1]
-        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:
-            gcmd.GError(parent = self,
-                        message="%s <%s>. %s%s" % (_("Writing POINTS file failed"),
-                                                   self.file['points'], os.linesep, err))
-            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:
-            gcmd.GError(parent = self,
-                        message = "%s. %s%s" % (_("source mapwin not defined"),
-                                                os.linesep, err))
-        
-        if not targetMapWin:
-            gcmd.GError(parent = self,
-                        message="%s. %s%s" % (_("target mapwin not defined"),
-                                              os.linesep, err))
-        
-        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:
-            gcmd.GError(parent = self,
-                        message = "%s <%s>. %s%s" % (_("Reading POINTS file failed"),
-                                                     self.file['points'], os.linesep, err))
-            return
-
-        f.close()
-
-        if GCPcnt == 0:
-            # 3 gcp is minimum
-            for i in range(3):
-                self.AddGCP(None)
-
-        if self.CheckGCPcount():
-            # calculate RMS
-            self.RMSError(self.xygroup, self.gr_order)
-
-    def ReloadGCPs(self, event):
-        """!Reload data from file"""
-
-        # use backup
-        shutil.copy(self.file['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
-
-        if self._col != -1:
-            self.list.ClearColumnImage(self._col)
-        self._colSortFlag = [1] * self.list.GetColumnCount()
-
-        # draw GCPs (source and target)
-        sourceMapWin = self.SrcMapWindow
-        sourceMapWin.UpdateMap(render=False, renderVector=False)
-        if self.show_target:
-            targetMapWin = self.TgtMapWindow
-            targetMapWin.UpdateMap(render=False, renderVector=False)
-    
-    def OnFocus(self, event):
-        # self.grwiz.SwitchEnv('source')
-        pass
-        
-    def OnRMS(self, event):
-        """
-        RMS button handler
-        """
-        self.RMSError(self.xygroup,self.gr_order)
-
-        sourceMapWin = self.SrcMapWindow
-        sourceMapWin.UpdateMap(render=False, renderVector=False)
-        if self.show_target:
-            targetMapWin = self.TgtMapWindow
-            targetMapWin.UpdateMap(render=False, renderVector=False)
-        
-    def CheckGCPcount(self, msg=False):
-        """
-        Checks to make sure that the minimum number of GCPs have been defined and
-        are active for the selected transformation order
-        """
-        if (self.GCPcount < 3 and self.gr_order == 1) or \
-            (self.GCPcount < 6 and self.gr_order == 2) or \
-            (self.GCPcount < 10 and self.gr_order == 3):
-            if msg:
-                gcmd.GWarning(parent = self,
-                              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.'))
-                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')
-
-            if self.clip_to_region:
-                flags = "ac"
-            else:
-                flags = "a"
-
-            busy = wx.BusyInfo(message=_("Rectifying images, please wait..."),
-                               parent=self)
-            wx.Yield()
-
-            ret, msg = gcmd.RunCommand('i.rectify',
-                                  parent = self,
-                                  getErrorMsg = True,
-                                  quiet = True,
-                                  group = self.xygroup,
-                                  extension = self.extension,
-                                  order = self.gr_order,
-                                  method=self.gr_method,
-                                  flags = flags)
-
-            busy.Destroy()
-
-            # provide feedback on failure
-            if ret != 0:
-                print >> sys.stderr, msg
-                
-        elif maptype == 'vector':
-            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',
-                                                overwrite = True,
-                                                input = vect,
-                                                output = self.outname,
-                                                pointsfile = self.file['points'],
-                                                getErrorMsg = True, read = True) 
-                
-                if ret == 0:
-                    self.VectGRList.append(self.outname)
-                    # 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
-                                                   
-            gcmd.GMessage(_('For all vector maps georectified successfully,') + '\n' +
-                          _('you will need to copy any attribute tables') + '\n' +
-                          _('and reconnect them to the georectified vectors'),
-                          parent = self)
-        
-        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 m.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('m.transform',
-                              parent = self,
-                              read = True,
-                              group = xygroup,
-                              order = order)
-        
-        self.grwiz.SwitchEnv('target')
-
-        if ret:
-            errlist = ret.splitlines()
-        else:
-            gcmd.GError(parent = self,
-                        message=_('Could not calculate RMS Error.\n'
-                                  'Possible error with m.transform.'))
-            return
-        
-        # insert error values into GCP list for checked items
-        sdfactor = float(UserSettings.Get(group='gcpman', key='rms', subkey='sdfactor'))
-        GCPcount = 0
-        sumsq_fwd_err = 0.0
-        sumsq_bkw_err = 0.0
-        sum_fwd_err = 0.0
-        highest_fwd_err = 0.0
-        self.highest_key = 0
-        highest_idx = 0
-        
-        for index in range(self.list.GetItemCount()):
-            key = self.list.GetItemData(index)
-            if self.list.IsChecked(index):
-                fwd_err, bkw_err = errlist[GCPcount].split()
-                self.list.SetStringItem(index, 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()
-
-    def GetNewExtent(self, region, map = None):
-
-        coord_file = utils.GetTempfile()
-        newreg = { 'n' : 0.0, 's' : 0.0, 'e' : 0.0, 'w' : 0.0,}
-
-        try:
-            f = open(coord_file, mode='w')
-            # NW corner        
-            f.write(str(region['e']) + " " + str(region['n']) + "\n")
-            # NE corner        
-            f.write(str(region['e']) + " " + str(region['s']) + "\n")
-            # SW corner        
-            f.write(str(region['w']) + " " + str(region['n']) + "\n")
-            # SE corner        
-            f.write(str(region['w']) + " " + str(region['s']) + "\n")
-        finally:
-            f.close()
-
-        # save GCPs to points file to make sure that all checked GCPs are used
-        self.SaveGCPs(None)
-
-        order = self.gr_order
-        self.gr_order = 1
-
-        if self.CheckGCPcount(msg=True) == False:
-            self.gr_order = order
-            return
-        
-        self.gr_order = order
-
-        # get list of forward and reverse rms error values for each point
-        self.grwiz.SwitchEnv('source')
-        
-        if map == 'source':
-            ret = gcmd.RunCommand('m.transform',
-                                  parent = self,
-                                  read = True,
-                                  group = self.xygroup,
-                                  order = 1,
-                                  format = 'dst',
-                                  coords = coord_file)
-
-        elif map == 'target':
-            ret = gcmd.RunCommand('m.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:
-            gcmd.GError(parent = self,
-                        message=_('Could not calculate new extends.\n'
-                                  'Possible error with m.transform.'))
-            return
-
-        # fist corner
-        e, n = errlist[0].split()
-        fe = float(e)
-        fn = float(n)
-        newreg['n'] = fn
-        newreg['s'] = fn
-        newreg['e'] = fe
-        newreg['w'] = fe
-        # other three corners
-        for i in range(1, 4):
-            e, n = errlist[i].split()
-            fe = float(e)
-            fn = float(n)
-            if fe < newreg['w']:
-                newreg['w'] = fe
-            if fe > newreg['e']:
-                newreg['e'] = fe
-            if fn < newreg['s']:
-                newreg['s'] = fn
-            if fn > newreg['n']:
-                newreg['n'] = fn
-
-        return newreg
-
-    def OnHelp(self, event):
-        """!Show GCP Manager manual page"""
-        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.GetMapToolbar().Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
-
-        if self.activemap.GetSelection() != (win == self.TgtMapWindow):
-            self.activemap.SetSelection(win == self.TgtMapWindow)
-        self.StatusbarUpdate()
-
-    def AdjustMap(self, newreg):
-        """!Adjust map window to new extents
-        """
-
-        # adjust map window
-        self.Map.region['n'] = newreg['n']
-        self.Map.region['s'] = newreg['s']
-        self.Map.region['e'] = newreg['e']
-        self.Map.region['w'] = newreg['w']
-
-        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                 self.Map.region['e'], self.Map.region['w'])
-
-        # LL locations
-        if self.Map.projinfo['proj'] == 'll':
-            if newreg['n'] > 90.0:
-                newreg['n'] = 90.0
-            if newreg['s'] < -90.0:
-                newreg['s'] = -90.0
-        
-        ce = newreg['w'] + (newreg['e'] - newreg['w']) / 2
-        cn = newreg['s'] + (newreg['n'] - newreg['s']) / 2
-        
-        # calculate new center point and display resolution
-        self.Map.region['center_easting'] = ce
-        self.Map.region['center_northing'] = cn
-        self.Map.region["ewres"] = (newreg['e'] - newreg['w']) / self.Map.width
-        self.Map.region["nsres"] = (newreg['n'] - newreg['s']) / self.Map.height
-        self.Map.AlignExtentFromDisplay()
-
-        self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                 self.Map.region['e'], self.Map.region['w'])
-
-        if self.MapWindow.redrawAll is False:
-            self.MapWindow.redrawAll = True
-
-        self.MapWindow.UpdateMap()
-        self.StatusbarUpdate()
-
-    def OnZoomToSource(self, event):
-        """!Set target map window to match extents of source map window
-        """
-
-        if not self.MapWindow == self.TgtMapWindow:
-            self.MapWindow = self.TgtMapWindow
-            self.Map = self.TgtMap
-            self.UpdateActive(self.TgtMapWindow)
-
-        # get new N, S, E, W for target
-        newreg = self.GetNewExtent(self.SrcMap.region, 'source')
-        if newreg:
-            self.AdjustMap(newreg)
-
-    def OnZoomToTarget(self, event):
-        """!Set source map window to match extents of target map window
-        """
-
-        if not self.MapWindow == self.SrcMapWindow:
-            self.MapWindow = self.SrcMapWindow
-            self.Map = self.SrcMap
-            self.UpdateActive(self.SrcMapWindow)
-
-        # get new N, S, E, W for target
-        newreg = self.GetNewExtent(self.TgtMap.region, 'target')
-        if newreg:
-            self.AdjustMap(newreg)
-
-    def OnZoomMenuGCP(self, event):
-        """!Popup Zoom menu
-        """
-        point = wx.GetMousePosition()
-        zoommenu = wx.Menu()
-        # Add items to the menu
-
-        zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust source display to target display'))
-        zoommenu.AppendItem(zoomsource)
-        self.Bind(wx.EVT_MENU, self.OnZoomToTarget, zoomsource)
-
-        zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust target display to source display'))
-        zoommenu.AppendItem(zoomtarget)
-        self.Bind(wx.EVT_MENU, self.OnZoomToSource, zoomtarget)
-
-        # Popup the menu. If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(zoommenu)
-        zoommenu.Destroy()
-        
-    def OnDispResize(self, event):
-        """!GCP Map Display resized, adjust Map Windows
-        """
-        if self.GetMapToolbar():
-            srcwidth, srcheight = self.SrcMapWindow.GetSize()
-            tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
-            srcwidth = (srcwidth + tgtwidth) / 2
-            self._mgr.GetPane("target").Hide()
-            self._mgr.Update()
-            self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
-            self._mgr.GetPane("target").BestSize((srcwidth, 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:
-                gcmd.GError(parent = self,
-                            message=_("Invalid coordinate value. Operation cancelled."))
-            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 = {}
-        
-        self.methods = ["nearest",
-                        "bilinear",
-                        "bilinear_f",
-                        "cubic", 
-                        "cubic_f",
-                        "lanczos",
-                        "lanczos_f"]
-
-        # notebook
-        notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
-        self.__CreateSymbologyPage(notebook)
-        self.__CreateRectificationPage(notebook)
-
-        # buttons
-        btnSave = wx.Button(self, wx.ID_SAVE)
-        btnApply = wx.Button(self, wx.ID_APPLY)
-        btnClose = wx.Button(self, wx.ID_CLOSE)
-        btnApply.SetDefault()
-
-        # bindings
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnApply.SetToolTipString(_("Apply changes for the current session"))
-        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
-        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
-        btnClose.SetToolTipString(_("Close dialog"))
-
-        # sizers
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
-        btnSizer.Add(btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
-        btnSizer.Add(btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
-        
-        # sizers
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(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_grorder = wx.RadioBox(parent=panel, id=wx.ID_ANY,
-                                       label=" %s " % _("Select rectification order"),
-                                       choices=[_('1st order'), _('2nd order'), _('3rd order')],
-                                       majorDimension=wx.RA_SPECIFY_COLS)
-        sizer.Add(item=self.rb_grorder, proportion=0,
-                       flag=wx.EXPAND | wx.ALL, border=5)
-        self.rb_grorder.SetSelection(self.parent.gr_order - 1)
-
-        # interpolation method
-        gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
-        gridSizer.AddGrowableCol(1)
-        gridSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY, label=_('Select interpolation method:')),
-                       pos=(0,0), flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
-        self.grmethod = wx.Choice(parent=panel, id=wx.ID_ANY,
-                                  choices = self.methods)
-        gridSizer.Add(item=self.grmethod, pos=(0,1),
-                       flag=wx.ALIGN_RIGHT, border=5)
-        self.grmethod.SetStringSelection(self.parent.gr_method)
-        sizer.Add(item=gridSizer, flag=wx.EXPAND | wx.ALL, border=5)
-
-        # clip to region
-        self.check = wx.CheckBox(parent=panel, id=wx.ID_ANY,
-                                label=_("clip to computational region in target location"))
-        sizer.Add(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_grorder)
-        self.Bind(wx.EVT_CHOICE, self.OnMethod, self.grmethod)
-        self.Bind(wx.EVT_CHECKBOX, self.OnClipRegion, self.check)
-
-        panel.SetSizer(sizer)
-        
-        return panel
-
-    def OnHighlight(self, event):
-        """!Checkbox 'highlighthighest' checked/unchecked"""
-        if self.highlighthighest.IsChecked():
-            self.parent.highest_only = True
-            self.rmsWin.Disable()
-        else:
-            self.parent.highest_only = False
-            self.rmsWin.Enable()
-
-    def OnSDFactor(self,event):
-        """!New factor for RMS threshold = M + SD * factor"""
-
-        self.sdfactor = float(event.GetString())
-
-        if self.sdfactor <= 0:
-            gcmd.GError(parent = self,
-                        message=_('RMS threshold factor must be > 0'))
-        elif self.sdfactor < 1:
-            gcmd.GError(parent = self,
-                        message=_('RMS threshold factor is < 1\n'
-                                  'Too many points might be highlighted'))
-        
-    def OnSrcSelection(self,event):
-        """!Source map to display selected"""
-        global src_map
-
-        tmp_map = 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 OnMethod(self, event):
-        self.parent.gr_method = self.methods[event.GetSelection()]
-
-    def OnClipRegion(self, event):
-        self.parent.clip_to_region = event.IsChecked()
-        
-    def OnExtension(self, event):
-        self.parent.extension = 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')
-            name, found = utils.GetLayerNameFromCmd(cmdlist),
-            self.parent.grwiz.SrcMap.AddLayer(type='raster', command=cmdlist, l_active=True,
-                              name=name, 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]
-                name, found = utils.GetLayerNameFromCmd(cmdlist)
-                self.parent.grwiz.TgtMap.AddLayer(type='raster', command=cmdlist, l_active=True,
-                                  name=name, 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._mgr.Update()
-                    self.parent.GetMapToolbar().Enable('zoommenu', enable = True)
-                    self.parent.activemap.Enable()
-                    self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
-            else: # tgt_map == ''
-                if self.parent.show_target == True:
-                    self.parent.show_target = False
-                    self.parent._mgr.GetPane("target").Hide()
-                    self.parent._mgr.Update()
-                    self.parent.activemap.SetSelection(0)
-                    self.parent.activemap.Enable(False)
-                    self.parent.GetMapToolbar().Enable('zoommenu', enable = False)
-
-        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()

Deleted: grass/trunk/gui/wxpython/gui_modules/gcpmapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gcpmapdisp.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gcpmapdisp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,659 +0,0 @@
-"""!
- 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 platform
-
-import globalvar
-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
-import mapdisp_statusbar as sb
-from mapdisp import MapFrameBase
-from grass.script import core as grass
-from debug import Debug
-from icon  import Icons
-from preferences import globalSettings as UserSettings
-
-from mapdisp_window import BufferedWindow
-
-# for standalone app
-cmdfilename = None
-
-class MapFrame(MapFrameBase):
-    """!Main frame for map display window. Drawing takes place in
-    child double buffered drawing window.
-    """
-    def __init__(self, parent=None, title=_("GRASS GIS Manage Ground Control Points"),
-                 toolbars=["gcpdisp"], tree=None, notebook=None, lmgr=None,
-                 page=None, Map=None, auimgr=None, name = 'GCPMapWindow', **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
-        """
-        
-        MapFrameBase.__init__(self, parent = parent, title = title, toolbars = toolbars,
-                              Map = Map, auimgr = auimgr, name = name, **kwargs)
-        
-        self._layerManager = lmgr   # Layer Manager object
-        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
-        #
-        # Add toolbars
-        #
-        for toolb in toolbars:
-            self.AddToolbar(toolb)
-
-        self.activemap = self.toolbars['gcpdisp'].togglemap
-        self.activemap.SetSelection(0)
-        
-        self.SrcMap        = self.grwiz.SrcMap       # instance of render.Map
-        self.TgtMap        = self.grwiz.TgtMap       # instance of render.Map
-        self._mgr.SetDockSizeConstraint(0.5, 0.5)
-
-        #
-        # Add statusbar
-        #
-        
-        # items for choice
-        self.statusbarItems = [sb.SbCoordinates,
-                               sb.SbRegionExtent,
-                               sb.SbCompRegionExtent,
-                               sb.SbShowRegion,
-                               sb.SbResolution,
-                               sb.SbDisplayGeometry,
-                               sb.SbMapScale,
-                               sb.SbProjection,
-                               sb.SbGoToGCP,
-                               sb.SbRMSError]
-                            
-        
-        # create statusbar and its manager
-        statusbar = self.CreateStatusBar(number = 4, style = 0)
-        statusbar.SetStatusWidths([-5, -2, -1, -1])
-        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
-        
-        # fill statusbar manager
-        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
-        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
-        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
-        
-        self.statusbarManager.SetMode(8) # goto GCP
-        self.statusbarManager.Update()
-        
-
-        #
-        # 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._initMap(map = self.SrcMap) 
-        self._initMap(map = self.TgtMap) 
-
-        #
-        # 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()
-        srcwidth = (srcwidth + tgtwidth) / 2
-        self._mgr.GetPane("target").Hide()
-        self._mgr.Update()
-        self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
-        self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
-        if self.show_target:
-            self._mgr.GetPane("target").Show()
-        else:
-            self.activemap.Enable(False)
-        # needed by Mac OS, does not harm on Linux, breaks display on Windows
-        if platform.system() != 'Windows':
-            self._mgr.Update()
-
-        #
-        # Init print module and classes
-        #
-        self.printopt = disp_print.PrintOptions(self, self.MapWindow)
-        
-        #
-        # Initialization of digitization tool
-        #
-        self.digit = None
-
-        # set active map
-        self.MapWindow = self.SrcMapWindow
-        self.Map = self.SrcMap
-        
-        # do not init zoom history here, that happens when zooming to map(s)
-
-        #
-        # Re-use dialogs
-        #
-        self.dialogs = {}
-        self.dialogs['attributes'] = None
-        self.dialogs['category'] = None
-        self.dialogs['barscale'] = None
-        self.dialogs['legend'] = None
-
-        self.decorationDialog = None # decoration/overlays
-
-    def AddToolbar(self, name):
-        """!Add defined toolbar to the window
-        
-        Currently known toolbars are:
-         - 'map'     - basic map toolbar
-         - 'vdigit'  - vector digitizer
-         - 'gcpdisp' - GCP Manager, Display
-         - 'gcpman'  - GCP Manager, points management
-         - 'nviz'    - 3D view mode
-        """
-        # default toolbar
-        if name == "map":
-            self.toolbars['map'] = 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 OnUpdateProgress(self, event):
-        """
-        Update progress bar info
-        """
-        self.GetProgressBar().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)
-        if self.show_target:
-            self.TgtMapWindow.UpdateMap(render=True)
-        
-        # 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.GetToolbar('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.GetToolbar('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 OnPan(self, event):
-        """
-        Panning, set mouse to drag
-        """
-        if self.GetToolbar('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 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 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 OnZoomToRaster(self, event):
-        """!
-        Set display extents to match selected raster map (ignore NULLs)
-        """
-        self.MapWindow.ZoomToMap(ignoreNulls = True)
-        
-    def OnZoomToSaved(self, event):
-        """!Set display geometry to match extents in
-        saved region file
-        """
-        self.MapWindow.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 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
-    
-    def GetSrcWindow(self):
-        return self.SrcMapWindow
-        
-    def GetTgtWindow(self):
-        return self.TgtMapWindow
-    
-    def GetShowTarget(self):
-        return self.show_target
-        
-    def GetMapToolbar(self):
-        """!Returns toolbar with zooming tools"""
-        return self.toolbars['gcpdisp']
-        
-# end of class MapFrame

Deleted: grass/trunk/gui/wxpython/gui_modules/gdialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gdialogs.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gdialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2403 +0,0 @@
-"""!
- at package gdialogs.py
-
- at brief Various dialogs used in wxGUI.
-
-List of classes:
- - ElementDialog
- - LocationDialog
- - MapsetDialog
- - NewVectorDialog
- - SavedRegion
- - DecorationDialog
- - TextLayerDialog 
- - GroupDialog
- - MapLayersDialog
- - ImportDialog
- - GdalImportDialog
- - GdalOutputDialog
- - DxfImportDialog
- - LayersList (used by MultiImport) 
- - SetOpacityDialog
- - StaticWrapText
- - ImageSizeDialog
- - SqlQueryFrame
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
- at author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog)
-"""
-
-import os
-import sys
-import re
-from bisect import bisect
-
-import wx
-import wx.lib.filebrowsebutton as filebrowse
-import wx.lib.mixins.listctrl as listmix
-
-from grass.script import core as grass
-from grass.script import task as gtask
-
-import gcmd
-import globalvar
-import gselect
-import menuform
-import utils
-from preferences import globalSettings as UserSettings
-from debug       import Debug
-
-class ElementDialog(wx.Dialog):
-    def __init__(self, parent, title, label, id = wx.ID_ANY,
-                 etype = False, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
-                 **kwargs):
-        """!General dialog to choose given element (location, mapset, vector map, etc.)
-        
-        @param parent window
-        @param title window title
-        @param label element label
-        @param etype show also ElementSelect
-        """
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-        
-        self.etype = etype
-        self.label = label
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.btnOK     = wx.Button(parent = self.panel, id = wx.ID_OK)
-        self.btnOK.SetDefault()
-        self.btnOK.Enable(False)
-        
-        if self.etype:
-            self.typeSelect = gselect.ElementSelect(parent = self.panel,
-                                                    size = globalvar.DIALOG_GSELECT_SIZE)
-            self.typeSelect.Bind(wx.EVT_CHOICE, self.OnType)
-        
-        self.element = None # must be defined 
-        
-        self.__layout()
-        
-    def PostInit(self):
-        self.element.SetFocus()
-        self.element.Bind(wx.EVT_TEXT, self.OnElement)
-        
-    def OnType(self, event):
-        """!Select element type"""
-        if not self.etype:
-            return
-        evalue = self.typeSelect.GetValue(event.GetString())
-        self.element.SetType(evalue)
-        
-    def OnElement(self, event):
-        """!Name for vector map layer given"""
-        if len(event.GetString()) > 0:
-            self.btnOK.Enable(True)
-        else:
-            self.btnOK.Enable(False)
-        
-    def __layout(self):
-        """!Do layout"""
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        self.dataSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        if self.etype:
-            self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                                    label = _("Type of element:")),
-                               proportion = 0, flag = wx.ALL, border = 1)
-            self.dataSizer.Add(item = self.typeSelect,
-                               proportion = 0, flag = wx.ALL, border = 1)
-        
-        self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                                label = self.label),
-                           proportion = 0, flag = wx.ALL, border = 1)
-        
-        # buttons
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnOK)
-        btnSizer.Realize()
-        
-        self.sizer.Add(item = self.dataSizer, proportion = 1,
-                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.sizer.Add(item = btnSizer, proportion = 0,
-                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-    def GetElement(self):
-        """!Return (mapName, overwrite)"""
-        return self.element.GetValue()
-    
-    def GetType(self):
-        """!Get element type"""
-        return self.element.tcp.GetType()
-        
-class LocationDialog(ElementDialog):
-    """!Dialog used to select location"""
-    def __init__(self, parent, title = _("Select GRASS location and mapset"), id =  wx.ID_ANY):
-        ElementDialog.__init__(self, parent, title, label = _("Name of GRASS location:"))
-
-        self.element = gselect.LocationSelect(parent = self.panel, id = wx.ID_ANY,
-                                              size = globalvar.DIALOG_GSELECT_SIZE)
-
-        self.element1 = gselect.MapsetSelect(parent = self.panel, id = wx.ID_ANY,
-                                             size = globalvar.DIALOG_GSELECT_SIZE,
-                                             setItems = False)
-        
-        self.PostInit()
-        
-        self.__Layout()
-        self.SetMinSize(self.GetSize())
-
-    def __Layout(self):
-        """!Do layout"""
-        self.dataSizer.Add(self.element, proportion = 0,
-                           flag = wx.EXPAND | wx.ALL, border = 1)
- 
-        self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                         label = _("Name of mapset:")), proportion = 0,
-                           flag = wx.EXPAND | wx.ALL, border = 1)
-
-        self.dataSizer.Add(self.element1, proportion = 0,
-                           flag = wx.EXPAND | wx.ALL, border = 1)
-       
-        self.panel.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-    def OnElement(self, event):
-        """!Select mapset given location name"""
-        location = event.GetString()
-        
-        if location:
-            dbase = grass.gisenv()['GISDBASE']
-            self.element1.SetItems(utils.GetListOfMapsets(dbase, location, selectable = True))
-            self.element1.SetSelection(0)
-            mapset = self.element1.GetStringSelection()
-        
-        if location and mapset:
-            self.btnOK.Enable(True)
-        else:
-            self.btnOK.Enable(False)
-
-    def GetValues(self):
-        """!Get location, mapset"""
-        return (self.GetElement(), self.element1.GetStringSelection())
-    
-class MapsetDialog(ElementDialog):
-    """!Dialog used to select mapset"""
-    def __init__(self, parent, title = _("Select mapset in GRASS location"),
-                 location = None, id =  wx.ID_ANY):
-        ElementDialog.__init__(self, parent, title, label = _("Name of mapset:"))
-        if location:
-            self.SetTitle(self.GetTitle() + ' <%s>' % location)
-        else:
-            self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
-        
-        self.element = gselect.MapsetSelect(parent = self.panel, id = wx.ID_ANY,
-                                            size = globalvar.DIALOG_GSELECT_SIZE)
-        
-        self.PostInit()
-        
-        self.__Layout()
-        self.SetMinSize(self.GetSize())
-
-    def __Layout(self):
-        """!Do layout"""
-        self.dataSizer.Add(self.element, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 1)
-        
-        self.panel.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-    def GetMapset(self):
-        return self.GetElement()
-    
-class NewVectorDialog(ElementDialog):
-    def __init__(self, parent, id = wx.ID_ANY, title = _('Create new vector map'),
-                 disableAdd = False, disableTable = False, showType = False,
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
-        """!Dialog for creating new vector map
-
-        @param parent parent window
-        @param id window id
-        @param title window title
-        @param disableAdd disable 'add layer' checkbox
-        @param disableTable disable 'create table' checkbox
-        @param showType True to show feature type selector (used for creating new empty OGR layers)
-        @param style window style
-        @param kwargs other argumentes for ElementDialog
-        
-        @return dialog instance       
-        """
-        ElementDialog.__init__(self, parent, title, label = _("Name for new vector map:"))
-        
-        self.element = gselect.Select(parent = self.panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                                      type = 'vector', mapsets = [grass.gisenv()['MAPSET'],])
-        
-        # determine output format
-        if showType:
-            self.ftype = gselect.OgrTypeSelect(parent = self, panel = self.panel)
-        else:
-            self.ftype = None
-        
-        self.table = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                 label = _("Create attribute table"))
-        self.table.SetValue(True)
-        if disableTable:
-            self.table.Enable(False)
-        
-        if showType:
-            self.keycol = None
-        else:
-            self.keycol = wx.TextCtrl(parent = self.panel, id =  wx.ID_ANY,
-                                      size = globalvar.DIALOG_SPIN_SIZE)
-            self.keycol.SetValue(UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
-            if disableTable:
-                self.keycol.Enable(False)
-        
-        self.addbox = wx.CheckBox(parent = self.panel,
-                                  label = _('Add created map into layer tree'), style = wx.NO_BORDER)
-        if disableAdd:
-            self.addbox.SetValue(True)
-            self.addbox.Enable(False)
-        else:
-            self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
-
-        self.table.Bind(wx.EVT_CHECKBOX, self.OnTable)
-        
-        self.PostInit()
-        
-        self._layout()
-        self.SetMinSize(self.GetSize())
-        
-    def OnMapName(self, event):
-        """!Name for vector map layer given"""
-        self.OnElement(event)
-        
-    def OnTable(self, event):
-        if self.keycol:
-            self.keycol.Enable(event.IsChecked())
-        
-    def _layout(self):
-        """!Do layout"""
-        self.dataSizer.Add(item = self.element, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 1)
-        if self.ftype:
-            self.dataSizer.AddSpacer(1)
-            self.dataSizer.Add(item = self.ftype, proportion = 0,
-                               flag = wx.EXPAND | wx.ALL, border = 1)
-        
-        self.dataSizer.Add(item = self.table, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 1)
-        
-        if self.keycol:
-            keySizer = wx.BoxSizer(wx.HORIZONTAL)
-            keySizer.Add(item = wx.StaticText(parent = self.panel, label = _("Key column:")),
-                         proportion = 0,
-                         flag = wx.ALIGN_CENTER_VERTICAL)
-            keySizer.AddSpacer(10)
-            keySizer.Add(item = self.keycol, proportion = 0,
-                         flag = wx.ALIGN_RIGHT)
-            self.dataSizer.Add(item = keySizer, proportion = 1,
-                               flag = wx.EXPAND | wx.ALL, border = 1)
-            
-        self.dataSizer.AddSpacer(5)
-        
-        self.dataSizer.Add(item = self.addbox, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 1)
-        
-        self.panel.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-    def GetName(self, full = False):
-        """!Get name of vector map to be created
-
-        @param full True to get fully qualified name
-        """
-        name = self.GetElement()
-        if full:
-            if '@' in name:
-                return name
-            else:
-                return name + '@' + grass.gisenv()['MAPSET']
-        
-        return name.split('@', 1)[0]
-
-    def GetKey(self):
-        """!Get key column name"""
-        if self.keycol:
-            return self.keycol.GetValue()
-        return UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value')
-    
-    def IsChecked(self, key):
-        """!Get dialog properties
-
-        @param key window key ('add', 'table')
-
-        @return True/False
-        @return None on error
-        """
-        if key == 'add':
-            return self.addbox.IsChecked()
-        elif key == 'table':
-            return self.table.IsChecked()
-        
-        return None
-    
-    def GetFeatureType(self):
-        """!Get feature type for OGR
-
-        @return feature type as string
-        @return None for native format
-        """
-        if self.ftype:
-            return self.ftype.GetType()
-        
-        return None
-
-def CreateNewVector(parent, cmd, title = _('Create new vector map'),
-                    exceptMap = None, log = None,
-                    disableAdd = False, disableTable = False):
-    """!Create new vector map layer
-    
-    @param cmd (prog, **kwargs)
-    @param title window title
-    @param exceptMap list of maps to be excepted
-    @param log
-    @param disableAdd disable 'add layer' checkbox
-    @param disableTable disable 'create table' checkbox
-    
-    @return dialog instance
-    @return None on error
-    """
-    vExternalOut = grass.parse_command('v.external.out', flags = 'g')
-    isNative = vExternalOut['format'] == 'native'
-    if cmd[0] == 'v.edit' and not isNative:
-        showType = True
-    else:
-        showType = False
-    dlg = NewVectorDialog(parent, title = title,
-                          disableAdd = disableAdd, disableTable = disableTable,
-                          showType = showType)
-    
-    if dlg.ShowModal() != wx.ID_OK:
-        dlg.Destroy()
-        return None
-
-    outmap = dlg.GetName()
-    key    = dlg.GetKey()
-    if outmap == exceptMap:
-        gcmd.GError(parent = parent,
-                    message = _("Unable to create vector map <%s>.") % outmap)
-        dlg.Destroy()
-        return None
-    if dlg.table.IsEnabled() and not key:
-        gcmd.GError(parent = parent,
-                    message = _("Invalid or empty key column.\n"
-                                "Unable to create vector map <%s>.") % outmap)
-        dlg.Destroy()
-        return
-        
-    if outmap == '': # should not happen
-        dlg.Destroy()
-        return None
-
-    # update cmd -> output name defined
-    cmd[1][cmd[2]] = outmap
-    if showType:
-        cmd[1]['type'] = dlg.GetFeatureType()
-        
-    if isNative:
-        listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
-    else:
-        listOfVectors = gcmd.RunCommand('v.external',
-                                        quiet = True,
-                                        parent = parent,
-                                        read = True,
-                                        flags = 'l',
-                                        dsn = vExternalOut['dsn']).splitlines()
-    
-    overwrite = False
-    if not UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
-            outmap in listOfVectors:
-        dlgOw = wx.MessageDialog(parent, message = _("Vector map <%s> already exists "
-                                                     "in the current mapset. "
-                                                     "Do you want to overwrite it?") % outmap,
-                                 caption = _("Overwrite?"),
-                                 style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-        if dlgOw.ShowModal() == wx.ID_YES:
-            overwrite = True
-        else:
-            dlgOw.Destroy()
-            dlg.Destroy()
-            return None
-        
-    if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
-        overwrite = True
-        
-    ret = gcmd.RunCommand(prog = cmd[0],
-                          parent = parent,
-                          overwrite = overwrite,
-                          **cmd[1])
-    if ret != 0:
-        dlg.Destroy()
-        return None
-    
-    if not isNative:
-        # create link for OGR layers
-        gcmd.RunCommand('v.external',
-                        overwrite = overwrite,
-                        parent = parent,
-                        dsn = vExternalOut['dsn'],
-                        layer = outmap)
-        
-    # create attribute table
-    if dlg.table.IsEnabled() and dlg.table.IsChecked():
-        if isNative:
-            sql = 'CREATE TABLE %s (%s INTEGER)' % (outmap, key)
-            
-            gcmd.RunCommand('db.connect',
-                            flags = 'c')
-            
-            Debug.msg(1, "SQL: %s" % sql)
-            gcmd.RunCommand('db.execute',
-                            quiet = True,
-                            parent = parent,
-                            input = '-',
-                            stdin = sql)
-            
-            gcmd.RunCommand('v.db.connect',
-                            quiet = True,
-                            parent = parent,
-                            map = outmap,
-                            table = outmap,
-                            key = key,
-                            layer = '1')
-        # TODO: how to deal with attribute tables for OGR layers?
-            
-    # return fully qualified map name
-    if '@' not in outmap:
-        outmap += '@' + grass.gisenv()['MAPSET']
-        
-    if log:
-        log.WriteLog(_("New vector map <%s> created") % outmap)
-        
-    return dlg
-
-class SavedRegion(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, title = "", loadsave = 'load',
-                 **kwargs):
-        """!Loading and saving of display extents to saved region file
-
-        @param loadsave load or save region?
-        """
-        wx.Dialog.__init__(self, parent, id, title, **kwargs)
-
-        self.loadsave = loadsave
-        self.wind = ''
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        label = wx.StaticText(parent = self, id = wx.ID_ANY)
-        box.Add(item = label, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
-        if loadsave == 'load':
-            label.SetLabel(_("Load region:"))
-            selection = gselect.Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                                       type = 'windows')
-        elif loadsave == 'save':
-            label.SetLabel(_("Save region:"))
-            selection = gselect.Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                                       type = 'windows', mapsets  =  [grass.gisenv()['MAPSET']])
-        
-        box.Add(item = selection, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
-        selection.SetFocus()
-        selection.Bind(wx.EVT_TEXT, self.OnRegion)
-        
-        sizer.Add(item = box, proportion = 0, flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL,
-                  border = 5)
-        
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
-        
-        btnsizer = wx.StdDialogButtonSizer()
-        
-        btn = wx.Button(parent = self, id = wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-        
-        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-        
-        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-        self.Layout()
-        
-    def OnRegion(self, event):
-        self.wind = event.GetString()
-    
-class DecorationDialog(wx.Dialog):
-    """!Controls setting options and displaying/hiding map overlay
-    decorations
-    """
-    def __init__(self, parent, ovlId, title, cmd, name = None,
-                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE,
-                 checktxt = '', ctrltxt = ''):
-        
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
-        
-        self.ovlId   = ovlId   # PseudoDC id
-        self.cmd     = cmd
-        self.name    = name    # overlay name
-        self.parent  = parent  # MapFrame
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY, label = checktxt)
-        if self.parent.Map.GetOverlay(self.ovlId) is None:
-            self.chkbox.SetValue(True)
-        else:
-            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
-        box.Add(item = self.chkbox, proportion = 0,
-                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        optnbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set options"))
-        box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        if self.name == 'legend':
-            box = wx.BoxSizer(wx.HORIZONTAL)
-            resize = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
-            resize.SetToolTipString(_("Click and drag on the map display to set legend"
-                                        " size and position and then press OK"))
-            resize.SetName('resize')
-            if self.parent.IsPaneShown('3d'):
-                resize.Disable()
-            box.Add(item = resize, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-            sizer.Add(item = box, proportion = 0,
-                      flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = _("Drag %s with mouse in pointer mode to position.\n"
-                                      "Double-click to change options." % ctrltxt))
-        if self.name == 'legend':
-            label.SetLabel(label.GetLabel() + _('\nDefine raster map name for legend in '
-                                                'properties dialog.'))
-        box.Add(item = label, proportion = 0,
-                flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20,-1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-
-        # buttons
-        btnsizer = wx.StdDialogButtonSizer()
-
-        self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
-        self.btnOK.SetDefault()
-        if self.name == 'legend':
-            self.btnOK.Enable(False)
-        btnsizer.AddButton(self.btnOK)
-
-        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btnCancel)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
-
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_BUTTON,   self.OnOptions, optnbtn)
-        if self.name == 'legend':
-            self.Bind(wx.EVT_TOGGLEBUTTON,   self.OnResize, resize)
-        self.Bind(wx.EVT_BUTTON,   self.OnCancel,  btnCancel)
-        self.Bind(wx.EVT_BUTTON,   self.OnOK,      self.btnOK)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-        # create overlay if doesn't exist
-        self._createOverlay()
-        
-        if len(self.parent.MapWindow.overlays[self.ovlId]['cmd']) > 1:
-            if name == 'legend':
-                mapName, found = utils.GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd'])
-                if found:
-                    # enable 'OK' button
-                    self.btnOK.Enable()
-                    # set title
-                    self.SetTitle(_('Legend of raster map <%s>') % \
-                                      mapName)
-            
-        
-    def _createOverlay(self):
-        """!Creates overlay"""
-        if not self.parent.GetMap().GetOverlay(self.ovlId):
-            self.newOverlay = self.parent.Map.AddOverlay(id = self.ovlId, type = self.name,
-                                                         command = self.cmd,
-                                                         l_active = False, l_render = False, l_hidden = True)
-            prop = { 'layer' : self.newOverlay,
-                     'params' : None,
-                     'propwin' : None,
-                     'cmd' : self.cmd,
-                     'coords': (0, 0),
-                     'pdcType': 'image' }
-            self.parent.MapWindow2D.overlays[self.ovlId] = prop
-            if self.parent.MapWindow3D:
-                self.parent.MapWindow3D.overlays[self.ovlId] = prop
-                
-        else:
-            if self.parent.MapWindow.overlays[self.ovlId]['propwin'] == None:
-                return
-            
-            self.parent.MapWindow.overlays[self.ovlId]['propwin'].get_dcmd = self.GetOptData
-        
-    def OnOptions(self, event):
-        """!Sets option for decoration map overlays
-        """
-        if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None:
-            # build properties dialog
-            menuform.GUI(parent = self.parent).ParseCommand(cmd = self.cmd,
-                                                            completed = (self.GetOptData, self.name, ''))
-            
-        else:
-            if self.parent.MapWindow.overlays[self.ovlId]['propwin'].IsShown():
-                self.parent.MapWindow.overlays[self.ovlId]['propwin'].SetFocus()
-            else:
-                self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
-        
-    def OnResize(self, event):
-        if self.FindWindowByName('resize').GetValue():
-            self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
-            self.parent.MapWindow.mouse['use'] = 'legend'
-            self.parent.MapWindow.mouse['box'] = 'box'
-            self.parent.MapWindow.pen = wx.Pen(colour = 'Black', width = 2, style = wx.SHORT_DASH)
-        else:
-            self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
-            self.parent.MapWindow.mouse['use'] = 'pointer'
-            
-    def OnCancel(self, event):
-        """!Cancel dialog"""
-        if self.name == 'legend' and self.FindWindowByName('resize').GetValue():
-            self.FindWindowByName('resize').SetValue(False)
-            self.OnResize(None)
-            
-        self.parent.dialogs['barscale'] = None
-        if event and hasattr(self, 'newOverlay'):
-            self.parent.Map.DeleteOverlay(self.newOverlay)
-        self.Destroy()
-
-    def OnOK(self, event):
-        """!Button 'OK' pressed"""
-        # enable or disable overlay
-        self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
-        
-        # update map
-        if self.parent.IsPaneShown('3d'):
-            self.parent.MapWindow.UpdateOverlays()
-        
-        self.parent.MapWindow.UpdateMap()
-        
-        # close dialog
-        self.OnCancel(None)
-        
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """!Process decoration layer data"""
-        # update layer data
-        if params:
-            self.parent.MapWindow.overlays[self.ovlId]['params'] = params
-        if dcmd:
-            self.parent.MapWindow.overlays[self.ovlId]['cmd'] = dcmd
-        self.parent.MapWindow.overlays[self.ovlId]['propwin'] = propwin
-
-        # change parameters for item in layers list in render.Map
-        # "Use mouse..." (-m) flag causes GUI freeze and is pointless here, trac #119
-        
-        try:
-            self.parent.MapWindow.overlays[self.ovlId]['cmd'].remove('-m')
-        except ValueError:
-            pass
-            
-        self.parent.Map.ChangeOverlay(id = self.ovlId, type = self.name,
-                                      command = self.parent.MapWindow.overlays[self.ovlId]['cmd'],
-                                      l_active = self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive(),
-                                      l_render = False, l_hidden = True)
-        if  self.name == 'legend':
-            if params and not self.btnOK.IsEnabled():
-                self.btnOK.Enable()
-            
-class TextLayerDialog(wx.Dialog):
-    """
-    Controls setting options and displaying/hiding map overlay decorations
-    """
-
-    def __init__(self, parent, ovlId, title, name = 'text',
-                 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE):
-
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
-        from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
-
-        self.ovlId = ovlId
-        self.parent = parent
-
-        if self.ovlId in self.parent.MapWindow.textdict.keys():
-            self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
-            self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
-            self.currClr  = self.parent.MapWindow.textdict[self.ovlId]['color']
-            self.currRot  = self.parent.MapWindow.textdict[self.ovlId]['rotation']
-            self.currCoords = self.parent.MapWindow.textdict[self.ovlId]['coords']
-            self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
-        else:
-            self.currClr = wx.BLACK
-            self.currText = ''
-            self.currFont = self.GetFont()
-            self.currRot = 0.0
-            self.currCoords = [10, 10]
-            self.currBB = wx.Rect()
-
-        self.sizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.GridBagSizer(vgap = 5, hgap = 5)
-
-        # show/hide
-        self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                  label = _('Show text object'))
-        if self.parent.Map.GetOverlay(self.ovlId) is None:
-            self.chkbox.SetValue(True)
-        else:
-            self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
-        box.Add(item = self.chkbox, span = (1,2),
-                flag = wx.ALIGN_LEFT|wx.ALL, border = 5,
-                pos = (0, 0))
-
-        # text entry
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Enter text:"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL,
-                pos = (1, 0))
-
-        self.textentry = ExpandoTextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (300,-1))
-        self.textentry.SetFont(self.currFont)
-        self.textentry.SetForegroundColour(self.currClr)
-        self.textentry.SetValue(self.currText)
-        # get rid of unneeded scrollbar when text box first opened
-        self.textentry.SetClientSize((300,-1))
-        
-        box.Add(item = self.textentry,
-                pos = (1, 1))
-
-        # rotation
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Rotation:"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL,
-                pos = (2, 0))
-        self.rotation = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                    size = (75,-1), style = wx.SP_ARROW_KEYS)
-        self.rotation.SetRange(-360, 360)
-        self.rotation.SetValue(int(self.currRot))
-        box.Add(item = self.rotation,
-                flag = wx.ALIGN_RIGHT,
-                pos = (2, 1))
-
-        # font
-        fontbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set font"))
-        box.Add(item = fontbtn,
-                flag = wx.ALIGN_RIGHT,
-                pos = (3, 1))
-
-        self.sizer.Add(item = box, proportion = 1,
-                  flag = wx.ALL, border = 10)
-
-        # note
-        box = wx.BoxSizer(wx.HORIZONTAL)
-        label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = _("Drag text with mouse in pointer mode "
-                                      "to position.\nDouble-click to change options"))
-        box.Add(item = label, proportion = 0,
-                flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
-        self.sizer.Add(item = box, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border = 5)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                             size = (20,-1), style = wx.LI_HORIZONTAL)
-        self.sizer.Add(item = line, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(parent = self, id = wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        self.sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        self.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-        # bindings
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
-        self.Bind(wx.EVT_BUTTON,     self.OnSelectFont, fontbtn)
-        self.Bind(wx.EVT_TEXT,       self.OnText,       self.textentry)
-        self.Bind(wx.EVT_SPINCTRL,   self.OnRotation,   self.rotation)
-
-    def OnRefit(self, event):
-        """!Resize text entry to match text"""
-        self.sizer.Fit(self)
-
-    def OnText(self, event):
-        """!Change text string"""
-        self.currText = event.GetString()
-
-    def OnRotation(self, event):
-        """!Change rotation"""
-        self.currRot = event.GetInt()
-
-        event.Skip()
-
-    def OnSelectFont(self, event):
-        """!Change font"""
-        data = wx.FontData()
-        data.EnableEffects(True)
-        data.SetColour(self.currClr)         # set colour
-        data.SetInitialFont(self.currFont)
-
-        dlg = wx.FontDialog(self, data)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            data = dlg.GetFontData()
-            self.currFont = data.GetChosenFont()
-            self.currClr = data.GetColour()
-
-            self.textentry.SetFont(self.currFont)
-            self.textentry.SetForegroundColour(self.currClr)
-
-            self.Layout()
-
-        dlg.Destroy()
-
-    def GetValues(self):
-        """!Get text properties"""
-        return { 'text' : self.currText,
-                 'font' : self.currFont,
-                 'color' : self.currClr,
-                 'rotation' : self.currRot,
-                 'coords' : self.currCoords,
-                 'active' : self.chkbox.IsChecked() }
-
-class GroupDialog(wx.Dialog):
-    """!Dialog for creating/editing groups"""
-    def __init__(self, parent = None, defaultGroup = None, 
-                 title = _("Create or edit imagery groups"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-                     
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
-                            style = style, **kwargs)
-                            
-        self.parent = parent
-        self.defaultGroup = defaultGroup
-        self.currentGroup = self.defaultGroup
-        self.groupChanged = False
-        
-        self.bodySizer = self._createDialogBody()
-        
-        # buttons
-        btnOk = wx.Button(parent = self, id = wx.ID_OK)
-        btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
-        btnClose = wx.Button(parent = self, id = wx.ID_CANCEL)
-        
-        btnOk.SetToolTipString(_("Apply changes to selected group and close dialog"))
-        btnApply.SetToolTipString(_("Apply changes to selected group"))
-        btnClose.SetToolTipString(_("Close dialog, changes are not applied"))
-
-        btnOk.SetDefault()
-        
-        # sizers & do layout
-        # btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        # btnSizer.Add(item = btnClose, proportion = 0,
-        #              flag = wx.RIGHT | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
-        # btnSizer.Add(item = btnApply, proportion = 0,
-        #              flag = wx.LEFT, border = 5)
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnOk)
-        btnSizer.AddButton(btnApply)
-        btnSizer.AddButton(btnClose)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.bodySizer, proportion = 1,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
-        mainSizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                      style = wx.LI_HORIZONTAL), proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10) 
-        
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.ALL | wx.ALIGN_RIGHT, border = 10)
-
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        
-        btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
-
-        # set dialog min size
-        self.SetMinSize(self.GetSize())
-        
-    def _createDialogBody(self):
-        bodySizer = wx.BoxSizer(wx.VERTICAL)
-    
-        # group selection
-        bodySizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = _("Select the group you want to edit or "
-                                                     "enter name of new group:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
-        self.groupSelect = gselect.Select(parent = self, type = 'group',
-                                          mapsets = [grass.gisenv()['MAPSET']],
-                                          size = globalvar.DIALOG_GSELECT_SIZE) # searchpath?
-            
-        bodySizer.Add(item = self.groupSelect, flag = wx.TOP | wx.EXPAND, border = 5)
-        
-        bodySizer.AddSpacer(10)
-        # layers in group
-        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Layers in selected group:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM, border = 5)
-        
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        gridSizer.AddGrowableCol(0)
-        
-        self.layerBox = wx.ListBox(parent = self,  id = wx.ID_ANY, size = (-1, 150),
-                                   style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
-        
-        gridSizer.Add(item = self.layerBox, pos = (0, 0), span = (2, 1), flag = wx.EXPAND)
-        
-        self.addLayer = wx.Button(self, id = wx.ID_ADD)
-        self.addLayer.SetToolTipString(_("Select map layers and add them to the list."))
-        gridSizer.Add(item = self.addLayer, pos = (0, 1))
-        
-        self.removeLayer = wx.Button(self, id = wx.ID_REMOVE)
-        self.removeLayer.SetToolTipString(_("Remove selected layer(s) from list."))
-        gridSizer.Add(item = self.removeLayer, pos = (1, 1))
-        
-        bodySizer.Add(item = gridSizer, proportion = 1, flag = wx.EXPAND)
-        
-        self.infoLabel = wx.StaticText(parent = self, id = wx.ID_ANY)
-        bodySizer.Add(item = self.infoLabel, 
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, border = 5)
-        
-        # bindings
-        self.groupSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnGroupSelected)
-        self.addLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
-        self.removeLayer.Bind(wx.EVT_BUTTON, self.OnRemoveLayer)
-        
-        if self.defaultGroup:
-            self.groupSelect.SetValue(self.defaultGroup)
-        
-        return bodySizer
-        
-    def OnAddLayer(self, event):
-        """!Add new layer to listbox"""
-        dlg = MapLayersDialog(parent = self, title = _("Add selected map layers into group"),
-                              mapType = 'raster', selectAll = False,
-                              fullyQualified = True, showFullyQualified = False)
-        if dlg.ShowModal() != wx.ID_OK:
-            dlg.Destroy()
-            return
-        
-        layers = dlg.GetMapLayers()
-        for layer in layers:
-            if layer not in self.GetLayers():
-                self.layerBox.Append(layer)
-                self.groupChanged = True
-            
-    
-    def OnRemoveLayer(self, event):
-        """!Remove layer from listbox"""
-        while self.layerBox.GetSelections():
-            sel = self.layerBox.GetSelections()[0]
-            self.layerBox.Delete(sel)
-            self.groupChanged = True
-                
-    def GetLayers(self):
-        """!Get layers"""
-        return self.layerBox.GetItems()
-        
-    def OnGroupSelected(self, event):
-        """!Text changed in group selector"""
-        # callAfter must be called to close popup before other actions
-        wx.CallAfter(self.GroupSelected)
-        
-    def GroupSelected(self):
-        """!Group was selected, check if changes were apllied"""
-        group = self.GetSelectedGroup()
-        if self.groupChanged:
-            dlg = wx.MessageDialog(self, message = _("Group <%s> was changed, "
-                                                     "do you want to apply changes?") % self.currentGroup,
-                                   caption = _("Unapplied changes"),
-                                   style = wx.YES_NO | wx.ICON_QUESTION | wx.YES_DEFAULT)
-            if dlg.ShowModal() == wx.ID_YES:
-                self.ApplyChanges(showResult = True)
-                
-            dlg.Destroy()
-            
-            
-        
-        groups = self.GetExistGroups()
-        if group in groups:
-            self.ShowGroupLayers(self.GetGroupLayers(group))
-            
-        self.currentGroup = group
-        self.groupChanged = False
-        
-        self.ClearNotification()
-        
-    def ShowGroupLayers(self, mapList):
-        """!Show map layers in currently selected group"""
-        self.layerBox.Set(mapList)
-        
-        
-    def EditGroup(self, group):
-        """!Edit selected group"""
-        layersNew = self.GetLayers()
-        layersOld = self.GetGroupLayers(group)
-        
-        add = []
-        remove = []
-        for layerNew in layersNew:
-            if layerNew not in layersOld:
-                add.append(layerNew)
-                
-        for layerOld in layersOld:
-            if layerOld not in layersNew:
-                remove.append(layerOld)
-        
-        ret = None
-        if remove:
-            ret = gcmd.RunCommand('i.group',
-                                  parent = self,
-                                  group = group,
-                                  flags = 'r',
-                                  input = ','.join(remove))
-                        
-        if add:
-            ret = gcmd.RunCommand('i.group',
-                                  parent = self,
-                                  group = group,
-                                  input = ','.join(add))
-                            
-        return ret
-        
-    def CreateNewGroup(self, group):
-        """!Create new group"""
-        layers = self.GetLayers()
-        ret = gcmd.RunCommand('i.group',
-                              parent = self,
-                              group = group,
-                              input = layers)
-        return ret
-        
-                        
-    def GetExistGroups(self):
-        """!Returns existing groups in current mapset"""
-        return grass.list_grouped('group')[grass.gisenv()['MAPSET']]
-        
-    def ShowResult(self, group, returnCode, create):
-        """!Show if operation was successfull."""
-        group += '@' + grass.gisenv()['MAPSET']
-        if returnCode is None:
-            label = _("No changes to apply in group <%s>.") % group
-        elif returnCode == 0:
-            if create:
-                label = _("Group <%s> was successfully created.") % group
-            else:
-                label = _("Group <%s> was successfully changed.") % group
-        else:
-            if create:
-                label = _("Creating of new group <%s> failed.") % group
-            else:
-                label = _("Changing of group <%s> failed.") % group
-                
-        self.infoLabel.SetLabel(label)
-        wx.FutureCall(4000, self.ClearNotification)
-        
-    def GetSelectedGroup(self):
-        """!Return currently selected group (without mapset)"""
-        return self.groupSelect.GetValue().split('@')[0]
-        
-    def GetGroupLayers(self, group):
-        """!Get layers in group"""
-        res = gcmd.RunCommand('i.group',
-                              parent = self,
-                              flags = 'g',
-                              group = group,
-                              read = True).strip()
-        if res.split('\n')[0]:
-            return res.split('\n')
-        return []
-        
-    def ClearNotification(self):
-        """!Clear notification string"""
-        self.infoLabel.SetLabel("")
-       
-    def ApplyChanges(self, showResult):
-        """!Create or edit group"""
-        group = self.currentGroup
-        if not group:
-            gcmd.GMessage(parent = self,
-                          message = _("No group selected."))
-            return False
-        
-        groups = self.GetExistGroups()
-        if group in groups:
-            ret = self.EditGroup(group)
-            self.ShowResult(group = group, returnCode = ret, create = False)
-            
-        else:
-            ret = self.CreateNewGroup(group)
-            self.ShowResult(group = group, returnCode = ret, create = True)
-            
-        self.groupChanged = False
-        
-        return True
-        
-    def OnApply(self, event):
-        """!Apply changes"""
-        self.ApplyChanges(showResult = True)
-        
-    def OnOk(self, event):
-        """!Apply changes and close dialog"""
-        if self.ApplyChanges(showResult = False):
-            self.OnClose(event)
-        
-    def OnClose(self, event):
-        """!Close dialog"""
-        if not self.IsModal():
-            self.Destroy()
-        event.Skip()
-        
-class MapLayersDialog(wx.Dialog):
-    def __init__(self, parent, title, modeler = False,
-                 mapType = None, selectAll = True, fullyQualified = True, showFullyQualified = True, 
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        """!Dialog for selecting map layers (raster, vector)
-        
-        @param mapType type of map (if None: raster, vector, 3d raster, if one only: selects it and disables selection)
-        @param selectAll all/none maps should be selected by default
-        @param fullyQualified True if dialog should return full map names by default
-        @param showFullyQualified True to show 'fullyQualified' checkbox, otherwise hide it
-        """
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
-                           style = style, **kwargs)
-        
-        self.parent = parent # GMFrame or ?
-        self.mapType = mapType
-        self.selectAll = selectAll
-        
-        # dialog body
-        self.bodySizer = self._createDialogBody()
-        # update list of layer to be loaded
-        self.map_layers = [] # list of map layers (full list type/mapset)
-        self.LoadMapLayers(self.GetLayerType(cmd = True),
-                           self.mapset.GetStringSelection())
-        
-        self.fullyQualified = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                          label = _("Use fully-qualified map names"))
-        self.fullyQualified.SetValue(fullyQualified)
-        self.fullyQualified.Show(showFullyQualified)
-
-        self.dseries = None
-        if modeler:
-            self.dseries = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                       label = _("Dynamic series (%s)") % 'g.mlist')
-            self.dseries.SetValue(False)
-        
-        # buttons
-        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
-        btnOk = wx.Button(parent = self, id = wx.ID_OK)
-        btnOk.SetDefault()
-        
-        # sizers & do layout
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        btnSizer.AddButton(btnOk)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.bodySizer, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = self.fullyQualified, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
-        if self.dseries:
-            mainSizer.Add(item = self.dseries, proportion = 0,
-                          flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
-        
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-        # set dialog min size
-        self.SetMinSize(self.GetSize())
-        
-    def _createDialogBody(self):
-        bodySizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        bodySizer.AddGrowableCol(1)
-        bodySizer.AddGrowableRow(3)
-        
-        # layer type
-        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Map type:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0,0))
-        
-        self.layerType = wx.Choice(parent = self, id = wx.ID_ANY,
-                                   choices = [_('raster'), _('3D raster'), _('vector')], size = (100,-1))
-        
-        if self.mapType:
-            self.layerType.SetStringSelection(self.mapType)
-            self.layerType.Disable()
-        else:
-            self.layerType.SetSelection(0)
-            
-        bodySizer.Add(item = self.layerType,
-                      pos = (0,1))
-        
-        # select toggle
-        self.toggle = wx.CheckBox(parent = self, id = wx.ID_ANY,
-                                  label = _("Select toggle"))
-        self.toggle.SetValue(self.selectAll)
-        bodySizer.Add(item = self.toggle,
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0,2))
-        
-        # mapset filter
-        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Mapset:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (1,0))
-        
-        self.mapset = gselect.MapsetSelect(parent = self, searchPath = True)
-        self.mapset.SetStringSelection(grass.gisenv()['MAPSET'])
-        bodySizer.Add(item = self.mapset,
-                      pos = (1,1), span = (1, 2))
-        
-        # map name filter
-        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Pattern:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2,0))
-        
-        self.filter = wx.TextCtrl(parent = self, id = wx.ID_ANY,
-                                  value = "",
-                                  size = (250,-1))
-        bodySizer.Add(item = self.filter,
-                      flag = wx.EXPAND,
-                      pos = (2,1), span = (1, 2))
-        
-        # layer list 
-        bodySizer.Add(item = wx.StaticText(parent = self, label = _("List of maps:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
-                      pos = (3,0))
-        self.layers = wx.CheckListBox(parent = self, id = wx.ID_ANY,
-                                      size = (250, 100),
-                                      choices = [])
-        bodySizer.Add(item = self.layers,
-                      flag = wx.EXPAND,
-                      pos = (3,1), span = (1, 2))
-        
-        # bindings
-        self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
-        self.mapset.Bind(wx.EVT_COMBOBOX, self.OnChangeParams)
-        self.layers.Bind(wx.EVT_RIGHT_DOWN, self.OnMenu)
-        self.filter.Bind(wx.EVT_TEXT, self.OnFilter)
-        self.toggle.Bind(wx.EVT_CHECKBOX, self.OnToggle)
-        
-        return bodySizer
-
-    def LoadMapLayers(self, type, mapset):
-        """!Load list of map layers
-
-        @param type layer type ('raster' or 'vector')
-        @param mapset mapset name
-        """
-        self.map_layers = grass.mlist_grouped(type = type)[mapset]
-        self.layers.Set(self.map_layers)
-        
-        # check all items by default
-        for item in range(self.layers.GetCount()):
-            
-            self.layers.Check(item, check = self.selectAll)
-        
-    def OnChangeParams(self, event):
-        """!Filter parameters changed by user"""
-        # update list of layer to be loaded
-        self.LoadMapLayers(self.GetLayerType(cmd = True),
-                           self.mapset.GetStringSelection())
-        
-        event.Skip()
-        
-    def OnMenu(self, event):
-        """!Table description area, context menu"""
-        if not hasattr(self, "popupID1"):
-            self.popupDataID1 = wx.NewId()
-            self.popupDataID2 = wx.NewId()
-            self.popupDataID3 = wx.NewId()
-
-            self.Bind(wx.EVT_MENU, self.OnSelectAll,    id = self.popupDataID1)
-            self.Bind(wx.EVT_MENU, self.OnSelectInvert, id = self.popupDataID2)
-            self.Bind(wx.EVT_MENU, self.OnDeselectAll,  id = self.popupDataID3)
-        
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupDataID1, _("Select all"))
-        menu.Append(self.popupDataID2, _("Invert selection"))
-        menu.Append(self.popupDataID3, _("Deselect all"))
-        
-        self.PopupMenu(menu)
-        menu.Destroy()
-        
-    def OnSelectAll(self, event):
-        """!Select all map layer from list"""
-        for item in range(self.layers.GetCount()):
-            self.layers.Check(item, True)
-        
-    def OnSelectInvert(self, event):
-        """!Invert current selection"""
-        for item in range(self.layers.GetCount()):
-            if self.layers.IsChecked(item):
-                self.layers.Check(item, False)
-            else:
-                self.layers.Check(item, True)
-        
-    def OnDeselectAll(self, event):
-        """!Select all map layer from list"""
-        for item in range(self.layers.GetCount()):
-            self.layers.Check(item, False)
-        
-    def OnFilter(self, event):
-        """!Apply filter for map names"""
-        if len(event.GetString()) == 0:
-           self.layers.Set(self.map_layers) 
-           return 
-        
-        list = []
-        for layer in self.map_layers:
-            try:
-                if re.compile('^' + event.GetString()).search(layer):
-                    list.append(layer)
-            except:
-                pass
-        
-        self.layers.Set(list)
-        self.OnSelectAll(None)
-        
-        event.Skip()
-        
-    def OnToggle(self, event):
-        """!Select toggle (check or uncheck all layers)"""
-        check = event.Checked()
-        for item in range(self.layers.GetCount()):
-            self.layers.Check(item, check)
-        
-        event.Skip()
-        
-    def GetMapLayers(self):
-        """!Return list of checked map layers"""
-        layerNames = []
-        for indx in self.layers.GetSelections():
-            # layers.append(self.layers.GetStringSelec(indx))
-            pass
-
-        fullyQualified = self.fullyQualified.IsChecked()
-        mapset = self.mapset.GetStringSelection()
-        for item in range(self.layers.GetCount()):
-            if not self.layers.IsChecked(item):
-                continue
-            if fullyQualified:
-                layerNames.append(self.layers.GetString(item) + '@' + mapset)
-            else:
-                layerNames.append(self.layers.GetString(item))
-        
-        return layerNames
-    
-    def GetLayerType(self, cmd = False):
-        """!Get selected layer type
-
-        @param cmd True for g.mlist
-        """
-        if not cmd:
-            return self.layerType.GetStringSelection()
-        
-        sel = self.layerType.GetSelection()
-        if sel == 0:
-            ltype = 'rast'
-        elif sel == 1:
-            ltype = 'rast3d'
-        else:
-            ltype = 'vect'
-        
-        return ltype
-
-    def GetDSeries(self):
-        """!Used by modeler only
-
-        @return g.mlist command
-        """
-        if not self.dseries or not self.dseries.IsChecked():
-            return ''
-        
-        cond = 'map in `g.mlist type=%s ' % self.GetLayerType(cmd = True)
-        patt = self.filter.GetValue()
-        if patt:
-            cond += 'pattern=%s ' % patt
-        cond += 'mapset=%s`' % self.mapset.GetStringSelection()
-        
-        return cond
-    
-class ImportDialog(wx.Dialog):
-    """!Dialog for bulk import of various data (base class)"""
-    def __init__(self, parent, itype,
-                 id = wx.ID_ANY, title = _("Multiple import"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        self.parent = parent    # GMFrame 
-        self.importType = itype
-        self.options = dict()   # list of options
-        
-        self.commandId = -1  # id of running command
-        
-        wx.Dialog.__init__(self, parent, id, title, style = style,
-                           name = "MultiImportDialog")
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.layerBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                     label = _(" List of %s layers ") % self.importType.upper())
-        
-        #
-        # list of layers
-        #
-        columns = [_('Layer id'),
-                   _('Layer name'),
-                   _('Name for GRASS map (editable)')]
-        if itype == 'ogr':
-            columns.insert(2, _('Feature type'))
-        self.list = LayersList(parent = self.panel, columns = columns)
-        self.list.LoadData()
-
-        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                      label = "%s" % _("Options"))
-        
-        cmd = self._getCommand()
-        task = gtask.parse_interface(cmd)
-        for f in task.get_options()['flags']:
-            name = f.get('name', '')
-            desc = f.get('label', '')
-            if not desc:
-                desc = f.get('description', '')
-            if not name and not desc:
-                continue
-            if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
-                continue
-            elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
-                continue
-            elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
-                continue
-            elif cmd == 'v.external' and name not in ('b'):
-                continue
-            elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
-                continue
-            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                             label = desc)
-        
-        
-        self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                     label = _("Allow output files to overwrite existing files"))
-        self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
-        
-        self.add = wx.CheckBox(parent = self.panel, id = wx.ID_ANY)
-        
-        #
-        # buttons
-        #
-        # cancel
-        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.btn_cancel.SetToolTipString(_("Close dialog"))
-        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        # run
-        self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
-        self.btn_run.SetToolTipString(_("Import selected layers"))
-        self.btn_run.SetDefault()
-        self.btn_run.Enable(False)
-        self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
-        # run command dialog
-        self.btn_cmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                 label = _("Command dialog"))
-        self.btn_cmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
-        
-    def doLayout(self):
-        """!Do layout"""
-        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # dsn input
-        dialogSizer.Add(item = self.dsnInput, proportion = 0,
-                        flag = wx.EXPAND)
-        
-        #
-        # list of DXF layers
-        #
-        layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
-
-        layerSizer.Add(item = self.list, proportion = 1,
-                      flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        dialogSizer.Add(item = layerSizer, proportion = 1,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-
-        # options
-        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
-        for key in self.options.keys():
-            optionSizer.Add(item = self.options[key], proportion = 0)
-            
-        dialogSizer.Add(item = optionSizer, proportion = 0,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-        
-        dialogSizer.Add(item = self.overwrite, proportion = 0,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        
-        dialogSizer.Add(item = self.add, proportion = 0,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        
-        #
-        # buttons
-        #
-        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-        
-        btnsizer.Add(item = self.btn_cmd, proportion = 0,
-                     flag = wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        
-        btnsizer.Add(item = self.btn_cancel, proportion = 0,
-                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        
-        btnsizer.Add(item = self.btn_run, proportion = 0,
-                     flag = wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        
-        dialogSizer.Add(item = btnsizer, proportion = 0,
-                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
-                        border = 10)
-        
-        # dialogSizer.SetSizeHints(self.panel)
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(dialogSizer)
-        dialogSizer.Fit(self.panel)
-        
-        # auto-layout seems not work here - FIXME
-        size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, 550)
-        self.SetMinSize(size)
-        self.SetSize((size.width, size.height + 100))
-        # width = self.GetSize()[0]
-        # self.list.SetColumnWidth(col = 1, width = width / 2 - 50)
-        self.Layout()
-
-    def _getCommand(self):
-        """!Get command"""
-        return ''
-    
-    def OnCancel(self, event = None):
-        """!Close dialog"""
-        self.Close()
-
-    def OnRun(self, event):
-        """!Import/Link data (each layes as separate vector map)"""
-        pass
-
-    def OnCmdDialog(self, event):
-        """!Show command dialog"""
-        pass
-    
-    def AddLayers(self, returncode, cmd = None):
-        """!Add imported/linked layers into layer tree"""
-        self.commandId += 1
-        
-        if not self.add.IsChecked() or returncode != 0:
-            return
-        
-        maptree = self.parent.curr_page.maptree
-        
-        layer, output = self.list.GetLayers()[self.commandId]
-        
-        if '@' not in output:
-            name = output + '@' + grass.gisenv()['MAPSET']
-        else:
-            name = output
-        
-        # add imported layers into layer tree
-        if self.importType == 'gdal':
-            cmd = ['d.rast',
-                   'map=%s' % name]
-            if UserSettings.Get(group = 'cmd', key = 'rasterOverlay', subkey = 'enabled'):
-                cmd.append('-o')
-                
-            item = maptree.AddLayer(ltype = 'raster',
-                                    lname = name, lchecked = False,
-                                    lcmd = cmd)
-        else:
-            item = maptree.AddLayer(ltype = 'vector',
-                                    lname = name, lchecked = False,
-                                    lcmd = ['d.vect',
-                                            'map=%s' % name])
-        
-        maptree.mapdisplay.MapWindow.ZoomToMap()
-        
-    def OnAbort(self, event):
-        """!Abort running import
-
-        @todo not yet implemented
-        """
-        pass
-
-class GdalImportDialog(ImportDialog):
-    def __init__(self, parent, ogr = False, link = False):
-        """!Dialog for bulk import of various raster/vector data
-
-        @param parent parent window
-        @param ogr True for OGR (vector) otherwise GDAL (raster)
-        @param link True for linking data otherwise importing data
-        """
-        self.link = link
-        self.ogr  = ogr
-        
-        if ogr:
-            ImportDialog.__init__(self, parent, itype = 'ogr')
-            if link:
-                self.SetTitle(_("Link external vector data"))
-            else:
-                self.SetTitle(_("Import vector data"))
-        else:
-            ImportDialog.__init__(self, parent, itype = 'gdal') 
-            if link:
-                self.SetTitle(_("Link external raster data"))
-            else:
-                self.SetTitle(_("Import raster data"))
-        
-        self.dsnInput = gselect.GdalSelect(parent = self, panel = self.panel, ogr = ogr)
-        
-        if link:
-            self.add.SetLabel(_("Add linked layers into layer tree"))
-        else:
-            self.add.SetLabel(_("Add imported layers into layer tree"))
-        
-        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
-
-        if link:
-            self.btn_run.SetLabel(_("&Link"))
-            self.btn_run.SetToolTipString(_("Link selected layers"))
-            if ogr:
-                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'v.external')
-            else:
-                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'r.external')
-        else:
-            self.btn_run.SetLabel(_("&Import"))
-            self.btn_run.SetToolTipString(_("Import selected layers"))
-            if ogr:
-                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'v.in.ogr')
-            else:
-                self.btn_cmd.SetToolTipString(_('Open %s dialog') % 'r.in.gdal')
-        
-        self.doLayout()
-
-    def OnRun(self, event):
-        """!Import/Link data (each layes as separate vector map)"""
-        data = self.list.GetLayers()
-        
-        # hide dialog
-        self.Hide()
-        
-        dsn = self.dsnInput.GetDsn()
-        ext = self.dsnInput.GetFormatExt()
-            
-        for layer, output in data:
-            if self.importType == 'ogr':
-                if ext and layer.rfind(ext) > -1:
-                    layer = layer.replace('.' + ext, '')
-                if self.link:
-                    cmd = ['v.external',
-                           'dsn=%s' % dsn,
-                           'output=%s' % output,
-                           'layer=%s' % layer]
-                else:
-                    cmd = ['v.in.ogr',
-                           'dsn=%s' % dsn,
-                           'layer=%s' % layer,
-                           'output=%s' % output]
-            else: # gdal
-                if self.dsnInput.GetType() == 'dir':
-                    idsn = os.path.join(dsn, layer)
-                else:
-                    idsn = dsn
-                
-                if self.link:
-                    cmd = ['r.external',
-                           'input=%s' % idsn,
-                           'output=%s' % output]
-                else:
-                    cmd = ['r.in.gdal',
-                           'input=%s' % idsn,
-                           'output=%s' % output]
-            
-            if self.overwrite.IsChecked():
-                cmd.append('--overwrite')
-            
-            for key in self.options.keys():
-                if self.options[key].IsChecked():
-                    cmd.append('-%s' % key)
-            
-            if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
-                cmd.append('--overwrite')
-            
-            # run in Layer Manager
-            self.parent.goutput.RunCmd(cmd, switchPage = True,
-                                       onDone = self.AddLayers)
-        
-        self.OnCancel()
-
-    def _getCommand(self):
-        """!Get command"""
-        if self.link:
-            if self.ogr:
-                return 'v.external'
-            else:
-                return 'r.external'
-        else:
-            if self.ogr:
-                return 'v.in.ogr'
-            else:
-                return 'r.in.gdal'
-        
-        return ''
-    
-    def OnCmdDialog(self, event):
-        """!Show command dialog"""
-        name = self._getCommand()
-        menuform.GUI(parent = self, modal = False).ParseCommand(cmd = [name])
-
-class GdalOutputDialog(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, ogr = False,
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
-        """!Dialog for setting output format for rasters/vectors
-
-        @param parent parent window
-        @param id window id
-        @param ogr True for OGR (vector) otherwise GDAL (raster)
-        @param style window style
-        @param *kwargs other wx.Dialog's arguments
-        """
-        self.parent = parent # GMFrame 
-        self.ogr = ogr
-        wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
-        if self.ogr:
-            self.SetTitle(_("Define output format for vector data"))
-        else:
-            self.SetTitle(_("Define output format for raster data"))
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
-        # buttons
-        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                label = _("Command dialog"))
-        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
-        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.btnCancel.SetToolTipString(_("Close dialog"))
-        self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
-        self.btnOk.SetToolTipString(_("Set external format and close dialog"))
-        self.btnOk.SetDefault()
-        self.btnOk.Enable(False)
-        
-        self.dsnInput = gselect.GdalSelect(parent = self, panel = self.panel,
-                                           ogr = ogr,
-                                           exclude = ['file', 'protocol'], dest = True)
-        
-        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
-        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
-        
-        self._layout()
-
-    def _layout(self):
-        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        dialogSizer.Add(item = self.dsnInput, proportion = 0,
-                        flag = wx.EXPAND)
-
-        btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-        btnSizer.Add(item = self.btnCmd, proportion = 0,
-                     flag = wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        btnSizer.Add(item = self.btnCancel, proportion = 0,
-                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        btnSizer.Add(item = self.btnOk, proportion = 0,
-                     flag = wx.RIGHT | wx.ALIGN_CENTER,
-                     border = 10)
-        
-        dialogSizer.Add(item = btnSizer, proportion = 0,
-                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
-                        border = 10)
-        
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(dialogSizer)
-        dialogSizer.Fit(self.panel)
-
-        size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, self.GetBestSize()[1])
-        self.SetMinSize(size)
-        self.SetSize((size.width, size.height))
-        self.Layout()
-        
-    def OnCmdDialog(self, event):
-        menuform.GUI(parent = self, modal = True).ParseCommand(cmd = ['v.external.out'])
-    
-    def OnCancel(self, event):
-        self.Destroy()
-        
-    def OnOK(self, event):
-        if self.dsnInput.GetType() == 'native':
-            gcmd.RunCommand('v.external.out',
-                            parent = self,
-                            flags = 'r')
-        else:
-            dsn = self.dsnInput.GetDsn()
-            frmt = self.dsnInput.GetFormat()
-            options = self.dsnInput.GetOptions()
-            
-            gcmd.RunCommand('v.external.out',
-                            parent = self,
-                            dsn = dsn, format = frmt,
-                            options = options)
-        self.Close()
-        
-class DxfImportDialog(ImportDialog):
-    """!Dialog for bulk import of DXF layers""" 
-    def __init__(self, parent):
-        ImportDialog.__init__(self, parent, itype = 'dxf',
-                              title = _("Import DXF layers"))
-        
-        self.dsnInput = filebrowse.FileBrowseButton(parent = self.panel, id = wx.ID_ANY, 
-                                                    size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
-                                                    dialogTitle = _('Choose DXF file to import'),
-                                                    buttonText = _('Browse'),
-                                                    startDirectory = os.getcwd(), fileMode = 0,
-                                                    changeCallback = self.OnSetDsn,
-                                                    fileMask = "DXF File (*.dxf)|*.dxf")
-        
-        self.add.SetLabel(_("Add imported layers into layer tree"))
-        
-        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
-        
-        self.doLayout()
-
-    def _getCommand(self):
-        """!Get command"""
-        return 'v.in.dxf'
-    
-    def OnRun(self, event):
-        """!Import/Link data (each layes as separate vector map)"""
-        data = self.list.GetLayers()
-        
-        # hide dialog
-        self.Hide()
-        
-        inputDxf = self.dsnInput.GetValue()
-        
-        for layer, output in data:
-            cmd = ['v.in.dxf',
-                   'input=%s' % inputDxf,
-                   'layers=%s' % layer,
-                   'output=%s' % output]
-
-            for key in self.options.keys():
-                if self.options[key].IsChecked():
-                    cmd.append('-%s' % key)
-            
-            if self.overwrite.IsChecked() or \
-                    UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
-                cmd.append('--overwrite')
-            
-            # run in Layer Manager
-            self.parent.goutput.RunCmd(cmd, switchPage = True,
-                                       onDone = self.AddLayers)
-        
-        self.OnCancel()
-
-    def OnSetDsn(self, event):
-        """!Input DXF file defined, update list of layer widget"""
-        path = event.GetString()
-        if not path:
-            return 
-        
-        data = list()        
-        ret = gcmd.RunCommand('v.in.dxf',
-                              quiet = True,
-                              parent = self,
-                              read = True,
-                              flags = 'l',
-                              input = path)
-        if not ret:
-            self.list.LoadData()
-            self.btn_run.Enable(False)
-            return
-            
-        for line in ret.splitlines():
-            layerId = line.split(':')[0].split(' ')[1]
-            layerName = line.split(':')[1].strip()
-            grassName = utils.GetValidLayerName(layerName)
-            data.append((layerId, layerName.strip(), grassName.strip()))
-        
-        self.list.LoadData(data)
-        if len(data) > 0:
-            self.btn_run.Enable(True)
-        else:
-            self.btn_run.Enable(False)
-
-    def OnCmdDialog(self, event):
-        """!Show command dialog"""
-        menuform.GUI(parent = self, modal = True).ParseCommand(cmd = ['v.in.dxf'])
-                
-class LayersList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,
-                 listmix.CheckListCtrlMixin, listmix.TextEditMixin):
-    """!List of layers to be imported (dxf, shp...)"""
-    def __init__(self, parent, columns, log = None):
-        self.parent = parent
-        
-        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
-                             style = wx.LC_REPORT)
-        listmix.CheckListCtrlMixin.__init__(self)
-        self.log = log
-        
-        # setup mixins
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        listmix.TextEditMixin.__init__(self)
-        
-        for i in range(len(columns)):
-            self.InsertColumn(i, columns[i])
-        
-        if len(columns) == 3:
-            width = (65, 200)
-        else:
-            width = (65, 180, 110)
-        
-        for i in range(len(width)):
-            self.SetColumnWidth(col = i, width = width[i])
-        
-        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnPopupMenu) #wxMSW
-        self.Bind(wx.EVT_RIGHT_UP,            self.OnPopupMenu) #wxGTK
-
-    def LoadData(self, data = None):
-        """!Load data into list"""
-        if data is None:
-            return
-        
-        self.DeleteAllItems()
-        for item in data:
-            index = self.InsertStringItem(sys.maxint, str(item[0]))
-            for i in range(1, len(item)):
-                self.SetStringItem(index, i, "%s" % str(item[i]))
-        
-        # check by default only on one item
-        if len(data) == 1:
-            self.CheckItem(index, True)
-        
-    def OnPopupMenu(self, event):
-        """!Show popup menu"""
-        if self.GetItemCount() < 1:
-            return
-        
-        if not hasattr(self, "popupDataID1"):
-            self.popupDataID1 = wx.NewId()
-            self.popupDataID2 = wx.NewId()
-            
-            self.Bind(wx.EVT_MENU, self.OnSelectAll,  id = self.popupDataID1)
-            self.Bind(wx.EVT_MENU, self.OnSelectNone, id = self.popupDataID2)
-        
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupDataID1, _("Select all"))
-        menu.Append(self.popupDataID2, _("Deselect all"))
-        
-        self.PopupMenu(menu)
-        menu.Destroy()
-
-    def OnSelectAll(self, event):
-        """!Select all items"""
-        item = -1
-        
-        while True:
-            item = self.GetNextItem(item)
-            if item == -1:
-                break
-            self.CheckItem(item, True)
-        
-        event.Skip()
-        
-    def OnSelectNone(self, event):
-        """!Deselect items"""
-        item = -1
-        
-        while True:
-            item = self.GetNextItem(item, wx.LIST_STATE_SELECTED)
-            if item == -1:
-                break
-            self.CheckItem(item, False)
-        
-        event.Skip()
-        
-    def OnLeftDown(self, event):
-        """!Allow editing only output name
-        
-        Code taken from TextEditMixin class.
-        """
-        x, y = event.GetPosition()
-        
-        colLocs = [0]
-        loc = 0
-        for n in range(self.GetColumnCount()):
-            loc = loc + self.GetColumnWidth(n)
-            colLocs.append(loc)
-        
-        col = bisect(colLocs, x + self.GetScrollPos(wx.HORIZONTAL)) - 1
-        
-        if col == self.GetColumnCount() - 1:
-            listmix.TextEditMixin.OnLeftDown(self, event)
-        else:
-            event.Skip()
-        
-    def GetLayers(self):
-        """!Get list of layers (layer name, output name)"""
-        data = []
-        item = -1
-        while True:
-            item = self.GetNextItem(item)
-            if item == -1:
-                break
-            if not self.IsChecked(item):
-                continue
-            # layer / output name
-            data.append((self.GetItem(item, 1).GetText(),
-                         self.GetItem(item, self.GetColumnCount() - 1).GetText()))
-        
-        return data
-
-class SetOpacityDialog(wx.Dialog):
-    """!Set opacity of map layers"""
-    def __init__(self, parent, id = wx.ID_ANY, title = _("Set Map Layer Opacity"),
-                 size = wx.DefaultSize, pos = wx.DefaultPosition,
-                 style = wx.DEFAULT_DIALOG_STYLE, opacity = 100):
-
-        self.parent = parent    # GMFrame
-        self.opacity = opacity  # current opacity
-
-        super(SetOpacityDialog, self).__init__(parent, id = id, pos = pos,
-                                               size = size, style = style, title = title)
-
-        panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.GridBagSizer(vgap = 5, hgap = 5)
-        self.value = wx.Slider(panel, id = wx.ID_ANY, value = self.opacity,
-                               style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
-                                   wx.SL_TOP | wx.SL_LABELS,
-                               minValue = 0, maxValue = 100,
-                               size = (350, -1))
-
-        box.Add(item = self.value,
-                flag = wx.ALIGN_CENTRE, pos = (0, 0), span = (1, 2))
-        box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                   label = _("transparent")),
-                pos = (1, 0))
-        box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                   label = _("opaque")),
-                flag = wx.ALIGN_RIGHT,
-                pos = (1, 1))
-
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
-
-        line = wx.StaticLine(parent = panel, id = wx.ID_ANY,
-                             style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
-
-        # buttons
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btnOK = wx.Button(parent = panel, id = wx.ID_OK)
-        btnOK.SetDefault()
-        btnsizer.AddButton(btnOK)
-
-        btnCancel = wx.Button(parent = panel, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btnCancel)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
-
-        panel.SetSizer(sizer)
-        sizer.Fit(panel)
-
-        self.SetSize(self.GetBestSize())
-
-        self.Layout()
-
-    def GetOpacity(self):
-        """!Button 'OK' pressed"""
-        # return opacity value
-        opacity = float(self.value.GetValue()) / 100
-        return opacity
-
-def GetImageHandlers(image):
-    """!Get list of supported image handlers"""
-    lext = list()
-    ltype = list()
-    for h in image.GetHandlers():
-        lext.append(h.GetExtension())
-        
-    filetype = ''
-    if 'png' in lext:
-        filetype += "PNG file (*.png)|*.png|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
-                       'ext'  : 'png' })
-    filetype +=  "BMP file (*.bmp)|*.bmp|"
-    ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
-                   'ext'  : 'bmp' })
-    if 'gif' in lext:
-        filetype += "GIF file (*.gif)|*.gif|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
-                       'ext'  : 'gif' })
-        
-    if 'jpg' in lext:
-        filetype += "JPG file (*.jpg)|*.jpg|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
-                       'ext'  : 'jpg' })
-
-    if 'pcx' in lext:
-        filetype += "PCX file (*.pcx)|*.pcx|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
-                       'ext'  : 'pcx' })
-        
-    if 'pnm' in lext:
-        filetype += "PNM file (*.pnm)|*.pnm|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
-                       'ext'  : 'pnm' })
-
-    if 'tif' in lext:
-        filetype += "TIF file (*.tif)|*.tif|"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
-                       'ext'  : 'tif' })
-
-    if 'xpm' in lext:
-        filetype += "XPM file (*.xpm)|*.xpm"
-        ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
-                       'ext'  : 'xpm' })
-    
-    return filetype, ltype
-
-class StaticWrapText(wx.StaticText):
-    """!A Static Text field that wraps its text to fit its width,
-    enlarging its height if necessary.
-    """
-    def __init__(self, parent, id = wx.ID_ANY, label = '', *args, **kwds):
-        self.parent        = parent
-        self.originalLabel = label
-        
-        wx.StaticText.__init__(self, parent, id, label = '', *args, **kwds)
-        
-        self.SetLabel(label)
-        self.Bind(wx.EVT_SIZE, self.OnResize)
-    
-    def SetLabel(self, label):
-        self.originalLabel = label
-        self.wrappedSize = None
-        self.OnResize(None)
-
-    def OnResize(self, event):
-        if not getattr(self, "resizing", False):
-            self.resizing = True
-            newSize = wx.Size(self.parent.GetSize().width - 50,
-                              self.GetSize().height)
-            if self.wrappedSize != newSize:
-                wx.StaticText.SetLabel(self, self.originalLabel)
-                self.Wrap(newSize.width)
-                self.wrappedSize = newSize
-                
-                self.SetSize(self.wrappedSize)
-            del self.resizing
-
-class ImageSizeDialog(wx.Dialog):
-    """!Set size for saved graphic file"""
-    def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
-        self.parent = parent
-        
-        wx.Dialog.__init__(self, parent, id = id, style = style, title = title, **kwargs)
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                label = ' % s' % _("Image size"))
-        
-        size = self.parent.GetWindow().GetClientSize()
-        self.width = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
-                                 style = wx.SP_ARROW_KEYS)
-        self.width.SetRange(20, 1e6)
-        self.width.SetValue(size.width)
-        wx.CallAfter(self.width.SetFocus)
-        self.height = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
-                                  style = wx.SP_ARROW_KEYS)
-        self.height.SetRange(20, 1e6)
-        self.height.SetValue(size.height)
-        self.template = wx.Choice(parent = self.panel, id = wx.ID_ANY,
-                                  size = (125, -1),
-                                  choices = [ "",
-                                              "640x480",
-                                              "800x600",
-                                              "1024x768",
-                                              "1280x960",
-                                              "1600x1200",
-                                              "1920x1440" ])
-        
-        self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
-        self.btnOK.SetDefault()
-        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        
-        self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
-        
-        self._layout()
-        self.SetSize(self.GetBestSize())
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # body
-        box = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
-        fbox = wx.FlexGridSizer(cols = 2, vgap = 5, hgap = 5)
-        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                      label = _("Width:")),
-                 flag = wx.ALIGN_CENTER_VERTICAL)
-        fbox.Add(item = self.width)
-        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                      label = _("Height:")),
-                 flag = wx.ALIGN_CENTER_VERTICAL)
-        fbox.Add(item = self.height)
-        fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                      label = _("Template:")),
-                 flag = wx.ALIGN_CENTER_VERTICAL)
-        fbox.Add(item = self.template)
-        
-        box.Add(item = fbox, proportion = 1,
-                flag = wx.EXPAND | wx.ALL, border = 5)
-        sizer.Add(item = box, proportion = 1,
-                  flag=wx.EXPAND | wx.ALL, border = 3)
-        
-        # buttons
-        btnsizer = wx.StdDialogButtonSizer()
-        btnsizer.AddButton(self.btnOK)
-        btnsizer.AddButton(self.btnCancel)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
-        
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        self.Layout()
-    
-    def GetValues(self):
-        """!Get width/height values"""
-        return self.width.GetValue(), self.height.GetValue()
-    
-    def OnTemplate(self, event):
-        """!Template selected"""
-        sel = event.GetString()
-        if not sel:
-            width, height = self.parent.GetWindow().GetClientSize()
-        else:
-            width, height = map(int, sel.split('x'))
-        self.width.SetValue(width)
-        self.height.SetValue(height)
-        
-class SqlQueryFrame(wx.Frame):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _("GRASS GIS SQL Query Utility"),
-                 *kwargs):
-        """!SQL Query Utility window
-        """
-        self.parent = parent
-
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, *kwargs)
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.sqlBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                   label = _(" SQL statement "))
-        self.sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
-                               style = wx.TE_MULTILINE)
-        
-        self.btnApply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
-        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, self.btnCancel)
-        
-        self._layout()
-
-        self.SetMinSize(wx.Size(300, 150))
-        self.SetSize(wx.Size(500, 200))
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.HORIZONTAL)
-        sqlSizer.Add(item = self.sql, proportion = 1,
-                     flag = wx.EXPAND)
-
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnApply)
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.Realize()
-        
-        sizer.Add(item = sqlSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.ALL, border = 5) 
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-       
-        self.panel.SetSizer(sizer)
-        
-        self.Layout()
-
-    def OnCloseWindow(self, event):
-        """!Close window
-        """
-        self.Close()

Deleted: grass/trunk/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/ghelp.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/ghelp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1298 +0,0 @@
-"""!
- at package help.py
-
- at brief Help window
-
-Classes:
- - SearchModuleWindow
- - ItemTree
- - MenuTreeWindow
- - MenuTree
- - AboutWindow
- - InstallExtensionWindow
- - ExtensionTree
- - HelpFrame
- - HelpWindow
- - HelpPanel
-
-(C) 2008-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import codecs
-
-import wx
-try:
-    import wx.lib.agw.customtreectrl as CT
-    from wx.lib.agw.hyperlink import HyperLinkCtrl
-except ImportError:
-    import wx.lib.customtreectrl as CT
-    from wx.lib.hyperlink import HyperLinkCtrl
-import wx.lib.flatnotebook as FN
-import  wx.lib.scrolledpanel as scrolled
-
-import grass.script as grass
-from grass.script import task as gtask
-
-import menudata
-import gcmd
-import globalvar
-import gdialogs
-import utils
-import menuform
-
-class HelpFrame(wx.Frame):
-    """!GRASS Quickstart help window"""
-    def __init__(self, parent, id, title, size, file):
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, size = size)
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # text
-        content = HelpPanel(parent = self)
-        content.LoadPage(file)
-        
-        sizer.Add(item = content, proportion = 1, flag = wx.EXPAND)
-        
-        self.SetAutoLayout(True)
-        self.SetSizer(sizer)
-        self.Layout()
-
-class SearchModuleWindow(wx.Panel):
-    """!Search module window (used in MenuTreeWindow)"""
-    def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
-                 showChoice = True, showTip = False, **kwargs):
-        self.showTip    = showTip
-        self.showChoice = showChoice
-        self.cmdPrompt  = cmdPrompt
-        
-        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
-        
-        self._searchDict = { _('description') : 'description',
-                             _('command')     : 'command',
-                             _('keywords')    : 'keywords' }
-        
-        self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                label = " %s " % _("Find module(s)"))
-        
-        self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
-                                  choices = [_('description'),
-                                             _('keywords'),
-                                             _('command')])
-        self.searchBy.SetSelection(0)
-        
-        self.search = wx.TextCtrl(parent = self, id = wx.ID_ANY,
-                                  value = "", size = (-1, 25),
-                                  style = wx.TE_PROCESS_ENTER)
-        self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
-        
-        if self.showTip:
-            self.searchTip = gdialogs.StaticWrapText(parent = self, id = wx.ID_ANY,
-                                                     size = (-1, 35))
-        
-        if self.showChoice:
-            self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
-            if self.cmdPrompt:
-                self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
-            self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
-        
-        self._layout()
-
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
-        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(1)
-        
-        gridSizer.Add(item = self.searchBy,
-                      flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        gridSizer.Add(item = self.search,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (0, 1))
-        row = 1
-        if self.showTip:
-            gridSizer.Add(item = self.searchTip,
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
-            row += 1
-        
-        if self.showChoice:
-            gridSizer.Add(item = self.searchChoice,
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
-        
-        sizer.Add(item = gridSizer, proportion = 1)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def GetSelection(self):
-        """!Get selected element"""
-        selection = self.searchBy.GetStringSelection()
-        
-        return self._searchDict[selection]
-
-    def SetSelection(self, i):
-        """!Set selection element"""
-        self.searchBy.SetSelection(i)
-
-    def OnSearchModule(self, event):
-        """!Search module by keywords or description"""
-        if not self.cmdPrompt:
-            event.Skip()
-            return
-        
-        text = event.GetString()
-        if not text:
-            self.cmdPrompt.SetFilter(None)
-            mList = self.cmdPrompt.GetCommandItems()
-            self.searchChoice.SetItems(mList)
-            if self.showTip:
-                self.searchTip.SetLabel(_("%d modules found") % len(mList))
-            event.Skip()
-            return
-        
-        modules = dict()
-        iFound = 0
-        for module, data in self.cmdPrompt.moduleDesc.iteritems():
-            found = False
-            sel = self.searchBy.GetSelection()
-            if sel == 0: # -> description
-                if text in data['desc']:
-                    found = True
-            elif sel == 1: # keywords
-                if text in ','.join(data['keywords']):
-                    found = True
-            else: # command
-                if module[:len(text)] == text:
-                    found = True
-            
-            if found:
-                iFound += 1
-                try:
-                    group, name = module.split('.')
-                except ValueError:
-                    continue # TODO
-                
-                if group not in modules:
-                    modules[group] = list()
-                modules[group].append(name)
-                
-        self.cmdPrompt.SetFilter(modules)
-        self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
-        if self.showTip:
-            self.searchTip.SetLabel(_("%d modules found") % iFound)
-        
-        event.Skip()
-        
-    def OnSelectModule(self, event):
-        """!Module selected from choice, update command prompt"""
-        cmd  = event.GetString().split(' ', 1)[0]
-        text = cmd + ' '
-        pos = len(text)
-
-        if self.cmdPrompt:
-            self.cmdPrompt.SetText(text)
-            self.cmdPrompt.SetSelectionStart(pos)
-            self.cmdPrompt.SetCurrentPos(pos)
-            self.cmdPrompt.SetFocus()
-        
-        desc = self.cmdPrompt.GetCommandDesc(cmd)
-        if self.showTip:
-            self.searchTip.SetLabel(desc)
-    
-    def Reset(self):
-        """!Reset widget"""
-        self.searchBy.SetSelection(0)
-        self.search.SetValue('')
-        if self.showTip:
-            self.searchTip.SetLabel('')
-        
-class MenuTreeWindow(wx.Panel):
-    """!Show menu tree"""
-    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
-        self.parent = parent # LayerManager
-        
-        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
-        
-        self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                    label = " %s " % _("Menu tree (double-click to run command)"))
-        # tree
-        self.tree = MenuTree(parent = self, data = menudata.ManagerData())
-        self.tree.Load()
-
-        # search widget
-        self.search = SearchModuleWindow(parent = self, showChoice = False)
-        
-        # buttons
-        self.btnRun   = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
-        self.btnRun.SetToolTipString(_("Run selected command"))
-        self.btnRun.Enable(False)
-        
-        # bindings
-        self.btnRun.Bind(wx.EVT_BUTTON,            self.OnRun)
-        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
-        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
-        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
-        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
-        
-        self._layout()
-        
-        self.search.SetFocus()
-        
-    def _layout(self):
-        """!Do dialog layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # body
-        dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
-        dataSizer.Add(item = self.tree, proportion =1,
-                      flag = wx.EXPAND)
-        
-        # buttons
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = self.btnRun, proportion = 0)
-        
-        sizer.Add(item = dataSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.ALL, border = 5)
-
-        sizer.Add(item = self.search, proportion = 0,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
-        
-        sizer.Fit(self)
-        sizer.SetSizeHints(self)
-        
-        self.SetSizer(sizer)
-        
-        self.Fit()
-        self.SetAutoLayout(True)        
-        self.Layout()
-        
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        self.Destroy()
-        
-    def OnRun(self, event):
-        """!Run selected command"""
-        if not self.tree.GetSelected():
-            return # should not happen
-        
-        data = self.tree.GetPyData(self.tree.GetSelected())
-        if not data:
-            return
-
-        handler = 'self.parent.' + data['handler'].lstrip('self.')
-        if data['handler'] == 'self.OnXTerm':
-            wx.MessageBox(parent = self,
-                          message = _('You must run this command from the menu or command line',
-                                      'This command require an XTerm'),
-                          caption = _('Message'), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-        elif data['command']:
-            eval(handler)(event = None, cmd = data['command'].split())
-        else:
-            eval(handler)(None)
-
-    def OnShowItem(self, event):
-        """!Show selected item"""
-        self.tree.OnShowItem(event)
-        if self.tree.GetSelected():
-            self.btnRun.Enable()
-        else:
-            self.btnRun.Enable(False)
-        
-    def OnItemActivated(self, event):
-        """!Item activated (double-click)"""
-        item = event.GetItem()
-        if not item or not item.IsOk():
-            return
-        
-        data = self.tree.GetPyData(item)
-        if not data or 'command' not in data:
-            return
-        
-        self.tree.itemSelected = item
-        
-        self.OnRun(None)
-        
-    def OnItemSelected(self, event):
-        """!Item selected"""
-        item = event.GetItem()
-        if not item or not item.IsOk():
-            return
-        
-        data = self.tree.GetPyData(item)
-        if not data or 'command' not in data:
-            return
-        
-        if data['command']:
-            label = data['command'] + ' -- ' + data['description']
-        else:
-            label = data['description']
-        
-        self.parent.SetStatusText(label, 0)
-        
-    def OnUpdateStatusBar(self, event):
-        """!Update statusbar text"""
-        element = self.search.GetSelection()
-        self.tree.SearchItems(element = element,
-                              value = event.GetString())
-        
-        nItems = len(self.tree.itemsMarked)
-        if event.GetString():
-            self.parent.SetStatusText(_("%d modules match") % nItems, 0)
-        else:
-            self.parent.SetStatusText("", 0)
-        
-        event.Skip()
-        
-class ItemTree(CT.CustomTreeCtrl):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
-                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE, **kwargs):
-        if globalvar.hasAgw:
-            super(ItemTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
-        else:
-            super(ItemTree, self).__init__(parent, id, style = ctstyle, **kwargs)
-        
-        self.root = self.AddRoot(_("Menu tree"))
-        self.itemsMarked = [] # list of marked items
-        self.itemSelected = None
-
-    def SearchItems(self, element, value):
-        """!Search item 
-
-        @param element element index (see self.searchBy)
-        @param value
-
-        @return list of found tree items
-        """
-        items = list()
-        if not value:
-            return items
-        
-        item = self.GetFirstChild(self.root)[0]
-        self._processItem(item, element, value, items)
-        
-        self.itemsMarked  = items
-        self.itemSelected = None
-        
-        return items
-    
-    def _processItem(self, item, element, value, listOfItems):
-        """!Search items (used by SearchItems)
-        
-        @param item reference item
-        @param listOfItems list of found items
-        """
-        while item and item.IsOk():
-            subItem = self.GetFirstChild(item)[0]
-            if subItem:
-                self._processItem(subItem, element, value, listOfItems)
-            data = self.GetPyData(item)
-            
-            if data and element in data and \
-                    value.lower() in data[element].lower():
-                listOfItems.append(item)
-            
-            item = self.GetNextSibling(item)
-            
-    def GetSelected(self):
-        """!Get selected item"""
-        return self.itemSelected
-
-    def OnShowItem(self, event):
-        """!Highlight first found item in menu tree"""
-        if len(self.itemsMarked) > 0:
-            if self.GetSelected():
-                self.ToggleItemSelection(self.GetSelected())
-                idx = self.itemsMarked.index(self.GetSelected()) + 1
-            else:
-                idx = 0
-            try:
-                self.ToggleItemSelection(self.itemsMarked[idx])
-                self.itemSelected = self.itemsMarked[idx]
-                self.EnsureVisible(self.itemsMarked[idx])
-            except IndexError:
-                self.ToggleItemSelection(self.itemsMarked[0]) # reselect first item
-                self.EnsureVisible(self.itemsMarked[0])
-                self.itemSelected = self.itemsMarked[0]
-        else:
-            for item in self.root.GetChildren():
-                self.Collapse(item)
-            itemSelected = self.GetSelection()
-            if itemSelected:
-                self.ToggleItemSelection(itemSelected)
-            self.itemSelected = None
-    
-class MenuTree(ItemTree):
-    """!Menu tree class"""
-    def __init__(self, parent, data, **kwargs):
-        self.parent   = parent
-        self.menudata = data
-
-        super(MenuTree, self).__init__(parent, **kwargs)
-        
-    def Load(self, data = None):
-        """!Load menu data tree
-
-        @param data menu data (None to use self.menudata)
-        """
-        if not data:
-            data = self.menudata
-        
-        self.itemsMarked = [] # list of marked items
-        for eachMenuData in data.GetMenu():
-            for label, items in eachMenuData:
-                item = self.AppendItem(parentId = self.root,
-                                       text = label.replace('&', ''))
-                self.__AppendItems(item, items)
-        
-    def __AppendItems(self, item, data):
-        """!Append items into tree (used by Load()
-        
-        @param item tree item (parent)
-        @parent data menu data"""
-        for eachItem in data:
-            if len(eachItem) == 2:
-                if eachItem[0]:
-                    itemSub = self.AppendItem(parentId = item,
-                                    text = eachItem[0])
-                self.__AppendItems(itemSub, eachItem[1])
-            else:
-                if eachItem[0]:
-                    itemNew = self.AppendItem(parentId = item,
-                                              text = eachItem[0])
-                    
-                    data = { 'item'        : eachItem[0],
-                             'description' : eachItem[1],
-                             'handler'  : eachItem[2],
-                             'command'  : eachItem[3],
-                             'keywords' : eachItem[4] }
-                    
-                    self.SetPyData(itemNew, data)
-        
-class AboutWindow(wx.Frame):
-    """!Create custom About Window
-
-    @todo improve styling
-    """
-    def __init__(self, parent, size = (750, 400), 
-                 title = _('About GRASS GIS'), **kwargs):
-        wx.Frame.__init__(self, parent = parent, id = wx.ID_ANY, size = size, **kwargs)
-        
-        panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        # icon
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-
-        # get version and web site
-        vInfo = grass.version()
-        
-        infoTxt = wx.Panel(parent = panel, id = wx.ID_ANY)
-        infoSizer = wx.BoxSizer(wx.VERTICAL)
-        infoGridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        infoGridSizer.AddGrowableCol(0)
-        infoGridSizer.AddGrowableCol(1)
-        logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass.ico")
-        logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
-                                     bitmap = wx.Bitmap(name = logo,
-                                                        type = wx.BITMAP_TYPE_ICO))
-        infoSizer.Add(item = logoBitmap, proportion = 0,
-                      flag = wx.ALL | wx.ALIGN_CENTER, border = 25)
-        
-        info = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                             label = 'GRASS GIS ' + vInfo['version'] + '\n\n')
-        info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
-        infoSizer.Add(item = info, proportion = 0,
-                          flag = wx.BOTTOM | wx.ALIGN_CENTER, border = 15)
-
-        row = 0
-        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                                               label = _('Official GRASS site:')),
-                          pos = (row, 0),
-                          flag = wx.ALIGN_RIGHT)
-
-        infoGridSizer.Add(item = HyperLinkCtrl(parent = infoTxt, id = wx.ID_ANY,
-                                               label = 'http://grass.osgeo.org'),
-                          pos = (row, 1),
-                          flag = wx.ALIGN_LEFT)
-
-        row += 2
-        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                                               label = _('SVN Revision:')),
-                          pos = (row, 0),
-                          flag = wx.ALIGN_RIGHT)
-        
-        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                                               label = vInfo['revision']),
-                          pos = (row, 1),
-                          flag = wx.ALIGN_LEFT)
-        
-        row += 1
-        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                                               label = _('GIS Library Revision:')),
-                          pos = (row, 0),
-                          flag = wx.ALIGN_RIGHT)
-        
-        infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
-                                               label = vInfo['libgis_revision'] + ' (' +
-                                               vInfo['libgis_date'].split(' ')[0] + ')'),
-                          pos = (row, 1),
-                          flag = wx.ALIGN_LEFT)
-
-        infoSizer.Add(item = infoGridSizer,
-                      proportion = 1,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL,
-                      border = 25)
-        
-        # create a flat notebook for displaying information about GRASS
-        aboutNotebook = menuform.GNotebook(panel, style = globalvar.FNPageStyle | FN.FNB_NO_X_BUTTON) 
-        aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
-        
-        for title, win in ((_("Info"), infoTxt),
-                           (_("Copyright"), self._pageCopyright()),
-                           (_("License"), self._pageLicense()),
-                           (_("Authors"), self._pageCredit()),
-                           (_("Contributors"), self._pageContributors()),
-                           (_("Extra contributors"), self._pageContributors(extra = True)),
-                           (_("Translators"), self._pageTranslators())):
-            aboutNotebook.AddPage(page = win, text = title)
-        wx.CallAfter(aboutNotebook.SetSelection, 0)
-        
-        # buttons
-        btnClose = wx.Button(parent = panel, id = wx.ID_CLOSE)
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = btnClose, proportion = 0,
-                     flag = wx.ALL | wx.ALIGN_RIGHT,
-                     border = 5)
-        # bindings
-        btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
-        
-        infoTxt.SetSizer(infoSizer)
-        infoSizer.Fit(infoTxt)
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        sizer.Add(item = aboutNotebook, proportion = 1,
-                  flag = wx.EXPAND | wx.ALL, border = 1)
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALL | wx.ALIGN_RIGHT, border = 1)
-        panel.SetSizer(sizer)
-        self.Layout()
-    
-    def _pageCopyright(self):
-        """Copyright information"""
-        copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
-        if os.path.exists(copyfile):
-            copyrightFile = open(copyfile, 'r')
-            copytext = copyrightFile.read()
-            copyrightFile.close()
-        else:
-            copytext = _('%s file missing') % 'COPYING'
-        
-        # put text into a scrolling panel
-        copyrightwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
-                                              size = wx.DefaultSize,
-                                              style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
-        copyrighttxt = wx.StaticText(copyrightwin, id = wx.ID_ANY, label = copytext)
-        copyrightwin.SetAutoLayout(True)
-        copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
-        copyrightwin.sizer.Add(item = copyrighttxt, proportion = 1,
-                               flag = wx.EXPAND | wx.ALL, border = 3)
-        copyrightwin.SetSizer(copyrightwin.sizer)
-        copyrightwin.Layout()
-        copyrightwin.SetupScrolling()
-        
-        return copyrightwin
-    
-    def _pageLicense(self):
-        """Licence about"""
-        licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
-        if os.path.exists(licfile):
-            licenceFile = open(licfile, 'r')
-            license = ''.join(licenceFile.readlines())
-            licenceFile.close()
-        else:
-            license = _('%s file missing') % 'GPL.TXT'
-        # put text into a scrolling panel
-        licensewin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
-                                            style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
-        licensetxt = wx.StaticText(licensewin, id = wx.ID_ANY, label = license)
-        licensewin.SetAutoLayout(True)
-        licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
-        licensewin.sizer.Add(item = licensetxt, proportion = 1,
-                flag = wx.EXPAND | wx.ALL, border = 3)
-        licensewin.SetSizer(licensewin.sizer)
-        licensewin.Layout()
-        licensewin.SetupScrolling()
-        
-        return licensewin
-    
-    def _pageCredit(self):
-        """Credit about"""
-                # credits
-        authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
-        if os.path.exists(authfile):
-            authorsFile = open(authfile, 'r')
-            authors = unicode(''.join(authorsFile.readlines()), "utf-8")
-            authorsFile.close()
-        else:
-            authors = _('%s file missing') % 'AUTHORS'
-        authorwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
-                                           style  =  wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
-        authortxt = wx.StaticText(authorwin, id = wx.ID_ANY, label = authors)
-        authorwin.SetAutoLayout(1)
-        authorwin.SetupScrolling()
-        authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
-        authorwin.sizer.Add(item = authortxt, proportion = 1,
-                flag = wx.EXPAND | wx.ALL, border = 3)
-        authorwin.SetSizer(authorwin.sizer)
-        authorwin.Layout()      
-        
-        return authorwin
-
-    def _pageContributors(self, extra = False):
-        """Contributors info"""
-        if extra:
-            contribfile = os.path.join(os.getenv("GISBASE"), "contributors_extra.csv")
-        else:
-            contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
-        if os.path.exists(contribfile):
-            contribFile = codecs.open(contribfile, encoding = 'utf-8', mode = 'r')
-            contribs = list()
-            errLines = list()
-            for line in contribFile.readlines()[1:]:
-                line = line.rstrip('\n')
-                try:
-                    if extra:
-                        name, email, rfc2_agreed = line.split(',')
-                    else:
-                        cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
-                except ValueError:
-                    errLines.append(line)
-                    continue
-                if extra:
-                    contribs.append((name, email))
-                else:
-                    contribs.append((name, email, country, osgeo_id))
-            
-            contribFile.close()
-            
-            if errLines:
-                gcmd.GError(parent = self,
-                            message = _("Error when reading file '%s'.") % contribfile + \
-                                "\n\n" + _("Lines:") + " %s" % \
-                                os.linesep.join(map(utils.DecodeString, errLines)))
-        else:
-            contribs = None
-        
-        contribwin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
-                                           style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
-        contribwin.SetAutoLayout(True)
-        contribwin.SetupScrolling()
-        contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        if not contribs:
-            contribtxt = wx.StaticText(contribwin, id = wx.ID_ANY,
-                                       label = _('%s file missing') % contribfile)
-            contribwin.sizer.Add(item = contribtxt, proportion = 1,
-                                 flag = wx.EXPAND | wx.ALL, border = 3)
-        else:
-            if extra:
-                items = (_('Name'), _('E-mail'))
-            else:
-                items = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
-            contribBox = wx.FlexGridSizer(cols = len(items), vgap = 5, hgap = 5)
-            for item in items:
-                contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
-                                                    label = item))
-            for vals in sorted(contribs, key = lambda x: x[0]):
-                for item in vals:
-                    contribBox.Add(item = wx.StaticText(parent = contribwin, id = wx.ID_ANY,
-                                                        label = item))
-            contribwin.sizer.Add(item = contribBox, proportion = 1,
-                                 flag = wx.EXPAND | wx.ALL, border = 3)
-        
-        contribwin.SetSizer(contribwin.sizer)
-        contribwin.Layout()      
-        
-        return contribwin
-
-    def _pageTranslators(self):
-        """Translators info"""
-        translatorsfile = os.path.join(os.getenv("GISBASE"), "translators.csv")
-        if os.path.exists(translatorsfile):
-            translatorsFile = open(translatorsfile, 'r')
-            translators = dict()
-            errLines = list()
-            for line in translatorsFile.readlines()[1:]:
-                line = line.rstrip('\n')
-                try:
-                    name, email, languages = line.split(',')
-                except ValueError:
-                    errLines.append(line)
-                    continue
-                for language in languages.split(' '):
-                    if language not in translators:
-                        translators[language] = list()
-                    translators[language].append((name, email))
-            translatorsFile.close()
-            
-            if errLines:
-                gcmd.GError(parent = self,
-                            message = _("Error when reading file '%s'.") % translatorsfile + \
-                                "\n\n" + _("Lines:") + " %s" % \
-                                os.linesep.join(map(utils.DecodeString, errLines)))
-        else:
-            translators = None
-        
-        translatorswin = scrolled.ScrolledPanel(self, id = wx.ID_ANY, 
-                                           style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
-        translatorswin.SetAutoLayout(1)
-        translatorswin.SetupScrolling()
-        translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        if not translators:
-            translatorstxt = wx.StaticText(translatorswin, id = wx.ID_ANY,
-                                           label = _('%s file missing') % 'translators.csv')
-            translatorswin.sizer.Add(item = translatorstxt, proportion = 1,
-                                 flag = wx.EXPAND | wx.ALL, border = 3)
-        else:
-            translatorsBox = wx.FlexGridSizer(cols = 3, vgap = 5, hgap = 5)
-            languages = translators.keys()
-            languages.sort()
-            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                    label = _('Name')))
-            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                    label = _('E-mail')))
-            translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                    label = _('Language')))
-            for lang in languages:
-                for translator in translators[lang]:
-                    name, email = translator
-                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                            label =  unicode(name, "utf-8")))
-                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                            label = email))
-                    translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
-                                                            label = lang))
-            
-            translatorswin.sizer.Add(item = translatorsBox, proportion = 1,
-                                 flag = wx.EXPAND | wx.ALL, border = 3)
-        
-        translatorswin.SetSizer(translatorswin.sizer)
-        translatorswin.Layout()      
-        
-        return translatorswin
-    
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        self.Close()
-
-class InstallExtensionWindow(wx.Frame):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _("Fetch & install extension from GRASS Addons"), **kwargs):
-        self.parent = parent
-        self.options = dict() # list of options
-        
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
-        self.repoBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Repository"))
-        self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("List of extensions"))
-        
-        self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
-        self.fullDesc = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("Fetch full info including description and keywords (takes time)"))
-        self.fullDesc.SetValue(True)
-        
-        self.search = SearchModuleWindow(parent = self.panel)
-        self.search.SetSelection(0) 
-        
-        self.tree   = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
-        
-        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                      label = " %s " % _("Options"))
-        task = gtask.parse_interface('g.extension')
-        for f in task.get_options()['flags']:
-            name = f.get('name', '')
-            desc = f.get('label', '')
-            if not desc:
-                desc = f.get('description', '')
-            if not name and not desc:
-                continue
-            if name in ('l', 'c', 'g', 'quiet', 'verbose'):
-                continue
-            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                             label = desc)
-        self.repo.SetValue(task.get_param(value = 'svnurl').get('default',
-                                                                'http://svn.osgeo.org/grass/grass-addons/grass7'))
-        
-        self.statusbar = self.CreateStatusBar(number = 1)
-        
-        self.btnFetch = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                  label = _("&Fetch"))
-        self.btnFetch.SetToolTipString(_("Fetch list of available modules from GRASS Addons SVN repository"))
-        self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-        self.btnInstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("&Install"))
-        self.btnInstall.SetToolTipString(_("Install selected add-ons GRASS module"))
-        self.btnInstall.Enable(False)
-        self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                label = _("Command dialog"))
-        self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
-
-        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
-        self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
-        self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
-        self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
-        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
-        self.tree.Bind(wx.EVT_TREE_SEL_CHANGED,    self.OnItemSelected)
-        self.search.Bind(wx.EVT_TEXT_ENTER,        self.OnShowItem)
-        self.search.Bind(wx.EVT_TEXT,              self.OnUpdateStatusBar)
-
-        self._layout()
-
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        repoSizer = wx.StaticBoxSizer(self.repoBox, wx.VERTICAL)
-        repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
-        repo1Sizer.Add(item = self.repo, proportion = 1,
-                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
-        repo1Sizer.Add(item = self.btnFetch, proportion = 0,
-                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
-        repoSizer.Add(item = repo1Sizer,
-                      flag = wx.EXPAND)
-        repoSizer.Add(item = self.fullDesc)
-        
-        findSizer = wx.BoxSizer(wx.HORIZONTAL)
-        findSizer.Add(item = self.search, proportion = 1)
-        
-        treeSizer = wx.StaticBoxSizer(self.treeBox, wx.HORIZONTAL)
-        treeSizer.Add(item = self.tree, proportion = 1,
-                      flag = wx.ALL | wx.EXPAND, border = 1)
-
-        # options
-        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
-        for key in self.options.keys():
-            optionSizer.Add(item = self.options[key], proportion = 0)
-        
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = self.btnCmd, proportion = 0,
-                     flag = wx.RIGHT, border = 5)
-        btnSizer.AddSpacer(10)
-        btnSizer.Add(item = self.btnClose, proportion = 0,
-                     flag = wx.RIGHT, border = 5)
-        btnSizer.Add(item = self.btnInstall, proportion = 0)
-        
-        sizer.Add(item = repoSizer, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        sizer.Add(item = findSizer, proportion = 0,
-                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        sizer.Add(item = treeSizer, proportion = 1,
-                  flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        sizer.Add(item = optionSizer, proportion = 0,
-                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        
-        self.Layout()
-
-    def _getCmd(self):
-        item = self.tree.GetSelected()
-        if not item or not item.IsOk():
-            return ['g.extension']
-        
-        name = self.tree.GetItemText(item)
-        if not name:
-            gcmd.GError(_("Extension not defined"), parent = self)
-            return
-        
-        flags = list()
-        for key in self.options.keys():
-            if self.options[key].IsChecked():
-                flags.append('-%s' % key)
-        
-        return ['g.extension'] + flags + ['extension=' + name,
-                                          'svnurl=' + self.repo.GetValue().strip()]
-    
-    def OnUpdateStatusBar(self, event):
-        """!Update statusbar text"""
-        element = self.search.GetSelection()
-        if not self.tree.IsLoaded():
-            self.SetStatusText(_("Fetch list of available extensions by clicking on 'Fetch' button"), 0)
-            return
-        
-        self.tree.SearchItems(element = element,
-                              value = event.GetString())
-        
-        nItems = len(self.tree.itemsMarked)
-        if event.GetString():
-            self.SetStatusText(_("%d items match") % nItems, 0)
-        else:
-            self.SetStatusText("", 0)
-        
-        event.Skip()
-    
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        self.Destroy()
-
-    def OnFetch(self, event):
-        """!Fetch list of available extensions"""
-        wx.BeginBusyCursor()
-        self.SetStatusText(_("Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
-        self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
-        self.SetStatusText("", 0)
-        wx.EndBusyCursor()
-
-    def OnItemActivated(self, event):
-        item = event.GetItem()
-        data = self.tree.GetPyData(item)
-        if data and 'command' in data:
-            self.OnInstall(event = None)
-        
-    def OnInstall(self, event):
-        """!Install selected extension"""
-        log = self.parent.GetLogWindow()
-        log.RunCmd(self._getCmd(), onDone = self.OnDone)
-        
-    def OnDone(self, cmd, returncode):
-        item = self.tree.GetSelected()
-        if not item or not item.IsOk() or \
-                returncode != 0 or \
-                not os.getenv('GRASS_ADDON_PATH'):
-            return
-        
-        name = self.tree.GetItemText(item)
-        globalvar.grassCmd['all'].append(name)
-        
-    def OnItemSelected(self, event):
-        """!Item selected"""
-        item = event.GetItem()
-        self.tree.itemSelected = item
-        data = self.tree.GetPyData(item)
-        if not data:
-            self.SetStatusText('', 0)
-            self.btnInstall.Enable(False)
-        else:
-            self.SetStatusText(data.get('description', ''), 0)
-            self.btnInstall.Enable(True)
-
-    def OnShowItem(self, event):
-        """!Show selected item"""
-        self.tree.OnShowItem(event)
-        if self.tree.GetSelected():
-            self.btnInstall.Enable()
-        else:
-            self.btnInstall.Enable(False)
-
-    def OnCmdDialog(self, event):
-        """!Shows command dialog"""
-        menuform.GUI(parent = self).ParseCommand(cmd = self._getCmd())
-        
-class ExtensionTree(ItemTree):
-    """!List of available extensions"""
-    def __init__(self, parent, log, id = wx.ID_ANY,
-                 ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
-                 CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
-                 **kwargs):
-        self.parent = parent # GMFrame
-        self.log    = log
-        
-        super(ExtensionTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
-        
-        self._initTree()
-        
-    def _initTree(self):
-        for prefix in ('display', 'database',
-                       'general', 'imagery',
-                       'misc', 'postscript', 'paint',
-                       'raster', 'raster3D', 'sites', 'vector', 'wxGUI', 'other'):
-            self.AppendItem(parentId = self.root,
-                            text = prefix)
-        self._loaded = False
-        
-    def _expandPrefix(self, c):
-        name = { 'd'  : 'display',
-                 'db' : 'database',
-                 'g'  : 'general',
-                 'i'  : 'imagery',
-                 'm'  : 'misc',
-                 'ps' : 'postscript',
-                 'p'  : 'paint',
-                 'r'  : 'raster',
-                 'r3' : 'raster3D',
-                 's'  : 'sites',
-                 'v'  : 'vector',
-                 'wx' : 'wxGUI',
-                 'u'  : 'other' }
-        
-        if c in name:
-            return name[c]
-        
-        return c
-    
-    def _findItem(self, text):
-        """!Find item"""
-        item = self.GetFirstChild(self.root)[0]
-        while item and item.IsOk():
-            if text == self.GetItemText(item):
-                return item
-            
-            item = self.GetNextSibling(item)
-        
-        return None
-    
-    def Load(self, url, full = False):
-        """!Load list of extensions"""
-        self.DeleteAllItems()
-        self.root = self.AddRoot(_("Menu tree"))
-        self._initTree()
-        
-        if full:
-            flags = 'g'
-        else:
-            flags = 'l'
-        ret = gcmd.RunCommand('g.extension', read = True,
-                              svnurl = url,
-                              flags = flags, quiet = True)
-        if not ret:
-            return
-        
-        mdict = dict()
-        for line in ret.splitlines():
-            if full:
-                key, value = line.split('=', 1)
-                if key == 'name':
-                    try:
-                        prefix, name = value.split('.', 1)
-                    except ValueError:
-                        prefix = 'u'
-                        name = value
-                    if prefix not in mdict:
-                        mdict[prefix] = dict()
-                    mdict[prefix][name] = dict()
-                else:
-                    mdict[prefix][name][key] = value
-            else:
-                try:
-                    prefix, name = line.strip().split('.', 1)
-                except:
-                    prefix = 'unknown'
-                    name = line.strip()
-                
-                if self._expandPrefix(prefix) == prefix:
-                    prefix = 'unknown'
-                    
-                if prefix not in mdict:
-                    mdict[prefix] = dict()
-                    
-                mdict[prefix][name] = { 'command' : prefix + '.' + name }
-        
-        for prefix in mdict.keys():
-            prefixName = self._expandPrefix(prefix)
-            item = self._findItem(prefixName)
-            names = mdict[prefix].keys()
-            names.sort()
-            for name in names:
-                new = self.AppendItem(parentId = item,
-                                      text = prefix + '.' + name)
-                data = dict()
-                for key in mdict[prefix][name].keys():
-                    data[key] = mdict[prefix][name][key]
-                
-                self.SetPyData(new, data)
-        
-        self._loaded = True
-
-    def IsLoaded(self):
-        """Check if items are loaded"""
-        return self._loaded
-
-class HelpWindow(wx.html.HtmlWindow):
-    """!This panel holds the text from GRASS docs.
-    
-    GISBASE must be set in the environment to find the html docs dir.
-    The SYNOPSIS section is skipped, since this Panel is supposed to
-    be integrated into the cmdPanel and options are obvious there.
-    """
-    def __init__(self, parent, grass_command, text, skip_description,
-                 **kwargs):
-        """!If grass_command is given, the corresponding HTML help
-        file will be presented, with all links pointing to absolute
-        paths of local files.
-
-        If 'skip_description' is True, the HTML corresponding to
-        SYNOPSIS will be skipped, thus only presenting the help file
-        from the DESCRIPTION section onwards.
-
-        If 'text' is given, it must be the HTML text to be presented
-        in the Panel.
-        """
-        self.parent = parent
-        wx.InitAllImageHandlers()
-        wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
-        
-        gisbase = os.getenv("GISBASE")
-        self.loaded = False
-        self.history = list()
-        self.historyIdx = 0
-        self.fspath = os.path.join(gisbase, "docs", "html")
-        
-        self.SetStandardFonts (size = 10)
-        self.SetBorders(10)
-        
-        if text is None:
-            if skip_description:
-                url = os.path.join(self.fspath, grass_command + ".html")
-                self.fillContentsFromFile(url,
-                                          skip_description = skip_description)
-                self.history.append(url)
-                self.loaded = True
-            else:
-                ### FIXME: calling LoadPage() is strangely time-consuming (only first call)
-                # self.LoadPage(self.fspath + grass_command + ".html")
-                self.loaded = False
-        else:
-            self.SetPage(text)
-            self.loaded = True
-        
-    def OnLinkClicked(self, linkinfo):
-        url = linkinfo.GetHref()
-        if url[:4] != 'http':
-            url = os.path.join(self.fspath, url)
-        self.history.append(url)
-        self.historyIdx += 1
-        self.parent.OnHistory()
-        
-        super(HelpWindow, self).OnLinkClicked(linkinfo)
-        
-    def fillContentsFromFile(self, htmlFile, skip_description = True):
-        """!Load content from file"""
-        aLink = re.compile(r'(<a href="?)(.+\.html?["\s]*>)', re.IGNORECASE)
-        imgLink = re.compile(r'(<img src="?)(.+\.[png|gif])', re.IGNORECASE)
-        try:
-            contents = []
-            skip = False
-            for l in file(htmlFile, "rb").readlines():
-                if "DESCRIPTION" in l:
-                    skip = False
-                if not skip:
-                    # do skip the options description if requested
-                    if "SYNOPSIS" in l:
-                        skip = skip_description
-                    else:
-                        # FIXME: find only first item
-                        findALink = aLink.search(l)
-                        if findALink is not None: 
-                            contents.append(aLink.sub(findALink.group(1)+
-                                                      self.fspath+findALink.group(2),l))
-                        findImgLink = imgLink.search(l)
-                        if findImgLink is not None: 
-                            contents.append(imgLink.sub(findImgLink.group(1)+
-                                                        self.fspath+findImgLink.group(2),l))
-                        
-                        if findALink is None and findImgLink is None:
-                            contents.append(l)
-            self.SetPage("".join(contents))
-            self.loaded = True
-        except: # The Manual file was not found
-            self.loaded = False
-        
-class HelpPanel(wx.Panel):
-    def __init__(self, parent, grass_command = "index", text = None,
-                 skip_description = False, **kwargs):
-        self.grass_command = grass_command
-        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
-        
-        self.content = HelpWindow(self, grass_command, text,
-                                  skip_description)
-        
-        self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
-                                 label = _("&Next"))
-        self.btnNext.Enable(False)
-        self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
-                                 label = _("&Previous"))
-        self.btnPrev.Enable(False)
-        
-        self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
-        self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
-        
-        self._layout()
-
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        btnSizer.Add(item = self.btnPrev, proportion = 0,
-                     flag = wx.ALL, border = 5)
-        btnSizer.Add(item = wx.Size(1, 1), proportion = 1)
-        btnSizer.Add(item = self.btnNext, proportion = 0,
-                     flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        
-        sizer.Add(item = self.content, proportion = 1,
-                  flag = wx.EXPAND)
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.EXPAND)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def LoadPage(self, path = None):
-        """!Load page"""
-        if not path:
-            path = os.path.join(self.content.fspath, self.grass_command + ".html")
-        self.content.history.append(path)
-        self.content.LoadPage(path)
-        
-    def IsFile(self):
-        """!Check if file exists"""
-        return os.path.isfile(os.path.join(self.content.fspath, self.grass_command + ".html"))
-
-    def IsLoaded(self):
-        return self.content.loaded
-
-    def OnHistory(self):
-        """!Update buttons"""
-        nH = len(self.content.history)
-        iH = self.content.historyIdx
-        if iH == nH - 1:
-            self.btnNext.Enable(False)
-        elif iH > -1:
-            self.btnNext.Enable(True)
-        if iH < 1:
-            self.btnPrev.Enable(False)
-        else:
-            self.btnPrev.Enable(True)
-
-    def OnNext(self, event):
-        """Load next page"""
-        self.content.historyIdx += 1
-        idx = self.content.historyIdx
-        path = self.content.history[idx]
-        self.content.LoadPage(path)
-        self.OnHistory()
-        
-        event.Skip()
-        
-    def OnPrev(self, event):
-        """Load previous page"""
-        self.content.historyIdx -= 1
-        idx = self.content.historyIdx
-        path = self.content.history[idx]
-        self.content.LoadPage(path)
-        self.OnHistory()
-        
-        event.Skip()

Deleted: grass/trunk/gui/wxpython/gui_modules/globalvar.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/globalvar.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/globalvar.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,181 +0,0 @@
-"""!
- at package global.py
-
- at brief Global variables
-
-This module provide the space for global variables
-used in the code.
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import locale
-
-if not os.getenv("GISBASE"):
-    sys.exit("GRASS is not running. Exiting...")
-
-# path to python scripts
-ETCDIR = os.path.join(os.getenv("GISBASE"), "etc")
-ETCICONDIR = os.path.join(os.getenv("GISBASE"), "etc", "gui", "icons")
-ETCWXDIR = os.path.join(ETCDIR, "gui", "wxpython")
-ETCIMGDIR = os.path.join(ETCDIR, "gui", "images")
-
-sys.path.append(os.path.join(ETCDIR, "python"))
-import grass.script as grass
-
-def CheckWxVersion(version = [2, 8, 11, 0]):
-    """!Check wx version"""
-    ver = wx.version().split(' ')[0]
-    if map(int, ver.split('.')) < version:
-        return False
-    
-    return True
-
-def CheckForWx():
-    """!Try to import wx module and check its version"""
-    if 'wx' in sys.modules.keys():
-        return
-    
-    minVersion = [2, 8, 1, 1]
-    try:
-        try:
-            import wxversion
-        except ImportError, e:
-            raise ImportError(e)
-        # wxversion.select(str(minVersion[0]) + '.' + str(minVersion[1]))
-        wxversion.ensureMinimal(str(minVersion[0]) + '.' + str(minVersion[1]))
-        import wx
-        version = wx.version().split(' ')[0]
-        
-        if map(int, version.split('.')) < minVersion:
-            raise ValueError('Your wxPython version is %s.%s.%s.%s' % tuple(version.split('.')))
-
-    except ImportError, e:
-        print >> sys.stderr, 'ERROR: wxGUI requires wxPython. %s' % str(e)
-        sys.exit(1)
-    except (ValueError, wxversion.VersionError), e:
-        print >> sys.stderr, 'ERROR: wxGUI requires wxPython >= %d.%d.%d.%d. ' % tuple(minVersion) + \
-            '%s.' % (str(e))
-        sys.exit(1)
-    except locale.Error, e:
-        print >> sys.stderr, "Unable to set locale:", e
-        os.environ['LC_ALL'] = ''
-    
-if not os.getenv("GRASS_WXBUNDLED"):
-    CheckForWx()
-import wx
-import wx.lib.flatnotebook as FN
-
-"""
-Query layer (generated for example by selecting item in the Attribute Table Manager)
-Deleted automatically on re-render action
-"""
-# temporal query layer (removed on re-render action)
-QUERYLAYER = 'qlayer'
-
-"""!Style definition for FlatNotebook pages"""
-FNPageStyle = FN.FNB_VC8 | \
-    FN.FNB_BACKGROUND_GRADIENT | \
-    FN.FNB_NODRAG | \
-    FN.FNB_TABS_BORDER_SIMPLE 
-
-FNPageDStyle = FN.FNB_FANCY_TABS | \
-    FN.FNB_BOTTOM | \
-    FN.FNB_NO_NAV_BUTTONS | \
-    FN.FNB_NO_X_BUTTON
-
-FNPageColor = wx.Colour(125,200,175)
-
-"""!Dialog widget dimension"""
-DIALOG_SPIN_SIZE = (150, -1)
-DIALOG_COMBOBOX_SIZE = (300, -1)
-DIALOG_GSELECT_SIZE = (400, -1)
-DIALOG_TEXTCTRL_SIZE = (400, -1)
-DIALOG_LAYER_SIZE = (100, -1)
-DIALOG_COLOR_SIZE = (30, 30)
-
-MAP_WINDOW_SIZE = (725, 600)
-HIST_WINDOW_SIZE = (500, 350)
-GM_WINDOW_SIZE = (500, 600)
-
-
-"""!File name extension binaries/scripts"""
-if sys.platform == 'win32':
-    EXT_BIN = '.exe'
-    EXT_SCT = '.py'
-else:
-    EXT_BIN = ''
-    EXT_SCT = ''
-
-def GetGRASSCmds(bin = True, scripts = True, gui_scripts = True, addons = True):
-    """!Create list of available GRASS commands to use when parsing
-    string from the command line
-
-    @param bin True to include executable into list
-    @param scripts True to include scripts into list
-    @param gui_scripts True to include GUI scripts into list
-    """
-    gisbase = os.environ['GISBASE']
-    cmd = list()
-    
-    if bin:
-        for executable in os.listdir(os.path.join(gisbase, 'bin')):
-            ext = os.path.splitext(executable)[1]
-            if not EXT_BIN or \
-                    ext in (EXT_BIN, EXT_SCT):
-                cmd.append(executable)
-        
-        # add special call for setting vector colors
-        cmd.append('vcolors')
-    
-    if scripts:
-        cmd += os.listdir(os.path.join(gisbase, 'scripts'))
-    
-    if gui_scripts:
-        os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'gui', 'scripts')
-        cmd = cmd + os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts'))
-    
-    if addons and os.getenv('GRASS_ADDON_PATH'):
-        path = os.getenv('GRASS_ADDON_PATH')
-        bpath = os.path.join(path, 'bin')
-        spath = os.path.join(path, 'scripts')
-        if os.path.exists(bpath) and os.path.isdir(bpath):
-            for executable in os.listdir(bpath):
-                ext = os.path.splitext(executable)[1]
-                if not EXT_BIN or \
-                        ext in (EXT_BIN, EXT_SCT):
-                    cmd.append(executable)
-        if os.path.exists(spath) and os.path.isdir(spath):
-            cmd += os.listdir(spath)
-    
-    if sys.platform == 'win32':
-        for idx in range(len(cmd)):
-            name, ext = os.path.splitext(cmd[idx])
-            if ext in (EXT_BIN, EXT_SCT):
-                cmd[idx] = name
-    
-    return cmd
-
-"""@brief Collected GRASS-relared binaries/scripts"""
-grassCmd = {}
-grassCmd['all']    = GetGRASSCmds()
-grassCmd['script'] = GetGRASSCmds(bin = False, gui_scripts = False)
-
-"""@Toolbar icon size"""
-toolbarSize = (24, 24)
-
-"""@Is g.mlist available?"""
-if 'g.mlist' in grassCmd['all']:
-    have_mlist = True
-else:
-    have_mlist = False
-
-"""@Check version of wxPython, use agwStyle for 2.8.11+"""
-hasAgw = CheckWxVersion()

Deleted: grass/trunk/gui/wxpython/gui_modules/gmodeler.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gmodeler.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gmodeler.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,5092 +0,0 @@
-"""!
- at package gmodeler.py
-
- at brief wxGUI Graphical Modeler for creating, editing, and managing models
-
-Classes:
- - Model
- - ModelFrame
- - ModelCanvas
- - ModelObject
- - ModelAction
- - ModelSearchDialog
- - ModelData
- - ModelDataDialog
- - ModelRelation
- - ModelRelationDialog
- - ProcessModelFile
- - WriteModelFile
- - PreferencesDialog
- - PropertiesDialog
- - ModelParamDialog
- - ModelListCtrl
- - VariablePanel
- - ValiableListCtrl
- - ModelItem
- - ModelItemDialog
- - ModelLoop
- - ModelLoopDialog
- - ItemPanel
- - ItemListCtrl
- - ItemCheckListCtrl
- - ModelCondition
- - ModelConditionDialog
- - WritePythonFile
-
-(C) 2010-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import time
-import traceback
-import getpass
-import stat
-import textwrap
-import tempfile
-import copy
-import re
-import mimetypes
-
-try:
-    import xml.etree.ElementTree as etree
-except ImportError:
-    import elementtree.ElementTree as etree # Python <= 2.4
-
-import globalvar
-import wx
-import wx.lib.ogl             as ogl
-import wx.lib.flatnotebook    as FN
-import wx.lib.colourselect    as csel
-import wx.lib.mixins.listctrl as listmix
-
-import menu
-import menudata
-import toolbars
-import menuform
-import prompt
-import utils
-import goutput
-import gselect
-from debug        import Debug
-from gcmd         import GMessage, GException, GWarning, GError, RunCommand
-from gdialogs     import ElementDialog, GetImageHandlers, MapLayersDialog
-from preferences  import PreferencesBaseDialog, globalSettings as UserSettings
-from ghelp        import SearchModuleWindow
-
-from grass.script import core as grass
-from grass.script import task as gtask
-
-class Model(object):
-    """!Class representing the model"""
-    def __init__(self, canvas = None):
-        self.items      = list() # list of actions/loops/...
-        
-        # model properties
-        self.properties = { 'name'        : _("model"),
-                            'description' : _("Script generated by wxGUI Graphical Modeler."),
-                            'author'      : getpass.getuser() }
-        # model variables
-        self.variables = dict()
-        self.variablesParams = dict()
-        
-        self.canvas  = canvas
-        
-    def GetCanvas(self):
-        """!Get canvas or None"""
-        return self.canvas
-    
-    def GetItems(self, objType = None):
-        """!Get list of model items
-
-        @param objType Object type to filter model objects
-        """
-        if not objType:
-            return self.items
-        
-        result = list()
-        for item in self.items:
-            if isinstance(item, objType):
-                result.append(item)
-        
-        return result
-
-    def GetItem(self, aId):
-        """!Get item of given id
-
-        @param aId item id
-        
-        @return Model* instance
-        @return None if no item found
-        """
-        ilist = self.GetItems()
-        for item in ilist:
-            if item.GetId() == aId:
-                return item
-        
-        return None
-
-    def GetNumItems(self, actionOnly = False):
-        """!Get number of items"""
-        if actionOnly:
-            return len(self.GetItems(objType = ModelAction))
-        
-        return len(self.GetItems())
-
-    def GetNextId(self):
-        """!Get next id (data ignored)
-
-        @return next id to be used (default: 1)
-        """
-        if len(self.items) < 1:
-            return 1
-        
-        currId = self.items[-1].GetId()
-        if currId > 0:
-            return currId + 1
-        
-        return 1
-
-    def GetProperties(self):
-        """!Get model properties"""
-        return self.properties
-
-    def GetVariables(self, params = False):
-        """!Get model variables"""
-        if params:
-            return self.variablesParams
-        
-        return self.variables
-    
-    def SetVariables(self, data):
-        """!Set model variables"""
-        self.variables = data
-    
-    def Reset(self):
-        """!Reset model"""
-        self.items = list()
-        
-    def RemoveItem(self, item):
-        """!Remove item from model
-        
-        @return list of related items to remove/update
-        """
-        relList = list()
-        upList = list()
-        
-        if not isinstance(item, ModelData):
-            self.items.remove(item)
-        
-        if isinstance(item, ModelAction):
-            for rel in item.GetRelations():
-                relList.append(rel)
-                data = rel.GetData()
-                if len(data.GetRelations()) < 2:
-                    relList.append(data)
-                else:
-                    upList.append(data)
-            
-        elif isinstance(item, ModelData):
-            for rel in item.GetRelations():
-                relList.append(rel)
-                if rel.GetFrom() == self:
-                    relList.append(rel.GetTo())
-                else:
-                    relList.append(rel.GetFrom())
-        
-        elif isinstance(item, ModelLoop):
-            for rel in item.GetRelations():
-                relList.append(rel)
-            for action in self.GetItems():
-                action.UnSetBlock(item)
-        
-        return relList, upList
-    
-    def FindAction(self, aId):
-        """!Find action by id"""
-        alist = self.GetItems(objType = ModelAction)
-        for action in alist:
-            if action.GetId() == aId:
-                return action
-        
-        return None
-
-    def GetData(self):
-        """!Get list of data items"""
-        result = list()
-        dataItems = self.GetItems(objType = ModelData)
-        
-        for action in self.GetItems(objType = ModelAction):
-            for rel in action.GetRelations():
-                dataItem = rel.GetData()
-                if dataItem not in result:
-                    result.append(dataItem)
-                if dataItem in dataItems:
-                    dataItems.remove(dataItem)
-        
-        # standalone data
-        if dataItems:
-            result += dataItems
-        
-        return result
-
-    def FindData(self, value, prompt):
-        """!Find data item in the model
-
-        @param value value
-        @param prompt prompt
-
-        @return ModelData instance
-        @return None if not found
-        """
-        for data in self.GetData():
-            if data.GetValue() == value and \
-                    data.GetPrompt() == prompt:
-                return data
-        
-        return None
-                
-    def LoadModel(self, filename):
-        """!Load model definition stored in GRASS Model XML file (gxm)
-        
-        @todo Validate against DTD
-        
-        Raise exception on error.
-        """
-        dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxm.dtd")
-        
-        # parse workspace file
-        try:
-            gxmXml = ProcessModelFile(etree.parse(filename))
-        except StandardError, e:
-            raise GException(e)
-        
-        if self.canvas:
-            win = self.canvas.parent
-            if gxmXml.pos:
-                win.SetPosition(gxmXml.pos)
-            if gxmXml.size:
-                win.SetSize(gxmXml.size)
-        
-        # load properties
-        self.properties = gxmXml.properties
-        self.variables  = gxmXml.variables
-        
-        # load model.GetActions()
-        for action in gxmXml.actions:
-            actionItem = ModelAction(parent = self, 
-                                     x = action['pos'][0],
-                                     y = action['pos'][1],
-                                     width = action['size'][0],
-                                     height = action['size'][1],
-                                     task = action['task'],
-                                     id = action['id'])
-            
-            if action['disabled']:
-                actionItem.Enable(False)
-            
-            self.AddItem(actionItem)
-            
-            actionItem.SetValid(actionItem.GetTask().get_options())
-            actionItem.GetLog() # substitute variables (-> valid/invalid)
-        
-        # load data & relations
-        for data in gxmXml.data:
-            dataItem = ModelData(parent = self, 
-                                 x = data['pos'][0],
-                                 y = data['pos'][1],
-                                 width = data['size'][0],
-                                 height = data['size'][1],
-                                 prompt = data['prompt'],
-                                 value = data['value'])
-            dataItem.SetIntermediate(data['intermediate'])
-            
-            for rel in data['rels']:
-                actionItem = self.FindAction(rel['id'])
-                if rel['dir'] == 'from':
-                    relation = ModelRelation(parent = self, fromShape = dataItem,
-                                             toShape = actionItem, param = rel['name'])
-                else:
-                    relation = ModelRelation(parent = self, fromShape = actionItem,
-                                             toShape = dataItem, param = rel['name'])
-                relation.SetControlPoints(rel['points'])
-                actionItem.AddRelation(relation)
-                dataItem.AddRelation(relation)
-
-            if self.canvas:
-                dataItem.Update()
-           
-        # load loops
-        for loop in gxmXml.loops:
-            loopItem = ModelLoop(parent = self, 
-                                 x = loop['pos'][0],
-                                 y = loop['pos'][1],
-                                 width = loop['size'][0],
-                                 height = loop['size'][1],
-                                 text = loop['text'],
-                                 id = loop['id'])
-            self.AddItem(loopItem)
-
-        # load conditions
-        for condition in gxmXml.conditions:
-            conditionItem = ModelCondition(parent = self, 
-                                           x = condition['pos'][0],
-                                           y = condition['pos'][1],
-                                           width = condition['size'][0],
-                                           height = condition['size'][1],
-                                           text = condition['text'],
-                                           id = condition['id'])
-            self.AddItem(conditionItem)
-
-        # define loops & if/else items
-        for loop in gxmXml.loops:
-            alist = list()
-            for aId in loop['items']:
-                action = self.GetItem(aId)
-                alist.append(action)
-            
-            loopItem = self.GetItem(loop['id'])
-            loopItem.SetItems(alist)
-            
-            for action in loopItem.GetItems():
-                action.SetBlock(loopItem)
-        
-        for condition in gxmXml.conditions:
-            conditionItem = self.GetItem(condition['id'])
-            for b in condition['items'].keys():
-                alist = list()
-                for aId in condition['items'][b]:
-                    action = self.GetItem(aId)
-                    alist.append(action)
-                conditionItem.SetItems(alist, branch = b)
-            
-            items = conditionItem.GetItems()
-            for b in items.keys():
-                for action in items[b]:
-                    action.SetBlock(conditionItem)
-        
-    def AddItem(self, newItem):
-        """!Add item to the list"""
-        iId = newItem.GetId()
-        
-        i  = 0
-        for item in self.items:
-            if item.GetId() > iId:
-                self.items.insert(i, newItem)
-                return
-            i += 1
-        
-        self.items.append(newItem)
-        
-    def IsValid(self):
-        """Return True if model is valid"""
-        if self.Validate():
-            return False
-        
-        return True
-    
-    def Validate(self):
-        """!Validate model, return None if model is valid otherwise
-        error string"""
-        errList = list()
-
-        variables = self.GetVariables().keys()
-        pattern = re.compile(r'(.*)(%.+\s?)(.*)')
-        for action in self.GetItems(objType = ModelAction):
-            cmd = action.GetLog(string = False)
-            
-            task = menuform.GUI(show = None).ParseCommand(cmd = cmd)
-            errList += map(lambda x: cmd[0] + ': ' + x, task.get_cmd_error())
-            
-            # check also variables
-            for opt in cmd[1:]:
-                if '=' not in opt:
-                    continue
-                key, value = opt.split('=', 1)
-                sval = pattern.search(value)
-                if sval:
-                    var = sval.group(2).strip()[1:] # ignore '%'
-                    if var not in variables:
-                        report = True
-                        for item in filter(lambda x: isinstance(x, ModelLoop), action.GetBlock()):
-                            if var in item.GetText():
-                                report = False
-                                break
-                        if report:
-                            errList.append(_("%s: undefined variable '%s'") % (cmd[0], var))
-            ### TODO: check variables in file only optionally
-            ### errList += self._substituteFile(action, checkOnly = True)
-        
-        return errList
-
-    def _substituteFile(self, item, params = None, checkOnly = False):
-        """!Subsitute variables in command file inputs
-
-        @param checkOnly tuble - True to check variable, don't touch files
-        
-        @return list of undefined variables
-        """
-        errList = list()
-        
-        self.fileInput = dict()
-        
-        # collect ascii inputs
-        for p in item.GetParams()['params']:
-            if p.get('element', '') == 'file' and \
-                    p.get('prompt', '') == 'input' and \
-                    p.get('age', '') == 'old':
-                filename = p.get('value', p.get('default', ''))
-                if filename and \
-                        mimetypes.guess_type(filename)[0] == 'text/plain':
-                    self.fileInput[filename] = None
-        
-        for finput in self.fileInput:
-            # read lines
-            fd = open(finput, "r")
-            try:
-                data = self.fileInput[finput] = fd.read()
-            finally:
-                fd.close()
-            
-            # substitute variables
-            write = False
-            variables = self.GetVariables()
-            for variable in variables:
-                pattern = re.compile('%' + variable)
-                value = ''
-                if params and 'variables' in params:
-                    for p in params['variables']['params']:
-                        if variable == p.get('name', ''):
-                            if p.get('type', 'string') == 'string':
-                                value = p.get('value', '')
-                            else:
-                                value = str(p.get('value', ''))
-                            break
-                
-                if not value:
-                    value = variables[variable].get('value', '')
-                
-                data = pattern.sub(value, data)
-                if not checkOnly:
-                    write = True
-            
-            pattern = re.compile(r'(.*)(%.+\s?)(.*)')
-            sval = pattern.search(data)
-            if sval:
-                var = sval.group(2).strip()[1:] # ignore '%'
-                cmd = item.GetLog(string = False)[0]
-                errList.append(_("%s: undefined variable '%s'") % (cmd, var))
-            
-            if not checkOnly:
-                if write:
-                    fd = open(finput, "w")
-                    try:
-                        fd.write(data)
-                    finally:
-                        fd.close()
-                else:
-                    self.fileInput[finput] = None
-        
-        return errList
-    
-    def OnPrepare(self, item, params):
-        self._substituteFile(item, params, checkOnly = False)
-
-    def RunAction(self, item, params, log, onDone, onPrepare = None, statusbar = None):
-        """!Run given action
-
-        @param item action item
-        @param params parameters dict
-        @param log logging window
-        @param onDone on-done method
-        @param onPrepare on-prepare method
-        @param statusbar wx.StatusBar instance or None
-        """
-        name = item.GetName()
-        if name in params:
-            paramsOrig = item.GetParams(dcopy = True)
-            item.MergeParams(params[name])
-        
-        if statusbar:
-            statusbar.SetStatusText(_('Running model...'), 0)
-            
-        data = { 'item' : item,
-                 'params' : copy.deepcopy(params) }
-        log.RunCmd(command = item.GetLog(string = False, substitute = params),
-                   onDone = onDone, onPrepare = self.OnPrepare, userData = data)
-        
-        if name in params:
-            item.SetParams(paramsOrig)
-
-    def Run(self, log, onDone, parent = None):
-        """!Run model
-
-        @param log logging window (see goutput.GMConsole)
-        @param onDone on-done method
-        @param parent window for messages or None
-        """
-        if self.GetNumItems() < 1:
-            GMessage(parent = parent,
-                     message = _('Model is empty. Nothing to run.'))
-            return
-        
-        statusbar = None
-        if isinstance(parent, wx.Frame):
-            statusbar = parent.GetStatusBar()
-        
-        # validation
-        if statusbar:
-            statusbar.SetStatusText(_('Validating model...'), 0)
-        errList = self.Validate()
-        if statusbar:
-            statusbar.SetStatusText('', 0)
-        if errList:
-            dlg = wx.MessageDialog(parent = parent,
-                                   message = _('Model is not valid. Do you want to '
-                                               'run the model anyway?\n\n%s') % '\n'.join(errList),
-                                   caption = _("Run model?"),
-                                   style = wx.YES_NO | wx.NO_DEFAULT |
-                                   wx.ICON_QUESTION | wx.CENTRE)
-            ret = dlg.ShowModal()
-            if ret != wx.ID_YES:
-                return
-        
-        # parametrization
-        params = self.Parameterize()
-        if params:
-            dlg = ModelParamDialog(parent = parent,
-                                   params = params)
-            dlg.CenterOnParent()
-            
-            ret = dlg.ShowModal()
-            if ret != wx.ID_OK:
-                dlg.Destroy()
-                return
-            
-            err = dlg.GetErrors()
-            if err:
-                GError(parent = parent, message = unicode('\n'.join(err)))
-                return
-        
-            err = list()
-            for key, item in params.iteritems():
-                for p in item['params']:
-                    if p.get('value', '') == '':
-                        err.append((key, p.get('name', ''), p.get('description', '')))
-            if err:
-                GError(parent = parent,
-                       message = _("Variables below not defined:") + \
-                           "\n\n" + unicode('\n'.join(map(lambda x: "%s: %s (%s)" % (x[0], x[1], x[2]), err))))
-                return
-        
-        log.cmdThread.SetId(-1)
-        for item in self.GetItems():
-            if not item.IsEnabled():
-                continue
-            if isinstance(item, ModelAction):
-                if item.GetBlockId():
-                    continue
-                self.RunAction(item, params, log, onDone)
-            elif isinstance(item, ModelLoop):
-                cond = item.GetText()
-                # substitute variables in condition
-                variables = self.GetVariables()
-                for variable in variables:
-                    pattern = re.compile('%' + variable)
-                    if pattern.search(cond):
-                        value = ''
-                        if params and 'variables' in params:
-                            for p in params['variables']['params']:
-                                if variable == p.get('name', ''):
-                                    value = p.get('value', '')
-                                    break
-                        
-                        if not value:
-                            value = variables[variable].get('value', '')
-                        
-                        if not value:
-                            continue
-                        
-                        vtype = variables[variable].get('type', 'string')
-                        if vtype == 'string':
-                            value = '"' + value + '"'
-                        cond = pattern.sub(value, cond)
-                
-                # split condition
-                condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
-                pattern = re.compile('%' + condVar)
-                ### for vars()[condVar] in eval(condText): ?
-                if condText[0] == '`' and condText[-1] == '`':
-                    # run command
-                    cmd, dcmd = utils.CmdToTuple(condText[1:-1].split(' '))
-                    ret = RunCommand(cmd,
-                                     read = True,
-                                     **dcmd)
-                    if ret:
-                        vlist = ret.splitlines()
-                else:
-                    vlist = eval(condText)
-                
-                if 'variables' not in params:
-                    params['variables'] = { 'params' : [] }
-                varDict = { 'name' : condVar, 'value' : '' }
-                params['variables']['params'].append(varDict)
-                                
-                for var in vlist:
-                    for action in item.GetItems():
-                        if not isinstance(action, ModelAction) or \
-                                not action.IsEnabled():
-                            continue
-                        
-                        varDict['value'] = var
-                                                
-                        self.RunAction(item = action, params = params,
-                                       log = log, onDone = onDone)
-                params['variables']['params'].remove(varDict)
-                
-        # discard values
-        if params:
-            for item in params.itervalues():
-                for p in item['params']:
-                    p['value'] = ''
-        
-        if params:
-            dlg.Destroy()
-        
-    def DeleteIntermediateData(self, log):
-        """!Detele intermediate data"""
-        rast, vect, rast3d, msg = self.GetIntermediateData()
-        
-        if rast:
-            log.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
-        if rast3d:
-            log.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
-        if vect:
-            log.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
-        
-    def GetIntermediateData(self):
-        """!Get info about intermediate data"""
-        rast = list()
-        rast3d = list()
-        vect = list()
-        for data in self.GetData():
-            if not data.IsIntermediate():
-                continue
-            name = data.GetValue()
-            prompt = data.GetPrompt()
-            if prompt == 'raster':
-                rast.append(name)
-            elif prompt == 'vector':
-                vect.append(name)
-            elif prompt == 'rast3d':
-                rast3d.append(name)
-        
-        msg = ''
-        if rast:
-            msg += '\n\n%s: ' % _('Raster maps')
-            msg += ', '.join(rast)
-        if rast3d:
-            msg += '\n\n%s: ' % _('3D raster maps')
-            msg += ', '.join(rast3d)
-        if vect:
-            msg += '\n\n%s: ' % _('Vector maps')
-            msg += ', '.join(vect)
-        
-        return rast, vect, rast3d, msg
-
-    def Update(self):
-        """!Update model"""
-        for item in self.items:
-            item.Update()
-        
-    def IsParameterized(self):
-        """!Return True if model is parameterized"""
-        if self.Parameterize():
-            return True
-        
-        return False
-    
-    def Parameterize(self):
-        """!Return parameterized options"""
-        result = dict()
-        idx = 0
-        if self.variables:
-            params = list()
-            result["variables"] = { 'flags'  : list(),
-                                    'params' : params,
-                                    'idx'    : idx }
-            for name, values in self.variables.iteritems():
-                gtype = values.get('type', 'string')
-                if gtype in ('raster', 'vector', 'mapset', 'file'):
-                    gisprompt = True
-                    prompt = gtype
-                    if gtype == 'raster':
-                        element = 'cell'
-                    else:
-                        element = gtype
-                    ptype = 'string'
-                else:
-                    gisprompt = False
-                    prompt = None
-                    element = None
-                    ptype = gtype
-                params.append({ 'gisprompt' : gisprompt,
-                                'multiple'  : False,
-                                'description' : values.get('description', ''),
-                                'guidependency' : '',
-                                'default' : '',
-                                'age' : None,
-                                'required' : True,
-                                'value' : values.get('value', ''),
-                                'label' : '',
-                                'guisection' : '',
-                                'key_desc' : '',
-                                'values' : list(),
-                                'parameterized' : False,
-                                'values_desc' : list(),
-                                'prompt' : prompt,
-                                'element' : element,
-                                'type' : ptype,
-                                'name' : name })
-            
-            idx += 1
-        
-        for action in self.GetItems(objType = ModelAction):
-            if not action.IsEnabled():
-                continue
-            name   = action.GetName()
-            params = action.GetParams()
-            for f in params['flags']:
-                if f.get('parameterized', False):
-                    if name not in result:
-                        result[name] = { 'flags' : list(),
-                                         'params': list(),
-                                         'idx'   : idx }
-                    result[name]['flags'].append(f)
-            for p in params['params']:
-                if p.get('parameterized', False):
-                    if name not in result:
-                        result[name] = { 'flags' : list(),
-                                         'params': list(),
-                                         'idx'   : idx }
-                    result[name]['params'].append(p)
-            if name in result:
-                idx += 1
-        
-        self.variablesParams = result # record parameters
-        
-        return result
-    
-class ModelFrame(wx.Frame):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _("GRASS GIS Graphical Modeler"), **kwargs):
-        """!Graphical modeler main window
-        
-        @param parent parent window
-        @param id window id
-        @param title window title
-
-        @param kwargs wx.Frames' arguments
-        """
-        self.parent = parent
-        self.searchDialog = None # module search dialog
-        self.baseTitle = title
-        self.modelFile = None    # loaded model
-        self.modelChanged = False
-        
-        self.cursors = {
-            "default" : wx.StockCursor(wx.CURSOR_ARROW),
-            "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
-            }
-        
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
-        self.SetName("Modeler")
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.menubar = menu.Menu(parent = self, data = menudata.ModelerData())
-        
-        self.SetMenuBar(self.menubar)
-        
-        self.toolbar = toolbars.ModelToolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-        
-        self.statusbar = self.CreateStatusBar(number = 1)
-        
-        self.notebook = menuform.GNotebook(parent = self,
-                                           style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
-                                           FN.FNB_NO_NAV_BUTTONS | FN.FNB_NO_X_BUTTON)
-        
-        self.canvas = ModelCanvas(self)
-        self.canvas.SetBackgroundColour(wx.WHITE)
-        self.canvas.SetCursor(self.cursors["default"])
-        
-        self.model = Model(self.canvas)
-        
-        self.variablePanel = VariablePanel(parent = self)
-        
-        self.itemPanel = ItemPanel(parent = self)
-        
-        self.goutput = goutput.GMConsole(parent = self, notebook = self.notebook)
-        
-        self.notebook.AddPage(page = self.canvas, text=_('Model'), name = 'model')
-        self.notebook.AddPage(page = self.itemPanel, text=_('Items'), name = 'items')
-        self.notebook.AddPage(page = self.variablePanel, text=_('Variables'), name = 'variables')
-        self.notebook.AddPage(page = self.goutput, text=_('Command output'), name = 'output')
-        wx.CallAfter(self.notebook.SetSelectionByName, 'model')
-        wx.CallAfter(self.ModelChanged, False)
-
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        
-        self._layout()
-        self.SetMinSize((475, 300))
-        self.SetSize((640, 480))
-        
-        # fix goutput's pane size
-        if self.goutput:
-            self.goutput.SetSashPosition(int(self.GetSize()[1] * .75))
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        sizer.Add(item = self.notebook, proportion = 1,
-                  flag = wx.EXPAND)
-        
-        self.SetAutoLayout(True)
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-        
-        self.Layout()
-
-    def _addEvent(self, item):
-        """!Add event to item"""
-        evthandler = ModelEvtHandler(self.statusbar,
-                                     self)
-        evthandler.SetShape(item)
-        evthandler.SetPreviousHandler(item.GetEventHandler())
-        item.SetEventHandler(evthandler)
-
-    def GetCanvas(self):
-        """!Get canvas"""
-        return self.canvas
-    
-    def GetModel(self):
-        """!Get model"""
-        return self.model
-    
-    def ModelChanged(self, changed = True):
-        """!Update window title"""
-        self.modelChanged = changed
-        
-        if self.modelFile:
-            if self.modelChanged:
-                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile) + '*')
-            else:
-                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
-        else:
-            self.SetTitle(self.baseTitle)
-        
-    def OnVariables(self, event):
-        """!Switch to variables page"""
-        self.notebook.SetSelectionByName('variables')
-        
-    def OnRemoveItem(self, event):
-        """!Remove shape
-        """
-        self.GetCanvas().RemoveSelected()
-        
-    def OnCanvasRefresh(self, event):
-        """!Refresh canvas"""
-        self.SetStatusText(_("Redrawing model..."), 0)
-        self.GetCanvas().Refresh()
-        self.SetStatusText("", 0)
-
-    def OnCmdRun(self, event):
-        """!Run command"""
-        try:
-            action = self.GetModel().GetItems()[event.pid]
-            if hasattr(action, "task"):
-                action.Update(running = True)
-        except IndexError:
-            pass
-        
-    def OnCmdPrepare(self, event):
-        """!Prepare for running command"""
-        event.onPrepare(item = event.userData['item'],
-                        params = event.userData['params'])
-        
-    def OnCmdDone(self, event):
-        """!Command done (or aborted)"""
-        try:
-            action = self.GetModel().GetItems()[event.pid]
-            if hasattr(action, "task"):
-                action.Update(running = True)
-        except IndexError:
-            pass
-        
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        if self.modelChanged and \
-                UserSettings.Get(group='manager', key='askOnQuit', subkey='enabled'):
-            if self.modelFile:
-                message = _("Do you want to save changes in the model?")
-            else:
-                message = _("Do you want to store current model settings "
-                            "to model file?")
-            
-            # ask user to save current settings
-            dlg = wx.MessageDialog(self,
-                                   message = message,
-                                   caption=_("Quit Graphical Modeler"),
-                                   style = wx.YES_NO | wx.YES_DEFAULT |
-                                   wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
-            ret = dlg.ShowModal()
-            if ret == wx.ID_YES:
-                if not self.modelFile:
-                        self.OnWorkspaceSaveAs()
-                else:
-                    self.WriteModelFile(self.modelFile)
-            elif ret == wx.ID_CANCEL:
-                dlg.Destroy()
-                return
-            dlg.Destroy()
-        
-        self.Destroy()
-
-    def OnSize(self, event):
-        """Window resized, save to the model"""
-        self.ModelChanged()
-        event.Skip()
-        
-    def OnPreferences(self, event):
-        """!Open preferences dialog"""
-        dlg = PreferencesDialog(parent = self)
-        dlg.CenterOnParent()
-        
-        dlg.ShowModal()
-        self.canvas.Refresh()
-        
-    def OnHelp(self, event):
-        """!Show help"""
-        if self.parent and self.parent.GetName() == 'LayerManager':
-            log = self.parent.GetLogWindow()
-            log.RunCmd(['g.manual',
-                        'entry=wxGUI.Modeler'])
-        else:
-            RunCommand('g.manual',
-                       quiet = True,
-                       entry = 'wxGUI.Modeler')
-        
-    def OnModelProperties(self, event):
-        """!Model properties dialog"""
-        dlg = PropertiesDialog(parent = self)
-        dlg.CentreOnParent()
-        properties = self.model.GetProperties()
-        dlg.Init(properties)
-        if dlg.ShowModal() == wx.ID_OK:
-            self.ModelChanged()
-            for key, value in dlg.GetValues().iteritems():
-                properties[key] = value
-            for action in self.model.GetItems(objType = ModelAction):
-                action.GetTask().set_flag('overwrite', properties['overwrite'])
-        
-        dlg.Destroy()
-        
-    def OnDeleteData(self, event):
-        """!Delete intermediate data"""
-        rast, vect, rast3d, msg = self.model.GetIntermediateData()
-        
-        if not rast and not vect and not rast3d:
-            GMessage(parent = self,
-                     message = _('Nothing to delete.'))
-            return
-        
-        dlg = wx.MessageDialog(parent = self,
-                               message= _("Do you want to permanently delete data?%s" % msg),
-                               caption=_("Delete intermediate data?"),
-                               style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-        
-        ret = dlg.ShowModal()
-        if ret == wx.ID_YES:
-            dlg.Destroy()
-            
-            if rast:
-                self.goutput.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
-            if rast3d:
-                self.goutput.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
-            if vect:
-                self.goutput.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
-            
-            self.SetStatusText(_("%d maps deleted from current mapset") % \
-                                 int(len(rast) + len(rast3d) + len(vect)))
-            return
-        
-        dlg.Destroy()
-                
-    def OnModelNew(self, event):
-        """!Create new model"""
-        Debug.msg(4, "ModelFrame.OnModelNew():")
-        
-        # ask user to save current model
-        if self.modelFile and self.modelChanged:
-            self.OnModelSave()
-        elif self.modelFile is None and \
-                (self.model.GetNumItems() > 0 or len(self.model.GetData()) > 0):
-            dlg = wx.MessageDialog(self, message=_("Current model is not empty. "
-                                                   "Do you want to store current settings "
-                                                   "to model file?"),
-                                   caption=_("Create new model?"),
-                                   style=wx.YES_NO | wx.YES_DEFAULT |
-                                   wx.CANCEL | wx.ICON_QUESTION)
-            ret = dlg.ShowModal()
-            if ret == wx.ID_YES:
-                self.OnModelSaveAs()
-            elif ret == wx.ID_CANCEL:
-                dlg.Destroy()
-                return
-            
-            dlg.Destroy()
-        
-        # delete all items
-        self.canvas.GetDiagram().DeleteAllShapes()
-        self.model.Reset()
-        self.canvas.Refresh()
-        self.itemPanel.Update()
-        self.variablePanel.Reset()
-        
-        # no model file loaded
-        self.modelFile = None
-        self.modelChanged = False
-        self.SetTitle(self.baseTitle)
-        
-    def OnModelOpen(self, event):
-        """!Load model from file"""
-        filename = ''
-        dlg = wx.FileDialog(parent = self, message=_("Choose model file"),
-                            defaultDir = os.getcwd(),
-                            wildcard=_("GRASS Model File (*.gxm)|*.gxm"))
-        if dlg.ShowModal() == wx.ID_OK:
-            filename = dlg.GetPath()
-                    
-        if not filename:
-            return
-        
-        Debug.msg(4, "ModelFrame.OnModelOpen(): filename=%s" % filename)
-        
-        # close current model
-        self.OnModelClose()
-        
-        self.LoadModelFile(filename)
-        
-        self.modelFile = filename
-        self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
-        self.SetStatusText(_('%(items)d items (%(actions)d actions) loaded into model') % \
-                               { 'items' : self.model.GetNumItems(),
-                                 'actions' : self.model.GetNumItems(actionOnly = True) }, 0)
-        
-    def OnModelSave(self, event = None):
-        """!Save model to file"""
-        if self.modelFile and self.modelChanged:
-            dlg = wx.MessageDialog(self, message=_("Model file <%s> already exists. "
-                                                   "Do you want to overwrite this file?") % \
-                                       self.modelFile,
-                                   caption=_("Save model"),
-                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-            if dlg.ShowModal() == wx.ID_NO:
-                dlg.Destroy()
-            else:
-                Debug.msg(4, "ModelFrame.OnModelSave(): filename=%s" % self.modelFile)
-                self.WriteModelFile(self.modelFile)
-                self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
-                self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
-        elif not self.modelFile:
-            self.OnModelSaveAs(None)
-        
-    def OnModelSaveAs(self, event):
-        """!Create model to file as"""
-        filename = ''
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Choose file to save current model"),
-                            defaultDir = os.getcwd(),
-                            wildcard=_("GRASS Model File (*.gxm)|*.gxm"),
-                            style=wx.FD_SAVE)
-        
-        
-        if dlg.ShowModal() == wx.ID_OK:
-            filename = dlg.GetPath()
-        
-        if not filename:
-            return
-        
-        # check for extension
-        if filename[-4:] != ".gxm":
-            filename += ".gxm"
-        
-        if os.path.exists(filename):
-            dlg = wx.MessageDialog(parent = self,
-                                   message=_("Model file <%s> already exists. "
-                                             "Do you want to overwrite this file?") % filename,
-                                   caption=_("File already exists"),
-                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-            if dlg.ShowModal() != wx.ID_YES:
-                dlg.Destroy()
-                return
-        
-        Debug.msg(4, "GMFrame.OnModelSaveAs(): filename=%s" % filename)
-        
-        self.WriteModelFile(filename)
-        self.modelFile = filename
-        self.SetTitle(self.baseTitle + " - " + os.path.basename(self.modelFile))
-        self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
-
-    def OnModelClose(self, event = None):
-        """!Close model file"""
-        Debug.msg(4, "ModelFrame.OnModelClose(): file=%s" % self.modelFile)
-        # ask user to save current model
-        if self.modelFile and self.modelChanged:
-            self.OnModelSave()
-        elif self.modelFile is None and \
-                (self.model.GetNumItems() > 0 or len(self.model.GetData()) > 0):
-            dlg = wx.MessageDialog(self, message=_("Current model is not empty. "
-                                                   "Do you want to store current settings "
-                                                   "to model file?"),
-                                   caption=_("Create new model?"),
-                                   style=wx.YES_NO | wx.YES_DEFAULT |
-                                   wx.CANCEL | wx.ICON_QUESTION)
-            ret = dlg.ShowModal()
-            if ret == wx.ID_YES:
-                self.OnModelSaveAs()
-            elif ret == wx.ID_CANCEL:
-                dlg.Destroy()
-                return
-            
-            dlg.Destroy()
-        
-        self.modelFile = None
-        self.SetTitle(self.baseTitle)
-        
-        self.canvas.GetDiagram().DeleteAllShapes()
-        self.model.Reset()
-        
-        self.canvas.Refresh()
-        
-    def OnRunModel(self, event):
-        """!Run entire model"""
-        self.model.Run(self.goutput, self.OnDone, parent = self)
-        
-    def OnDone(self, cmd, returncode):
-        """!Computation finished"""
-        self.SetStatusText('', 0)
-        # restore original files
-        if hasattr(self.model, "fileInput"):
-            for finput in self.model.fileInput:
-                data = self.model.fileInput[finput]
-                if not data:
-                    continue
-                
-                fd = open(finput, "w")
-                try:
-                    fd.write(data)
-                finally:
-                    fd.close()
-            del self.model.fileInput
-        
-    def OnValidateModel(self, event, showMsg = True):
-        """!Validate entire model"""
-        if self.model.GetNumItems() < 1:
-            GMessage(parent = self, 
-                     message = _('Model is empty. Nothing to validate.'))
-            return
-        
-        
-        self.SetStatusText(_('Validating model...'), 0)
-        errList = self.model.Validate()
-        self.SetStatusText('', 0)
-        
-        if errList:
-            GWarning(parent = self,
-                     message = _('Model is not valid.\n\n%s') % '\n'.join(errList))
-        else:
-            GMessage(parent = self,
-                     message = _('Model is valid.'))
-    
-    def OnExportImage(self, event):
-        """!Export model to image (default image)
-        """
-        xminImg = 0
-        xmaxImg = 0
-        yminImg = 0
-        ymaxImg = 0
-        # get current size of canvas
-        for shape in self.canvas.GetDiagram().GetShapeList():
-            w, h = shape.GetBoundingBoxMax()
-            x    = shape.GetX()
-            y    = shape.GetY()
-            xmin = x - w / 2
-            xmax = x + w / 2
-            ymin = y - h / 2
-            ymax = y + h / 2
-            if xmin < xminImg:
-                xminImg = xmin
-            if xmax > xmaxImg:
-                xmaxImg = xmax
-            if ymin < yminImg:
-                yminImg = ymin
-            if ymax > ymaxImg:
-                ymaxImg = ymax
-        size = wx.Size(int(xmaxImg - xminImg) + 50,
-                       int(ymaxImg - yminImg) + 50)
-        bitmap = wx.EmptyBitmap(width = size.width, height = size.height)
-        
-        filetype, ltype = GetImageHandlers(wx.ImageFromBitmap(bitmap))
-        
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Choose a file name to save the image (no need to add extension)"),
-                            defaultDir = "",
-                            defaultFile = "",
-                            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
-            
-            dc = wx.MemoryDC(bitmap)
-            dc.SetBackground(wx.WHITE_BRUSH)
-            dc.SetBackgroundMode(wx.SOLID)
-            
-            dc.BeginDrawing()
-            self.canvas.GetDiagram().Clear(dc)
-            self.canvas.GetDiagram().Redraw(dc)
-            dc.EndDrawing()
-            
-            bitmap.SaveFile(path, fileType)
-            self.SetStatusText(_("Model exported to <%s>") % path)
-        
-        dlg.Destroy()
-        
-    def OnExportPython(self, event):
-        """!Export model to Python script"""
-        filename = ''
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Choose file to save"),
-                            defaultDir = os.getcwd(),
-                            wildcard=_("Python script (*.py)|*.py"),
-                            style=wx.FD_SAVE)
-        
-        if dlg.ShowModal() == wx.ID_OK:
-            filename = dlg.GetPath()
-        
-        if not filename:
-            return
-        
-        # check for extension
-        if filename[-3:] != ".py":
-            filename += ".py"
-        
-        if os.path.exists(filename):
-            dlg = wx.MessageDialog(self, message=_("File <%s> already exists. "
-                                                   "Do you want to overwrite this file?") % filename,
-                                   caption=_("Save file"),
-                                   style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-            if dlg.ShowModal() == wx.ID_NO:
-                dlg.Destroy()
-                return
-            
-            dlg.Destroy()
-        
-        fd = open(filename, "w")
-        try:
-            WritePythonFile(fd, self.model)
-        finally:
-            fd.close()
-        
-        # executable file
-        os.chmod(filename, stat.S_IRWXU | stat.S_IWUSR)
-        
-        self.SetStatusText(_("Model exported to <%s>") % filename)
-
-    def OnDefineRelation(self, event):
-        """!Define relation between data and action items"""
-        self.canvas.SetCursor(self.cursors["cross"])
-        self.defineRelation = { 'from' : None,
-                                'to'   : None }
-        
-    def OnDefineLoop(self, event):
-        """!Define new loop in the model"""
-        self.ModelChanged()
-        
-        width, height = self.canvas.GetSize()
-        loop = ModelLoop(self, x = width/2, y = height/2,
-                         id = self.model.GetNumItems() + 1)
-        self.canvas.diagram.AddShape(loop)
-        loop.Show(True)
-        
-        self._addEvent(loop)
-        self.model.AddItem(loop)
-        
-        self.canvas.Refresh()
-        
-    def OnDefineCondition(self, event):
-        """!Define new condition in the model"""
-        self.ModelChanged()
-        
-        width, height = self.canvas.GetSize()
-        cond = ModelCondition(self, x = width/2, y = height/2,
-                              id = self.model.GetNumItems() + 1)
-        self.canvas.diagram.AddShape(cond)
-        cond.Show(True)
-        
-        self._addEvent(cond)
-        self.model.AddItem(cond)
-        
-        self.canvas.Refresh()
-    
-    def OnAddAction(self, event):
-        """!Add action to model"""
-        if self.searchDialog is None:
-            self.searchDialog = ModelSearchDialog(self)
-            self.searchDialog.CentreOnParent()
-        else:
-            self.searchDialog.Reset()
-            
-        if self.searchDialog.ShowModal() == wx.ID_CANCEL:
-            self.searchDialog.Hide()
-            return
-            
-        cmd = self.searchDialog.GetCmd()
-        self.searchDialog.Hide()
-        
-        self.ModelChanged()
-        
-        # add action to canvas
-        width, height = self.canvas.GetSize()
-        action = ModelAction(self.model, cmd = cmd, x = width/2, y = height/2,
-                             id = self.model.GetNextId())
-        overwrite = self.model.GetProperties().get('overwrite', None)
-        if overwrite is not None:
-            action.GetTask().set_flag('overwrite', overwrite)
-        
-        self.canvas.diagram.AddShape(action)
-        action.Show(True)
-
-        self._addEvent(action)
-        self.model.AddItem(action)
-        
-        self.itemPanel.Update()
-        self.canvas.Refresh()
-        time.sleep(.1)
-        
-        # show properties dialog
-        win = action.GetPropDialog()
-        if not win:
-            if action.IsValid():
-                self.GetOptData(dcmd = action.GetLog(string = False), layer = action,
-                                params = action.GetParams(), propwin = None)
-            else:
-                menuform.GUI(parent = self, show = True).ParseCommand(action.GetLog(string = False),
-                                                                      completed = (self.GetOptData, action, action.GetParams()))
-        elif win and not win.IsShown():
-            win.Show()
-        
-        if win:
-            win.Raise()
-        
-    def OnAddData(self, event):
-        """!Add data item to model
-        """
-        # add action to canvas
-        width, height = self.canvas.GetSize()
-        data = ModelData(self, x = width/2, y = height/2)
-       
-        dlg = ModelDataDialog(parent = self, shape = data)
-        data.SetPropDialog(dlg)
-        dlg.CentreOnParent()
-        ret = dlg.ShowModal()
-        dlg.Destroy()
-        if ret != wx.ID_OK:
-            return
-        
-        data.Update()
-        self.canvas.diagram.AddShape(data)
-        data.Show(True)
-        
-        self.ModelChanged()
-        
-        self._addEvent(data)
-        self.model.AddItem(data)
-        
-        self.canvas.Refresh()
-        
-        
-    def OnHelp(self, event):
-        """!Display manual page"""
-        grass.run_command('g.manual',
-                          entry = 'wxGUI.Modeler')
-
-    def OnAbout(self, event):
-        """!Display About window"""
-        info = wx.AboutDialogInfo()
-
-        info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        info.SetName(_('wxGUI Graphical Modeler'))
-        info.SetWebSite('http://grass.osgeo.org')
-        year = grass.version()['date']
-        info.SetDescription(_('(C) 2010-%s by the GRASS Development Team\n\n') % year + 
-                            '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
-                                                      '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
-        
-        wx.AboutBox(info)
-        
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """!Process action data"""
-        if params: # add data items
-            width, height = self.canvas.GetSize()
-            x = [width/2 + 200, width/2 - 200]
-            for p in params['params']:
-                if p.get('prompt', '') in ('raster', 'vector', 'raster3d') and \
-                        (p.get('value', None) or \
-                             (p.get('age', 'old') != 'old' and p.get('required', 'no') == 'yes')):
-                    data = layer.FindData(p.get('name', ''))
-                    if data:
-                        data.SetValue(p.get('value', ''))
-                        data.Update()
-                        continue
-                    
-                    data = self.model.FindData(p.get('value', ''),
-                                               p.get('prompt', ''))
-                    if data:
-                        if p.get('age', 'old') == 'old':
-                            rel = ModelRelation(parent = self, fromShape = data,
-                                                toShape = layer, param = p.get('name', ''))
-                        else:
-                            rel = ModelRelation(parent = self, fromShape = layer,
-                                                toShape = data, param = p.get('name', ''))
-                        layer.AddRelation(rel)
-                        data.AddRelation(rel)
-                        self.AddLine(rel)
-                        data.Update()
-                        continue
-                    
-                    data = ModelData(self, value = p.get('value', ''),
-                                     prompt = p.get('prompt', ''),
-                                     x = x.pop(), y = height/2)
-                    self._addEvent(data)
-                    self.canvas.diagram.AddShape(data)
-                    data.Show(True)
-                                                            
-                    if p.get('age', 'old') == 'old':
-                        rel = ModelRelation(parent = self, fromShape = data,
-                                            toShape = layer, param = p.get('name', ''))
-                    else:
-                        rel = ModelRelation(parent = self, fromShape = layer,
-                                            toShape = data, param = p.get('name', ''))
-                    layer.AddRelation(rel)
-                    data.AddRelation(rel)
-                    self.AddLine(rel)
-                    data.Update()
-            
-            # valid / parameterized ?
-            layer.SetValid(params)
-            
-            self.canvas.Refresh()
-        
-        if dcmd:
-            layer.SetProperties(params, propwin)
-            
-        self.SetStatusText(layer.GetLog(), 0)
-        
-    def AddLine(self, rel):
-        """!Add connection between model objects
-        
-        @param rel relation
-        """
-        fromShape = rel.GetFrom()
-        toShape   = rel.GetTo()
-        
-        rel.SetCanvas(self)
-        rel.SetPen(wx.BLACK_PEN)
-        rel.SetBrush(wx.BLACK_BRUSH)
-        rel.AddArrow(ogl.ARROW_ARROW)
-        points = rel.GetControlPoints()
-        rel.MakeLineControlPoints(2)
-        if points:
-            for x, y in points:
-                rel.InsertLineControlPoint(point = wx.RealPoint(x, y))
-        
-        self._addEvent(rel)
-        try:
-            fromShape.AddLine(rel, toShape)
-        except TypeError:
-            pass # bug when connecting ModelCondition and ModelLoop - to be fixed
-        
-        self.canvas.diagram.AddShape(rel)
-        rel.Show(True)
-        
-    def LoadModelFile(self, filename):
-        """!Load model definition stored in GRASS Model XML file (gxm)
-        """
-        try:
-            self.model.LoadModel(filename)
-        except GException, e:
-            GError(parent = self,
-                   message = _("Reading model file <%s> failed.\n"
-                               "Invalid file, unable to parse XML document.") % filename)
-        
-        self.modelFile = filename
-        self.SetTitle(self.baseTitle + " - " +  os.path.basename(self.modelFile))
-        
-        self.SetStatusText(_("Please wait, loading model..."), 0)
-        
-        # load actions
-        for item in self.model.GetItems(objType = ModelAction):
-            self._addEvent(item)
-            self.canvas.diagram.AddShape(item)
-            item.Show(True)
-            # relations/data
-            for rel in item.GetRelations():
-                if rel.GetFrom() == item:
-                    dataItem = rel.GetTo()
-                else:
-                    dataItem = rel.GetFrom()
-                self._addEvent(dataItem)
-                self.canvas.diagram.AddShape(dataItem)
-                self.AddLine(rel)
-                dataItem.Show(True)
-        
-        # load loops
-        for item in self.model.GetItems(objType = ModelLoop):
-            self._addEvent(item)
-            self.canvas.diagram.AddShape(item)
-            item.Show(True)
-            
-            # connect items in the loop
-            self.DefineLoop(item)
-
-        # load conditions
-        for item in self.model.GetItems(objType = ModelCondition):
-            self._addEvent(item)
-            self.canvas.diagram.AddShape(item)
-            item.Show(True)
-            
-            # connect items in the condition
-            self.DefineCondition(item)
-        
-        # load variables
-        self.variablePanel.Update()
-        self.itemPanel.Update()
-        self.SetStatusText('', 0)
-        
-        # final updates
-        for action in self.model.GetItems(objType = ModelAction):
-            action.SetValid(action.GetParams())
-            action.Update()
-        
-        self.canvas.Refresh(True)
-        
-    def WriteModelFile(self, filename):
-        """!Save model to model file, recover original file on error.
-        
-        @return True on success
-        @return False on failure
-        """
-        self.ModelChanged(False)
-        tmpfile = tempfile.TemporaryFile(mode='w+b')
-        try:
-            WriteModelFile(fd = tmpfile, model = self.model)
-        except StandardError:
-            GError(parent = self,
-                   message = _("Writing current settings to model file failed."))
-            return False
-        
-        try:
-            mfile = open(filename, "w")
-            tmpfile.seek(0)
-            for line in tmpfile.readlines():
-                mfile.write(line)
-        except IOError:
-            wx.MessageBox(parent = self,
-                          message = _("Unable to open file <%s> for writing.") % filename,
-                          caption = _("Error"),
-                          style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return False
-        
-        mfile.close()
-        
-        return True
-    
-    def DefineLoop(self, loop):
-        """!Define loop with given list of items"""
-        parent = loop
-        items = loop.GetItems()
-        if not items:
-            return
-        
-        # remove defined relations first
-        for rel in loop.GetRelations():
-            self.canvas.GetDiagram().RemoveShape(rel)
-        loop.Clear()
-        
-        for item in items:
-            rel = ModelRelation(parent = self, fromShape = parent, toShape = item)
-            dx = item.GetX() - parent.GetX()
-            dy = item.GetY() - parent.GetY()
-            loop.AddRelation(rel)
-            if dx != 0:
-                rel.SetControlPoints(((parent.GetX(), parent.GetY() + dy / 2),
-                                      (parent.GetX() + dx, parent.GetY() + dy / 2)))
-            self.AddLine(rel)
-            parent = item
-        
-        # close loop
-        item = loop.GetItems()[-1]
-        rel = ModelRelation(parent = self, fromShape = item, toShape = loop)
-        loop.AddRelation(rel)
-        self.AddLine(rel)
-        dx = (item.GetX() - loop.GetX()) + loop.GetWidth() / 2 + 50
-        dy = item.GetHeight() / 2 + 50
-        rel.MakeLineControlPoints(0)
-        rel.InsertLineControlPoint(point = wx.RealPoint(loop.GetX() - loop.GetWidth() / 2 ,
-                                                        loop.GetY()))
-        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
-                                                        item.GetY() + item.GetHeight() / 2))
-        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX(),
-                                                        item.GetY() + dy))
-        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
-                                                        item.GetY() + dy))
-        rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - dx,
-                                                        loop.GetY()))
-        
-        self.canvas.Refresh()
-
-    def DefineCondition(self, condition):
-        """!Define if-else statement with given list of items"""
-        parent = condition
-        items = condition.GetItems()
-        if not items['if'] and not items['else']:
-            return
-        
-        # remove defined relations first
-        for rel in condition.GetRelations():
-            self.canvas.GetDiagram().RemoveShape(rel)
-        condition.Clear()
-        dxIf   = condition.GetX() + condition.GetWidth() / 2
-        dxElse = condition.GetX() - condition.GetWidth() / 2
-        dy     = condition.GetY()
-        for branch in items.keys():
-            for item in items[branch]:
-                rel = ModelRelation(parent = self, fromShape = parent,
-                                    toShape = item)
-                condition.AddRelation(rel)
-                self.AddLine(rel)
-                rel.MakeLineControlPoints(0)
-                if branch == 'if':
-                    rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
-                    rel.InsertLineControlPoint(point = wx.RealPoint(dxIf, dy))
-                else:
-                    rel.InsertLineControlPoint(point = wx.RealPoint(dxElse, dy))
-                    rel.InsertLineControlPoint(point = wx.RealPoint(item.GetX() - item.GetWidth() / 2, item.GetY()))
-                parent = item
-        
-        self.canvas.Refresh()
-        
-class ModelCanvas(ogl.ShapeCanvas):
-    """!Canvas where model is drawn"""
-    def __init__(self, parent):
-        self.parent = parent
-        ogl.OGLInitialize()
-        ogl.ShapeCanvas.__init__(self, parent)
-        
-        self.diagram = ogl.Diagram()
-        self.SetDiagram(self.diagram)
-        self.diagram.SetCanvas(self)
-        
-        self.SetScrollbars(20, 20, 1000/20, 1000/20)
-        
-        self.Bind(wx.EVT_CHAR,  self.OnChar)
-        
-    def OnChar(self, event):
-        """!Key pressed"""
-        kc = event.GetKeyCode()
-        diagram = self.GetDiagram()
-        if kc == wx.WXK_DELETE:
-            self.RemoveSelected()
-        
-    def RemoveSelected(self):
-        """!Remove selected shapes"""
-        self.parent.ModelChanged()
-        
-        diagram = self.GetDiagram()
-        for shape in diagram.GetShapeList():
-            if not shape.Selected():
-                continue
-            remList, upList = self.parent.GetModel().RemoveItem(shape)
-            shape.Select(False)
-            diagram.RemoveShape(shape)
-            shape.__del__()
-            for item in remList:
-                diagram.RemoveShape(item)
-                item.__del__()
-            
-            for item in upList:
-                item.Update()
-        
-        self.Refresh()
-        
-class ModelObject:
-    def __init__(self, id = -1):
-        self.id   = id
-        self.rels = list() # list of ModelRelations
-        
-        self.isEnabled = True
-        self.inBlock   = list() # list of related loops/conditions
-        
-    def __del__(self):
-        pass
-    
-    def GetId(self):
-        """!Get id"""
-        return self.id
-    
-    def AddRelation(self, rel):
-        """!Record new relation
-        """
-        self.rels.append(rel)
-
-    def GetRelations(self, fdir = None):
-        """!Get list of relations
-        
-        @param fdir True for 'from'
-        """
-        if fdir is None:
-            return self.rels
-        
-        result = list()
-        for rel in self.rels:
-            if fdir == 'from':
-                if rel.GetFrom() == self:
-                    result.append(rel)
-            else:
-                if rel.GetTo() == self:
-                    result.append(rel)
-        
-        return result
-    
-    def IsEnabled(self):
-        """!Get True if action is enabled, otherwise False"""
-        return self.isEnabled
-    
-    def Enable(self, enabled = True):
-        """!Enable/disable action"""
-        self.isEnabled = enabled
-        self.Update()
-
-    def Update(self):
-        pass
-
-    def SetBlock(self, item):
-        """!Add object to the block (loop/condition)
-
-        @param item reference to ModelLoop or ModelCondition which
-        defines loops/condition
-        """
-        if item not in self.inBlock:
-            self.inBlock.append(item)
-        
-    def UnSetBlock(self, item):
-        """!Remove object from the block (loop/consition)
-
-        @param item reference to ModelLoop or ModelCondition which
-        defines loops/codition
-        """
-        if item in self.inBlock:
-            self.inBlock.remove(item)
-        
-    def GetBlock(self):
-        """!Get list of related ModelObject(s) which defines block
-        (loop/condition)
-
-        @return list of ModelObjects
-        """
-        return self.inBlock
-    
-    def GetBlockId(self):
-        """!Get list of related ids which defines block
-
-        @return list of ids
-        """
-        ret = list()
-        for mo in self.inBlock:
-            ret.append(mo.GetId())
-        
-        return ret
-    
-class ModelAction(ModelObject, ogl.RectangleShape):
-    """!Action class (GRASS module)"""
-    def __init__(self, parent, x, y, id = -1, cmd = None, task = None, width = None, height = None):
-        ModelObject.__init__(self, id)
-        
-        self.parent  = parent
-        self.task    = task
-        
-        if not width:
-            width = UserSettings.Get(group='modeler', key='action', subkey=('size', 'width'))
-        if not height:
-            height = UserSettings.Get(group='modeler', key='action', subkey=('size', 'height'))
-        
-        if cmd:
-            self.task = menuform.GUI(show = None).ParseCommand(cmd = cmd)
-        else:
-            if task:
-                self.task = task
-            else:
-                self.task = None
-        
-        self.propWin = None
-        
-        self.data = list()   # list of connected data items
-        
-        self.isValid = False
-        self.isParameterized = False
-        
-        if self.parent.GetCanvas():
-            ogl.RectangleShape.__init__(self, width, height)
-            
-            self.SetCanvas(self.parent)
-            self.SetX(x)
-            self.SetY(y)
-            self.SetPen(wx.BLACK_PEN)
-            self._setPen()
-            self._setBrush()
-            self.SetId(id)
-        
-        if self.task:
-            self.SetValid(self.task.get_options())
-        
-    def _setBrush(self, running = False):
-        """!Set brush"""
-        if running:
-            color = UserSettings.Get(group='modeler', key='action',
-                                     subkey=('color', 'running'))
-        elif not self.isEnabled:
-            color = UserSettings.Get(group='modeler', key='disabled',
-                                     subkey='color')
-        elif self.isValid:
-            color = UserSettings.Get(group='modeler', key='action',
-                                     subkey=('color', 'valid'))
-        else:
-            color = UserSettings.Get(group='modeler', key='action',
-                                     subkey=('color', 'invalid'))
-        
-        wxColor = wx.Color(color[0], color[1], color[2])
-        self.SetBrush(wx.Brush(wxColor))
-        
-    def _setPen(self):
-        """!Set pen"""
-        if self.isParameterized:
-            width = int(UserSettings.Get(group='modeler', key='action',
-                                         subkey=('width', 'parameterized')))
-        else:
-            width = int(UserSettings.Get(group='modeler', key='action',
-                                         subkey=('width', 'default')))
-        pen = self.GetPen()
-        pen.SetWidth(width)
-        self.SetPen(pen)
-
-    def SetId(self, id):
-        """!Set id"""
-        self.id = id
-        cmd = self.task.get_cmd(ignoreErrors = True)
-        if cmd and len(cmd) > 0:
-            self.ClearText()
-            self.AddText('(%d) %s' % (self.id, cmd[0]))
-        else:
-            self.AddText('(%d) <<%s>>' % (self.id, _("unknown")))
-        
-    def SetProperties(self, params, propwin):
-        """!Record properties dialog"""
-        self.task.params = params['params']
-        self.task.flags  = params['flags']
-        self.propWin = propwin
-
-    def GetPropDialog(self):
-        """!Get properties dialog"""
-        return self.propWin
-
-    def GetLog(self, string = True, substitute = None):
-        """!Get logging info
-
-        @param string True to get cmd as a string otherwise a list
-        @param substitute dictionary of parameter to substitute or None
-        """
-        cmd = self.task.get_cmd(ignoreErrors = True, ignoreRequired = True,
-                                ignoreDefault = False)
-        
-        # substitute variables
-        if substitute:
-            variables = []
-            if 'variables' in substitute:
-                for p in substitute['variables']['params']:
-                    variables.append(p.get('name', ''))
-            else:
-                variables = self.parent.GetVariables()
-            for variable in variables:
-                pattern= re.compile('%' + variable)
-                value = ''
-                if substitute and 'variables' in substitute:
-                    for p in substitute['variables']['params']:
-                        if variable == p.get('name', ''):
-                            if p.get('type', 'string') == 'string':
-                                value = p.get('value', '')
-                            else:
-                                value = str(p.get('value', ''))
-                            break
-                    
-                if not value:
-                    value = variables[variable].get('value', '')
-                
-                if not value:
-                    continue
-                
-                for idx in range(len(cmd)):
-                    if pattern.search(cmd[idx]):
-                        cmd[idx] = pattern.sub(value, cmd[idx])
-                        break
-                    idx += 1
-        
-        if string:
-            if cmd is None:
-                return ''
-            else:
-                return ' '.join(cmd)
-        
-        return cmd
-    
-    def GetName(self):
-        """!Get name"""
-        cmd = self.task.get_cmd(ignoreErrors = True)
-        if cmd and len(cmd) > 0:
-            return cmd[0]
-        
-        return _('unknown')
-
-    def GetParams(self, dcopy = False):
-        """!Get dictionary of parameters"""
-        if dcopy:
-            return copy.deepcopy(self.task.get_options())
-        
-        return self.task.get_options()
-
-    def GetTask(self):
-        """!Get grassTask instance"""
-        return self.task
-    
-    def SetParams(self, params):
-        """!Set dictionary of parameters"""
-        self.task.params = params['params']
-        self.task.flags  = params['flags']
-        
-    def MergeParams(self, params):
-        """!Merge dictionary of parameters"""
-        if 'flags' in params:
-            for f in params['flags']:
-                self.task.set_flag(f['name'],
-                                   f.get('value', False))
-        if 'params' in params:
-            for p in params['params']:
-                self.task.set_param(p['name'],
-                                    p.get('value', ''))
-        
-    def SetValid(self, options):
-        """!Set validity for action
-        
-        @param options dictionary with flags and params (gtask)
-        """
-        self.isValid = True
-        self.isParameterized = False
-        
-        for f in options['flags']:
-            if f.get('parameterized', False):
-                self.IsParameterized = True
-                break
-        
-        for p in options['params']:
-            if self.isValid and p.get('required', False) and \
-                    p.get('value', '') == '' and \
-                    p.get('default', '') == '':
-                self.isValid = False
-            if not self.isParameterized and p.get('parameterized', False):
-                self.isParameterized = True
-        
-        if self.parent.GetCanvas():
-            self._setBrush()
-            self._setPen()
-        
-    def IsValid(self):
-        """!Check validity (all required parameters set)"""
-        return self.isValid
-    
-    def IsParameterized(self):
-        """!Check if action is parameterized"""
-        return self.isParameterized
-    
-    def FindData(self, name):
-        """!Find data item by name"""
-        for rel in self.GetRelations():
-            data = rel.GetData()
-            if name == rel.GetName() and name in data.GetName():
-                return data
-        
-        return None
-
-    def Update(self, running = False):
-        """!Update action"""
-        if running:
-            self._setBrush(running = True)
-        else:
-            self._setBrush()
-        self._setPen()
-
-    def OnDraw(self, dc):
-        """!Draw action in canvas"""
-        self._setBrush()
-        self._setPen()
-        ogl.RectangleShape.OnDraw(self, dc)
-
-class ModelData(ModelObject, ogl.EllipseShape):
-    def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
-        """Data item class
-        
-        @param parent window parent
-        @param x, y   position of the shape
-        @param fname, tname list of parameter names from / to
-        @param value  value
-        @param prompt type of GIS element
-        @param width,height dimension of the shape
-        """
-        ModelObject.__init__(self)
-        
-        self.parent  = parent
-        self.value   = value
-        self.prompt  = prompt
-        self.intermediate = False
-        self.propWin = None
-        if not width:
-            width = UserSettings.Get(group='modeler', key='data', subkey=('size', 'width'))
-        if not height:
-            height = UserSettings.Get(group='modeler', key='data', subkey=('size', 'height'))
-        
-        if self.parent.GetCanvas():
-            ogl.EllipseShape.__init__(self, width, height)
-            
-            self.SetCanvas(self.parent)
-            self.SetX(x)
-            self.SetY(y)
-            self.SetPen(wx.BLACK_PEN)
-            self._setBrush()
-            
-            self._setText()
-            
-    def IsIntermediate(self):
-        """!Checks if data item is intermediate"""
-        return self.intermediate
-    
-    def SetIntermediate(self, im):
-        """!Set intermediate flag"""
-        self.intermediate = im
-  
-    def OnDraw(self, dc):
-        pen = self.GetPen()
-        pen.SetWidth(1)
-        if self.intermediate:
-            pen.SetStyle(wx.SHORT_DASH)
-        else:
-            pen.SetStyle(wx.SOLID)
-        self.SetPen(pen)
-        
-        ogl.EllipseShape.OnDraw(self, dc)
-        
-    def GetLog(self, string = True):
-        """!Get logging info"""
-        name = list()
-        for rel in self.GetRelations():
-            name.append(rel.GetName())
-        if name:
-            return '/'.join(name) + '=' + self.value + ' (' + self.prompt + ')'
-        else:
-            return self.value + ' (' + self.prompt + ')'
-
-    def GetName(self):
-        """!Get list of names"""
-        name = list()
-        for rel in self.GetRelations():
-            name.append(rel.GetName())
-        
-        return name
-    
-    def GetPrompt(self):
-        """!Get prompt"""
-        return self.prompt
-
-    def SetPrompt(self, prompt):
-        """!Set prompt
-        
-        @param prompt
-        """
-        self.prompt = prompt
-        
-    def GetValue(self):
-        """!Get value"""
-        return self.value
-
-    def SetValue(self, value):
-        """!Set value
-
-        @param value
-        """
-        self.value = value
-        self._setText()
-        for direction in ('from', 'to'):
-            for rel in self.GetRelations(direction):
-                if direction == 'from':
-                    action = rel.GetTo()
-                else:
-                    action = rel.GetFrom()
-                
-                task = menuform.GUI(show = None).ParseCommand(cmd = action.GetLog(string = False))
-                task.set_param(rel.GetName(), self.value)
-                action.SetParams(params = task.get_options())
-        
-    def GetPropDialog(self):
-        """!Get properties dialog"""
-        return self.propWin
-
-    def SetPropDialog(self, win):
-        """!Get properties dialog"""
-        self.propWin = win
-
-    def _setBrush(self):
-        """!Set brush"""
-        if self.prompt == 'raster':
-            color = UserSettings.Get(group = 'modeler', key = 'data',
-                                     subkey = ('color', 'raster'))
-        elif self.prompt == 'raster3d':
-            color = UserSettings.Get(group = 'modeler', key = 'data',
-                                     subkey = ('color', 'raster3d'))
-        elif self.prompt == 'vector':
-            color = UserSettings.Get(group = 'modeler', key = 'data',
-                                     subkey = ('color', 'vector'))
-        else:
-            color = UserSettings.Get(group = 'modeler', key = 'action',
-                                     subkey = ('color', 'invalid'))
-        wxColor = wx.Color(color[0], color[1], color[2])
-        self.SetBrush(wx.Brush(wxColor))
-        
-    def _setPen(self):
-        """!Set pen"""
-        isParameterized = False
-        for rel in self.GetRelations('from'):
-            if rel.GetTo().IsParameterized():
-                isParameterized = True
-                break
-        if not isParameterized:
-            for rel in self.GetRelations('to'):
-                if rel.GetFrom().IsParameterized():
-                    isParameterized = True
-                    break
-
-        if isParameterized:
-            width = int(UserSettings.Get(group = 'modeler', key = 'action',
-                                         subkey = ('width', 'parameterized')))
-        else:
-            width = int(UserSettings.Get(group = 'modeler', key = 'action',
-                                         subkey = ('width', 'default')))
-        pen = self.GetPen()
-        pen.SetWidth(width)
-        self.SetPen(pen)
-        
-    def _setText(self):
-        """!Update text"""
-        self.ClearText()
-        name = []
-        for rel in self.GetRelations():
-            name.append(rel.GetName())
-        self.AddText('/'.join(name))
-        if self.value:
-            self.AddText(self.value)
-        else:
-            self.AddText(_('<not defined>'))
-        
-    def Update(self):
-        """!Update action"""
-        self._setBrush()
-        self._setPen()
-        self._setText()
-        
-class ModelDataDialog(ElementDialog):
-    """!Data item properties dialog"""
-    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Data properties"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        self.parent = parent
-        self.shape = shape
-        
-        label, etype = self._getLabel()
-        ElementDialog.__init__(self, parent, title, label = label, etype = etype)
-                
-        self.element = gselect.Select(parent = self.panel,
-                                      type = prompt)
-        self.element.SetValue(shape.GetValue())
-        
-        self.Bind(wx.EVT_BUTTON, self.OnOK,     self.btnOK)
-        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
-        
-        self.PostInit()
-        
-        if shape.GetValue():
-            self.btnOK.Enable()
-        
-        self._layout()
-        self.SetMinSize(self.GetSize())
-        
-    def _getLabel(self):
-        etype = False
-        prompt = self.shape.GetPrompt()
-        if prompt == 'raster':
-            label = _('Name of raster map:')
-        elif prompt == 'vector':
-            label = _('Name of vector map:')
-        else:
-            etype = True
-            label = _('Name of element:')
-
-        return label, etype
-    
-    def _layout(self):
-        """!Do layout"""
-        self.dataSizer.Add(self.element, proportion=0,
-                      flag=wx.EXPAND | wx.ALL, border=1)
-        
-        self.panel.SetSizer(self.sizer)
-        self.sizer.Fit(self)
-
-    def OnOK(self, event):
-        """!Ok pressed"""
-        self.shape.SetValue(self.GetElement())
-        if self.etype:
-            elem = self.GetType()
-            if elem == 'rast':
-                self.shape.SetPrompt('raster')
-            elif elem == 'vect':
-                self.shape.SetPrompt('raster')
-        
-        self.parent.canvas.Refresh()
-        self.parent.SetStatusText('', 0)
-        self.shape.SetPropDialog(None)
-        
-        if self.IsModal():
-            event.Skip() 
-        else:
-            self.Destroy()
-    
-    def OnCancel(self, event):
-        """!Cancel pressed"""
-        self.shape.SetPropDialog(None)
-        if self.IsModal():
-            event.Skip()
-        else:
-            self.Destroy()
-        
-class ModelEvtHandler(ogl.ShapeEvtHandler):
-    """!Model event handler class"""
-    def __init__(self, log, frame):
-        ogl.ShapeEvtHandler.__init__(self)
-        self.log = log
-        self.frame = frame
-        self.x = self.y = None
-        
-    def OnLeftClick(self, x, y, keys = 0, attachment = 0):
-        """!Left mouse button pressed -> select item & update statusbar"""
-        shape = self.GetShape()
-        canvas = shape.GetCanvas()
-        dc = wx.ClientDC(canvas)
-        canvas.PrepareDC(dc)
-        
-        if hasattr(self.frame, 'defineRelation'):
-            drel = self.frame.defineRelation
-            if drel['from'] is None:
-                drel['from'] = shape
-            elif drel['to'] is None:
-                drel['to'] = shape
-                rel = ModelRelation(parent = self.frame, fromShape = drel['from'],
-                                    toShape = drel['to'])
-                dlg = ModelRelationDialog(parent = self.frame,
-                                          shape = rel)
-                if dlg.IsValid():
-                    ret = dlg.ShowModal()
-                    if ret == wx.ID_OK:
-                        option = dlg.GetOption()
-                        rel.SetName(option)
-                        drel['from'].AddRelation(rel)
-                        drel['to'].AddRelation(rel)
-                        drel['from'].Update()
-                        params = { 'params' : [{ 'name' : option,
-                                                 'value' : drel['from'].GetValue()}] }
-                        drel['to'].MergeParams(params)
-                        self.frame.AddLine(rel)
-                
-                    dlg.Destroy()
-                del self.frame.defineRelation
-        
-        if shape.Selected():
-            shape.Select(False, dc)
-        else:
-            redraw = False
-            shapeList = canvas.GetDiagram().GetShapeList()
-            toUnselect = list()
-            
-            for s in shapeList:
-                if s.Selected():
-                    toUnselect.append(s)
-            
-            shape.Select(True, dc)
-            
-            for s in toUnselect:
-                s.Select(False, dc)
-                
-        canvas.Refresh(False)
-
-        if hasattr(shape, "GetLog"):
-            self.log.SetStatusText(shape.GetLog(), 0)
-        else:
-            self.log.SetStatusText('', 0)
-        
-    def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
-        """!Left mouse button pressed (double-click) -> show properties"""
-        self.OnProperties()
-        
-    def OnProperties(self, event = None):
-        """!Show properties dialog"""
-        self.frame.ModelChanged()
-        shape = self.GetShape()
-        if isinstance(shape, ModelAction):
-            module = menuform.GUI(parent = self.frame, show = True).ParseCommand(shape.GetLog(string = False),
-                                                                                 completed = (self.frame.GetOptData, shape, shape.GetParams()))
-        
-        elif isinstance(shape, ModelData):
-            dlg = ModelDataDialog(parent = self.frame, shape = shape)
-            shape.SetPropDialog(dlg)
-            dlg.CentreOnParent()
-            dlg.Show()
-        
-        elif isinstance(shape, ModelLoop):
-            dlg = ModelLoopDialog(parent = self.frame, shape = shape)
-            dlg.CentreOnParent()
-            if dlg.ShowModal() == wx.ID_OK:
-                shape.SetText(dlg.GetCondition())
-                alist = list()
-                ids = dlg.GetItems()
-                for aId in ids['unchecked']:
-                    action = self.frame.GetModel().GetItem(aId)
-                    action.UnSetBlock(shape)
-                for aId in ids['checked']:
-                    action = self.frame.GetModel().GetItem(aId)
-                    action.SetBlock(shape)
-                    if action:
-                        alist.append(action)
-                shape.SetItems(alist)
-                self.frame.DefineLoop(shape)
-                self.frame.SetStatusText(shape.GetLog(), 0)
-            self.frame.GetCanvas().Refresh()
-            
-            dlg.Destroy()
-        
-        elif isinstance(shape, ModelCondition):
-            dlg = ModelConditionDialog(parent = self.frame, shape = shape)
-            dlg.CentreOnParent()
-            if dlg.ShowModal() == wx.ID_OK:
-                shape.SetText(dlg.GetCondition())
-                ids = dlg.GetItems()
-                for b in ids.keys():
-                    alist = list()
-                    for aId in ids[b]['unchecked']:
-                        action = self.frame.GetModel().GetItem(aId)
-                        action.UnSetBlock(shape)
-                    for aId in ids[b]['checked']:
-                        action = self.frame.GetModel().GetItem(aId)
-                        action.SetBlock(shape)
-                        if action:
-                            alist.append(action)
-                    shape.SetItems(alist, branch = b)
-                self.frame.DefineCondition(shape)
-            self.frame.GetCanvas().Refresh()
-            
-            dlg.Destroy()
-                   
-    def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
-        """!Drag shape (begining)"""
-        self.frame.ModelChanged()
-        if self._previousHandler:
-            self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
-        
-    def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
-        """!Drag shape (end)"""
-        if self._previousHandler:
-            self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
-        
-        shape = self.GetShape()
-        if isinstance(shape, ModelLoop):
-            self.frame.DefineLoop(shape)
-        elif isinstance(shape, ModelCondition):
-            self.frame.DefineCondition(shape)
-        
-        for mo in shape.GetBlock():
-            if isinstance(mo, ModelLoop):
-                self.frame.DefineLoop(mo)
-            elif isinstance(mo, ModelCondition):
-                self.frame.DefineCondition(mo)
-        
-    def OnEndSize(self, x, y):
-        """!Resize shape"""
-        self.frame.ModelChanged()
-        if self._previousHandler:
-            self._previousHandler.OnEndSize(x, y)
-        
-    def OnRightClick(self, x, y, keys = 0, attachment = 0):
-        """!Right click -> pop-up menu"""
-        if not hasattr (self, "popupID"):
-            self.popupID = dict()
-            for key in ('remove', 'enable', 'addPoint',
-                        'delPoint', 'intermediate', 'props', 'id'):
-                self.popupID[key] = wx.NewId()
-        
-        # record coordinates
-        self.x = x
-        self.y = y
-        
-        shape = self.GetShape()
-        popupMenu = wx.Menu()
-        popupMenu.Append(self.popupID['remove'], text=_('Remove'))
-        self.frame.Bind(wx.EVT_MENU, self.OnRemove, id = self.popupID['remove'])
-        if isinstance(shape, ModelAction) or isinstance(shape, ModelLoop):
-            if shape.IsEnabled():
-                popupMenu.Append(self.popupID['enable'], text=_('Disable'))
-                self.frame.Bind(wx.EVT_MENU, self.OnDisable, id = self.popupID['enable'])
-            else:
-                popupMenu.Append(self.popupID['enable'], text=_('Enable'))
-                self.frame.Bind(wx.EVT_MENU, self.OnEnable, id = self.popupID['enable'])
-        
-        if isinstance(shape, ModelRelation):
-            popupMenu.AppendSeparator()
-            popupMenu.Append(self.popupID['addPoint'], text=_('Add control point'))
-            self.frame.Bind(wx.EVT_MENU, self.OnAddPoint, id = self.popupID['addPoint'])
-            popupMenu.Append(self.popupID['delPoint'], text=_('Remove control point'))
-            self.frame.Bind(wx.EVT_MENU, self.OnRemovePoint, id = self.popupID['delPoint'])
-            if len(shape.GetLineControlPoints()) == 2:
-                popupMenu.Enable(self.popupID['delPoint'], False)
-        
-        if isinstance(shape, ModelData) and '@' not in shape.GetValue():
-            popupMenu.AppendSeparator()
-            popupMenu.Append(self.popupID['intermediate'], text=_('Intermediate'),
-                             kind = wx.ITEM_CHECK)
-            if self.GetShape().IsIntermediate():
-                popupMenu.Check(self.popupID['intermediate'], True)
-            
-            self.frame.Bind(wx.EVT_MENU, self.OnIntermediate, id = self.popupID['intermediate'])
-            
-        if isinstance(shape, ModelData) or \
-                isinstance(shape, ModelAction) or \
-                isinstance(shape, ModelLoop):
-            popupMenu.AppendSeparator()
-            popupMenu.Append(self.popupID['props'], text=_('Properties'))
-            self.frame.Bind(wx.EVT_MENU, self.OnProperties, id = self.popupID['props'])
-        
-        self.frame.PopupMenu(popupMenu)
-        popupMenu.Destroy()
-
-    def OnDisable(self, event):
-        """!Disable action"""
-        self._onEnable(False)
-        
-    def OnEnable(self, event):
-        """!Disable action"""
-        self._onEnable(True)
-        
-    def _onEnable(self, enable):
-        shape = self.GetShape()
-        shape.Enable(enable)
-        self.frame.ModelChanged()
-        self.frame.canvas.Refresh()
-        
-    def OnAddPoint(self, event):
-        """!Add control point"""
-        shape = self.GetShape()
-        shape.InsertLineControlPoint(point = wx.RealPoint(self.x, self.y))
-        shape.ResetShapes()
-        shape.Select(True)
-        self.frame.ModelChanged()
-        self.frame.canvas.Refresh()
-        
-    def OnRemovePoint(self, event):
-        """!Remove control point"""
-        shape = self.GetShape()
-        shape.DeleteLineControlPoint()
-        shape.Select(False)
-        shape.Select(True)
-        self.frame.ModelChanged()
-        self.frame.canvas.Refresh()
-        
-    def OnIntermediate(self, event):
-        """!Mark data as intermediate"""
-        self.frame.ModelChanged()
-        shape = self.GetShape()
-        shape.SetIntermediate(event.IsChecked())
-        self.frame.canvas.Refresh()
-
-    def OnRemove(self, event):
-        """!Remove shape
-        """
-        self.frame.GetCanvas().RemoveSelected()
-        self.frame.itemPanel.Update()
-        
-class ModelSearchDialog(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, title = _("Add new GRASS module to the model"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        """!Graphical modeler module search window
-        
-        @param parent parent window
-        @param id window id
-        @param title window title
-        @param kwargs wx.Dialogs' arguments
-        """
-        self.parent = parent
-        
-        wx.Dialog.__init__(self, parent = parent, id = id, title = title, **kwargs)
-        self.SetName("ModelerDialog")
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.cmdBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                   label=" %s " % _("Command"))
-        
-        self.cmd_prompt = prompt.GPromptSTC(parent = self)
-        self.search = SearchModuleWindow(parent = self.panel, cmdPrompt = self.cmd_prompt, showTip = True)
-        wx.CallAfter(self.cmd_prompt.SetFocus)
-        
-        # get commands
-        items = self.cmd_prompt.GetCommandItems()
-        
-        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
-        self.btnOk     = wx.Button(self.panel, wx.ID_OK)
-        self.btnOk.SetDefault()
-        self.btnOk.Enable(False)
-
-        self.cmd_prompt.Bind(wx.EVT_KEY_UP, self.OnText)
-        self.search.searchChoice.Bind(wx.EVT_CHOICE, self.OnText)
-        self.Bind(wx.EVT_BUTTON, self.OnOk, self.btnOk)
-        
-        self._layout()
-        
-        self.SetSize((500, 275))
-        
-    def _layout(self):
-        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
-        cmdSizer.Add(item = self.cmd_prompt, proportion = 1,
-                     flag = wx.EXPAND)
-        
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnOk)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.search, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 3)
-        mainSizer.Add(item = cmdSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.panel.SetSizer(mainSizer)
-        mainSizer.Fit(self.panel)
-        
-        self.Layout()
-
-    def GetPanel(self):
-        """!Get dialog panel"""
-        return self.panel
-
-    def GetCmd(self):
-        """!Get command"""
-        line = self.cmd_prompt.GetCurLine()[0].strip()
-        if len(line) == 0:
-            list()
-        
-        try:
-            cmd = utils.split(str(line))
-        except UnicodeError:
-            cmd = utils.split(utils.EncodeString((line)))
-            
-        return cmd
-    
-    def OnOk(self, event):
-        """!Button 'OK' pressed"""
-        self.btnOk.SetFocus()
-        cmd = self.GetCmd()
-        
-        if len(cmd) < 1:
-            GError(parent = self,
-                   message = _("Command not defined.\n\n"
-                               "Unable to add new action to the model."))
-            return
-        
-        if cmd[0] not in globalvar.grassCmd['all']:
-            GError(parent = self,
-                   message = _("'%s' is not a GRASS module.\n\n"
-                               "Unable to add new action to the model.") % cmd[0])
-            return
-        
-        self.EndModal(wx.ID_OK)
-        
-    def OnText(self, event):
-        """!Text in prompt changed"""
-        if self.cmd_prompt.AutoCompActive():
-            event.Skip()
-            return
-        
-        if isinstance(event, wx.KeyEvent):
-            entry = self.cmd_prompt.GetTextLeft()
-        elif isinstance(event, wx.stc.StyledTextEvent):
-            entry = event.GetText()
-        else:
-            entry = event.GetString()
-        
-        if entry:
-            self.btnOk.Enable()
-        else:
-            self.btnOk.Enable(False)
-            
-        event.Skip()
-        
-    def Reset(self):
-        """!Reset dialog"""
-        self.search.Reset()
-        self.cmd_prompt.OnCmdErase(None)
-        self.btnOk.Enable(False)
-        self.cmd_prompt.SetFocus()
-
-class ModelRelation(ogl.LineShape):
-    """!Data - action relation"""
-    def __init__(self, parent, fromShape, toShape, param = ''):
-        self.fromShape = fromShape
-        self.toShape   = toShape
-        self.param     = param
-        self.parent    = parent
-        
-        self._points    = None
-        
-        if self.parent.GetCanvas():        
-            ogl.LineShape.__init__(self)
-    
-    def __del__(self):
-        if self in self.fromShape.rels:
-            self.fromShape.rels.remove(self)
-        if self in self.toShape.rels:
-            self.toShape.rels.remove(self)
-        
-    def GetFrom(self):
-        """!Get id of 'from' shape"""
-        return self.fromShape
-    
-    def GetTo(self):
-        """!Get id of 'to' shape"""
-        return self.toShape
-    
-    def GetData(self):
-        """!Get related ModelData instance
-
-        @return ModelData instance
-        @return None if not found
-        """
-        if isinstance(self.fromShape, ModelData):
-            return self.fromShape
-        elif isinstance(self.toShape, ModelData):
-            return self.toShape
-        
-        return None
-    
-    def GetName(self):
-        """!Get parameter name"""
-        return self.param
-    
-    def ResetShapes(self):
-        """!Reset related objects"""
-        self.fromShape.ResetControlPoints()
-        self.toShape.ResetControlPoints()
-        self.ResetControlPoints()
-        
-    def SetControlPoints(self, points):
-        """!Set control points"""
-        self._points = points
-        
-    def GetControlPoints(self):
-        """!Get list of control points"""
-        return self._points
-    
-    def _setPen(self):
-        """!Set pen"""
-        pen = self.GetPen()
-        pen.SetWidth(1)
-        pen.SetStyle(wx.SOLID)
-        self.SetPen(pen)
-        
-    def OnDraw(self, dc):
-        """!Draw relation"""
-        self._setPen()
-        ogl.LineShape.OnDraw(self, dc)
-    
-    def SetName(self, param):
-        self.param = param
-        
-class ModelRelationDialog(wx.Dialog):
-    """!Relation properties dialog"""
-    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Relation properties"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        self.parent = parent
-        self.shape = shape
-        
-        options = self._getOptions()
-        if not options:
-            self.valid = False
-            return
-        
-        self.valid = True
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.fromBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("From"))
-        self.toBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                  label = " %s " % _("To"))
-        
-        self.option = wx.ComboBox(parent = self.panel, id = wx.ID_ANY,
-                                  style = wx.CB_READONLY,
-                                  choices = options)
-        self.option.Bind(wx.EVT_COMBOBOX, self.OnOption)
-        
-        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
-        self.btnOk     = wx.Button(self.panel, wx.ID_OK)
-        self.btnOk.Enable(False)
-        
-        self._layout()
-
-    def _layout(self):
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-
-        fromSizer = wx.StaticBoxSizer(self.fromBox, wx.VERTICAL)
-        self._layoutShape(shape = self.shape.GetFrom(), sizer = fromSizer)
-        toSizer = wx.StaticBoxSizer(self.toBox, wx.VERTICAL)
-        self._layoutShape(shape = self.shape.GetTo(), sizer = toSizer)
-
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnOk)
-        btnSizer.Realize()
-        
-        mainSizer.Add(item = fromSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = toSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.panel.SetSizer(mainSizer)
-        mainSizer.Fit(self.panel)
-        
-        self.Layout()
-        self.SetSize(self.GetBestSize())
-        
-    def _layoutShape(self, shape, sizer):
-        if isinstance(shape, ModelData):
-            sizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                           label = _("Data: %s") % shape.GetLog()),
-                      proportion = 1, flag = wx.EXPAND | wx.ALL,
-                      border = 5)
-        elif isinstance(shape, ModelAction):
-            gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                               label = _("Command:")),
-                          pos = (0, 0))
-            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                               label = shape.GetName()),
-                          pos = (0, 1))
-            gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                               label = _("Option:")),
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (1, 0))
-            gridSizer.Add(item = self.option,
-                          pos = (1, 1))
-            sizer.Add(item = gridSizer,
-                      proportion = 1, flag = wx.EXPAND | wx.ALL,
-                      border = 5)
-            
-    def _getOptions(self):
-        """!Get relevant options"""
-        items = []
-        fromShape = self.shape.GetFrom()
-        if not isinstance(fromShape, ModelData):
-            GError(parent = self.parent,
-                   message = _("Relation doesn't start with data item.\n"
-                               "Unable to add relation."))
-            return items
-        
-        toShape = self.shape.GetTo()
-        if not isinstance(toShape, ModelAction):
-            GError(parent = self.parent,
-                   message = _("Relation doesn't point to GRASS command.\n"
-                               "Unable to add relation."))
-            return items
-        
-        prompt = fromShape.GetPrompt()
-        task = toShape.GetTask()
-        for p in task.get_options()['params']:
-            if p.get('prompt', '') == prompt and \
-                    'name' in p:
-                items.append(p['name'])
-        
-        if not items:
-            GError(parent = self.parent,
-                   message = _("No relevant option found.\n"
-                               "Unable to add relation."))
-        return items
-    
-    def GetOption(self):
-        """!Get selected option"""
-        return self.option.GetStringSelection()
-    
-    def IsValid(self):
-        """!Check if relation is valid"""
-        return self.valid
-    
-    def OnOption(self, event):
-        """!Set option"""
-        if event.GetString():
-            self.btnOk.Enable()
-        else:
-            self.btnOk.Enable(False)
-        
-class ProcessModelFile:
-    """!Process GRASS model file (gxm)"""
-    def __init__(self, tree):
-        """!A ElementTree handler for the GXM XML file, as defined in
-        grass-gxm.dtd.
-        """
-        self.tree = tree
-        self.root = self.tree.getroot()
-        
-        # list of actions, data
-        self.properties = dict()
-        self.variables  = dict() 
-        self.actions = list()
-        self.data    = list()
-        self.loops   = list()
-        self.conditions = list()
-        
-        self._processWindow()
-        self._processProperties()
-        self._processVariables()
-        self._processItems()
-        self._processData()
-        
-    def _filterValue(self, value):
-        """!Filter value
-        
-        @param value
-        """
-        value = value.replace('&lt;', '<')
-        value = value.replace('&gt;', '>')
-        
-        return value
-        
-    def _getNodeText(self, node, tag, default = ''):
-        """!Get node text"""
-        p = node.find(tag)
-        if p is not None:
-            if p.text:
-                return utils.normalize_whitespace(p.text)
-            else:
-                return ''
-        
-        return default
-    
-    def _processWindow(self):
-        """!Process window properties"""
-        node = self.root.find('window')
-        if node is None:
-            self.pos = self.size = None
-            return
-        
-        self.pos, self.size = self._getDim(node)
-        
-    def _processProperties(self):
-        """!Process model properties"""
-        node = self.root.find('properties')
-        if node is None:
-            return
-        for key in ('name', 'description', 'author'):
-            self._processProperty(node, key)
-        
-        for f in node.findall('flag'):
-            name = f.get('name', '')
-            if name == 'overwrite':
-                self.properties['overwrite'] = True
-        
-    def _processProperty(self, pnode, name):
-        """!Process given property"""
-        node = pnode.find(name)
-        if node is not None:
-            self.properties[name] = node.text
-        else:
-            self.properties[name] = ''
-
-    def _processVariables(self):
-        """!Process model variables"""
-        vnode = self.root.find('variables')
-        if vnode is None:
-            return
-        for node in vnode.findall('variable'):
-            name = node.get('name', '')
-            if not name:
-                continue # should not happen
-            self.variables[name] = { 'type' : node.get('type', 'string') }
-            for key in ('description', 'value'):
-                self._processVariable(node, name, key)
-        
-    def _processVariable(self, pnode, name, key):
-        """!Process given variable"""
-        node = pnode.find(key)
-        if node is not None:
-            if node.text:
-                self.variables[name][key] = node.text
-
-    def _processItems(self):
-        """!Process model items (actions, loops, conditions)"""
-        self._processActions()
-        self._processLoops()
-        self._processConditions()
-        
-    def _processActions(self):
-        """!Process model file"""
-        for action in self.root.findall('action'):
-            pos, size = self._getDim(action)
-            disabled  = False
-            
-            task = action.find('task')
-            if task is not None:
-                if task.find('disabled') is not None:
-                    disabled = True
-                task = self._processTask(task)
-            else:
-                task = None
-            
-            aId = int(action.get('id', -1))
-            
-            self.actions.append({ 'pos'      : pos,
-                                  'size'     : size,
-                                  'task'     : task,
-                                  'id'       : aId,
-                                  'disabled' : disabled })
-            
-    def _getDim(self, node):
-        """!Get position and size of shape"""
-        pos = size = None
-        posAttr = node.get('pos', None)
-        if posAttr:
-            posVal = map(int, posAttr.split(','))
-            try:
-                pos = (posVal[0], posVal[1])
-            except:
-                pos = None
-        
-        sizeAttr = node.get('size', None)
-        if sizeAttr:
-            sizeVal = map(int, sizeAttr.split(','))
-            try:
-                size = (sizeVal[0], sizeVal[1])
-            except:
-                size = None
-        
-        return pos, size        
-    
-    def _processData(self):
-        """!Process model file"""
-        for data in self.root.findall('data'):
-            pos, size = self._getDim(data)
-            param = data.find('data-parameter')
-            prompt = value = None
-            if param is not None:
-                prompt = param.get('prompt', None)
-                value = self._filterValue(self._getNodeText(param, 'value'))
-            
-            if data.find('intermediate') is None:
-                intermediate = False
-            else:
-                intermediate = True
-            
-            rels = list()
-            for rel in data.findall('relation'):
-                defrel = { 'id'  : int(rel.get('id', -1)),
-                           'dir' : rel.get('dir', 'to'),
-                           'name' : rel.get('name', '') }
-                points = list()
-                for point in rel.findall('point'):
-                    x = self._filterValue(self._getNodeText(point, 'x'))
-                    y = self._filterValue(self._getNodeText(point, 'y'))
-                    points.append((float(x), float(y)))
-                defrel['points'] = points
-                rels.append(defrel)
-            
-            self.data.append({ 'pos' : pos,
-                               'size': size,
-                               'prompt' : prompt,
-                               'value' : value,
-                               'intermediate' : intermediate,
-                               'rels' : rels })
-        
-    def _processTask(self, node):
-        """!Process task
-
-        @return grassTask instance
-        @return None on error
-        """
-        cmd = list()
-        parameterized = list()
-        
-        name = node.get('name', None)
-        if not name:
-            return None
-        
-        cmd.append(name)
-        
-        # flags
-        for f in node.findall('flag'):
-            flag = f.get('name', '')
-            if f.get('parameterized', '0') == '1':
-                parameterized.append(('flag', flag))
-                if f.get('value', '1') == '0':
-                    continue
-            if len(flag) > 1:
-                cmd.append('--' + flag)
-            else:
-                cmd.append('-' + flag)
-        # parameters
-        for p in node.findall('parameter'):
-            name = p.get('name', '')
-            if p.find('parameterized') is not None:
-                parameterized.append(('param', name))
-            cmd.append('%s=%s' % (name,
-                                  self._filterValue(self._getNodeText(p, 'value'))))
-        
-        task, err = menuform.GUI(show = None, checkError = True).ParseCommand(cmd = cmd)
-        if err:
-            GWarning(os.linesep.join(err))
-        
-        for opt, name in parameterized:
-            if opt == 'flag':
-                task.set_flag(name, True, element = 'parameterized')
-            else:
-                task.set_param(name, True, element = 'parameterized')
-        
-        return task
-
-    def _processLoops(self):
-        """!Process model loops"""
-        for node in self.root.findall('loop'):
-            pos, size = self._getDim(node)
-            text = self._filterValue(self._getNodeText(node, 'condition')).strip()
-            aid = list()
-            for anode in node.findall('item'):
-                try:
-                    aid.append(int(anode.text))
-                except ValueError:
-                    pass
-            
-            self.loops.append({ 'pos'     : pos,
-                                'size'    : size,
-                                'text'    : text,
-                                'id'      : int(node.get('id', -1)),
-                                'items'   : aid })
-        
-    def _processConditions(self):
-        """!Process model conditions"""
-        for node in self.root.findall('if-else'):
-            pos, size = self._getDim(node)
-            text = self._filterValue(self._getNodeText(node, 'condition')).strip()
-            aid = { 'if'   : list(),
-                    'else' : list() }
-            for b in aid.keys():
-                bnode = node.find(b)
-                if bnode is None:
-                    continue
-                for anode in bnode.findall('item'):
-                    try:
-                        aid[b].append(int(anode.text))
-                    except ValueError:
-                        pass
-            
-            self.conditions.append({ 'pos'     : pos,
-                                     'size'    : size,
-                                     'text'    : text,
-                                     'id'      : int(node.get('id', -1)),
-                                     'items'   : aid })
-        
-class WriteModelFile:
-    """!Generic class for writing model file"""
-    def __init__(self, fd, model):
-        self.fd         = fd
-        self.model      = model
-        self.properties = model.GetProperties()
-        self.variables  = model.GetVariables()
-        self.items      = model.GetItems()
-        
-        self.indent = 0
-        
-        self._header()
-        
-        self._window()
-        self._properties()
-        self._variables()
-        self._items()
-        
-        dataList = list()
-        for action in model.GetItems(objType = ModelAction):
-            for rel in action.GetRelations():
-                dataItem = rel.GetData()
-                if dataItem not in dataList:
-                    dataList.append(dataItem)
-        self._data(dataList)
-        
-        self._footer()
-
-    def _filterValue(self, value):
-        """!Make value XML-valid"""
-        value = value.replace('<', '&lt;')
-        value = value.replace('>', '&gt;')
-        
-        return value
-        
-    def _header(self):
-        """!Write header"""
-        self.fd.write('<?xml version="1.0" encoding="UTF-8"?>\n')
-        self.fd.write('<!DOCTYPE gxm SYSTEM "grass-gxm.dtd">\n')
-        self.fd.write('%s<gxm>\n' % (' ' * self.indent))
-        self.indent += 4
-                
-    def _footer(self):
-        """!Write footer"""
-        self.indent -= 4
-        self.fd.write('%s</gxm>\n' % (' ' * self.indent))
-
-    def _window(self):
-        """!Write window properties"""
-        canvas = self.model.GetCanvas()
-        if canvas is None:
-            return
-        win  = canvas.parent
-        pos  = win.GetPosition()
-        size = win.GetSize()
-        self.fd.write('%s<window pos="%d,%d" size="%d,%d" />\n' % \
-                          (' ' * self.indent, pos[0], pos[1], size[0], size[1]))
-        
-    def _properties(self):
-        """!Write model properties"""
-        self.fd.write('%s<properties>\n' % (' ' * self.indent))
-        self.indent += 4
-        if self.properties['name']:
-            self.fd.write('%s<name>%s</name>\n' % (' ' * self.indent, self.properties['name']))
-        if self.properties['description']:
-            self.fd.write('%s<description>%s</description>\n' % (' ' * self.indent,
-                                                                 utils.EncodeString(self.properties['description'])))
-        if self.properties['author']:
-            self.fd.write('%s<author>%s</author>\n' % (' ' * self.indent,
-                                                       utils.EncodeString(self.properties['author'])))
-        
-        if 'overwrite' in self.properties and \
-                self.properties['overwrite']:
-            self.fd.write('%s<flag name="overwrite" />\n' % (' ' * self.indent))
-        self.indent -= 4
-        self.fd.write('%s</properties>\n' % (' ' * self.indent))
-
-    def _variables(self):
-        """!Write model variables"""
-        if not self.variables:
-            return
-        self.fd.write('%s<variables>\n' % (' ' * self.indent))
-        self.indent += 4
-        for name, values in self.variables.iteritems():
-            self.fd.write('%s<variable name="%s" type="%s">\n' % \
-                              (' ' * self.indent, name, values['type']))
-            self.indent += 4
-            if 'value' in values:
-                self.fd.write('%s<value>%s</value>\n' % \
-                                  (' ' * self.indent, values['value']))
-            if 'description' in values:
-                self.fd.write('%s<description>%s</description>\n' % \
-                                  (' ' * self.indent, values['description']))
-            self.indent -= 4
-            self.fd.write('%s</variable>\n' % (' ' * self.indent))
-        self.indent -= 4
-        self.fd.write('%s</variables>\n' % (' ' * self.indent))
-        
-    def _items(self):
-        """!Write actions/loops/conditions"""
-        for item in self.items:
-            if isinstance(item, ModelAction):
-                self._action(item)
-            elif isinstance(item, ModelLoop):
-                self._loop(item)
-            elif isinstance(item, ModelCondition):
-                self._condition(item)
-        
-    def _action(self, action):
-        """!Write actions"""
-        self.fd.write('%s<action id="%d" name="%s" pos="%d,%d" size="%d,%d">\n' % \
-                          (' ' * self.indent, action.GetId(), action.GetName(), action.GetX(), action.GetY(),
-                           action.GetWidth(), action.GetHeight()))
-        self.indent += 4
-        self.fd.write('%s<task name="%s">\n' % (' ' * self.indent, action.GetLog(string = False)[0]))
-        self.indent += 4
-        if not action.IsEnabled():
-            self.fd.write('%s<disabled />\n' % (' ' * self.indent))
-        for key, val in action.GetParams().iteritems():
-            if key == 'flags':
-                for f in val:
-                    if f.get('value', False) or f.get('parameterized', False):
-                        if f.get('parameterized', False):
-                            if f.get('value', False) == False:
-                                self.fd.write('%s<flag name="%s" value="0" parameterized="1" />\n' %
-                                              (' ' * self.indent, f.get('name', '')))
-                            else:
-                                self.fd.write('%s<flag name="%s" parameterized="1" />\n' %
-                                              (' ' * self.indent, f.get('name', '')))
-                        else:
-                            self.fd.write('%s<flag name="%s" />\n' %
-                                          (' ' * self.indent, f.get('name', '')))
-            else: # parameter
-                for p in val:
-                    if not p.get('value', '') and not p.get('parameterized', False):
-                        continue
-                    self.fd.write('%s<parameter name="%s">\n' %
-                                  (' ' * self.indent, p.get('name', '')))
-                    self.indent += 4
-                    if p.get('parameterized', False):
-                        self.fd.write('%s<parameterized />\n' % (' ' * self.indent))
-                    self.fd.write('%s<value>%s</value>\n' %
-                                  (' ' * self.indent, self._filterValue(p.get('value', ''))))
-                    self.indent -= 4
-                    self.fd.write('%s</parameter>\n' % (' ' * self.indent))
-        self.indent -= 4
-        self.fd.write('%s</task>\n' % (' ' * self.indent))
-        self.indent -= 4
-        self.fd.write('%s</action>\n' % (' ' * self.indent))
-                
-    def _data(self, dataList):
-        """!Write data"""
-        for data in dataList:
-            self.fd.write('%s<data pos="%d,%d" size="%d,%d">\n' % \
-                              (' ' * self.indent, data.GetX(), data.GetY(),
-                               data.GetWidth(), data.GetHeight()))
-            self.indent += 4
-            self.fd.write('%s<data-parameter prompt="%s">\n' % \
-                              (' ' * self.indent, data.GetPrompt()))
-            self.indent += 4
-            self.fd.write('%s<value>%s</value>\n' %
-                          (' ' * self.indent, self._filterValue(data.GetValue())))
-            self.indent -= 4
-            self.fd.write('%s</data-parameter>\n' % (' ' * self.indent))
-            
-            if data.IsIntermediate():
-                self.fd.write('%s<intermediate />\n' % (' ' * self.indent))
-
-            # relations
-            for ft in ('from', 'to'):
-                for rel in data.GetRelations(ft):
-                    if ft == 'from':
-                        aid = rel.GetTo().GetId()
-                    else:
-                        aid  = rel.GetFrom().GetId()
-                    self.fd.write('%s<relation dir="%s" id="%d" name="%s">\n' % \
-                                      (' ' * self.indent, ft, aid, rel.GetName()))
-                    self.indent += 4
-                    for point in rel.GetLineControlPoints()[1:-1]:
-                        self.fd.write('%s<point>\n' % (' ' * self.indent))
-                        self.indent += 4
-                        x, y = point.Get()
-                        self.fd.write('%s<x>%d</x>\n' % (' ' * self.indent, int(x)))
-                        self.fd.write('%s<y>%d</y>\n' % (' ' * self.indent, int(y)))
-                        self.indent -= 4
-                        self.fd.write('%s</point>\n' % (' ' * self.indent))
-                    self.indent -= 4
-                    self.fd.write('%s</relation>\n' % (' ' * self.indent))
-                
-            self.indent -= 4
-            self.fd.write('%s</data>\n' % (' ' * self.indent))
-
-    def _loop(self, loop):
-        """!Write loops"""
-        self.fd.write('%s<loop id="%d" pos="%d,%d" size="%d,%d">\n' % \
-                          (' ' * self.indent, loop.GetId(), loop.GetX(), loop.GetY(),
-                           loop.GetWidth(), loop.GetHeight()))
-        text = loop.GetText()
-        self.indent += 4
-        if text:
-            self.fd.write('%s<condition>%s</condition>\n' %
-                          (' ' * self.indent, self._filterValue(text)))
-        for item in loop.GetItems():
-            self.fd.write('%s<item>%d</item>\n' %
-                          (' ' * self.indent, item.GetId()))
-        self.indent -= 4
-        self.fd.write('%s</loop>\n' % (' ' * self.indent))
-
-    def _condition(self, condition):
-        """!Write conditions"""
-        bbox = condition.GetBoundingBoxMin()
-        self.fd.write('%s<if-else id="%d" pos="%d,%d" size="%d,%d">\n' % \
-                          (' ' * self.indent, condition.GetId(), condition.GetX(), condition.GetY(),
-                           bbox[0], bbox[1]))
-        text = condition.GetText()
-        self.indent += 4
-        if text:
-            self.fd.write('%s<condition>%s</condition>\n' %
-                          (' ' * self.indent, self._filterValue(text)))
-        items = condition.GetItems()
-        for b in items.keys():
-            if len(items[b]) < 1:
-                continue
-            self.fd.write('%s<%s>\n' % (' ' * self.indent, b))
-            self.indent += 4
-            for item in items[b]:
-                self.fd.write('%s<item>%d</item>\n' %
-                              (' ' * self.indent, item.GetId()))
-            self.indent -= 4
-            self.fd.write('%s</%s>\n' % (' ' * self.indent, b))
-        
-        self.indent -= 4
-        self.fd.write('%s</if-else>\n' % (' ' * self.indent))
-        
-class PreferencesDialog(PreferencesBaseDialog):
-    """!User preferences dialog"""
-    def __init__(self, parent, settings = UserSettings,
-                 title = _("Modeler settings")):
-        
-        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
-                                       settings = settings)
-        
-        # create notebook pages
-        self._createGeneralPage(self.notebook)
-        self._createActionPage(self.notebook)
-        self._createDataPage(self.notebook)
-        self._createLoopPage(self.notebook)
-        
-        self.SetMinSize(self.GetBestSize())
-        self.SetSize(self.size)
-
-    def _createGeneralPage(self, notebook):
-        """!Create notebook page for action settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("General"))
-        
-        # colors
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Item properties"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Disabled:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='disabled', subkey='color'),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        rColor.SetName('GetColour')
-        self.winId['modeler:disabled:color'] = rColor.GetId()
-        
-        gridSizer.Add(item = rColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createActionPage(self, notebook):
-        """!Create notebook page for action settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Action"))
-        
-        # colors
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Color"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Valid:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'valid')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        vColor.SetName('GetColour')
-        self.winId['modeler:action:color:valid'] = vColor.GetId()
-        
-        gridSizer.Add(item = vColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Invalid:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        iColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'invalid')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        iColor.SetName('GetColour')
-        self.winId['modeler:action:color:invalid'] = iColor.GetId()
-        
-        gridSizer.Add(item = iColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Running:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='action', subkey=('color', 'running')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        rColor.SetName('GetColour')
-        self.winId['modeler:action:color:running'] = rColor.GetId()
-        
-        gridSizer.Add(item = rColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        # size
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Shape size"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
-        gridSizer.AddGrowableCol(0)
-
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Width:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        
-        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                            min = 0, max = 500,
-                            initial = self.settings.Get(group='modeler', key='action', subkey=('size', 'width')))
-        width.SetName('GetValue')
-        self.winId['modeler:action:size:width'] = width.GetId()
-        
-        gridSizer.Add(item = width,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
-                                         label=_("Height:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos=(row, 0))
-        
-        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                             min = 0, max = 500,
-                             initial = self.settings.Get(group='modeler', key='action', subkey=('size', 'height')))
-        height.SetName('GetValue')
-        self.winId['modeler:action:size:height'] = height.GetId()
-        
-        gridSizer.Add(item = height,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
-        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
-                
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createDataPage(self, notebook):
-        """!Create notebook page for data settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Data"))
-        
-        # colors
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Type"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Raster:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        rColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'raster')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        rColor.SetName('GetColour')
-        self.winId['modeler:data:color:raster'] = rColor.GetId()
-        
-        gridSizer.Add(item = rColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("3D raster:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        r3Color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                    colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'raster3d')),
-                                    size = globalvar.DIALOG_COLOR_SIZE)
-        r3Color.SetName('GetColour')
-        self.winId['modeler:data:color:raster3d'] = r3Color.GetId()
-        
-        gridSizer.Add(item = r3Color,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Vector:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='data', subkey=('color', 'vector')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        vColor.SetName('GetColour')
-        self.winId['modeler:data:color:vector'] = vColor.GetId()
-        
-        gridSizer.Add(item = vColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-
-        # size
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Shape size"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Width:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        
-        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                            min = 0, max = 500,
-                            initial = self.settings.Get(group='modeler', key='data', subkey=('size', 'width')))
-        width.SetName('GetValue')
-        self.winId['modeler:data:size:width'] = width.GetId()
-        
-        gridSizer.Add(item = width,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
-                                         label=_("Height:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos=(row, 0))
-        
-        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                             min = 0, max = 500,
-                             initial = self.settings.Get(group='modeler', key='data', subkey=('size', 'height')))
-        height.SetName('GetValue')
-        self.winId['modeler:data:size:height'] = height.GetId()
-        
-        gridSizer.Add(item = height,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
-        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
-        
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createLoopPage(self, notebook):
-        """!Create notebook page for loop settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Loop"))
-        
-        # colors
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Color"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Valid:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        vColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                   colour = self.settings.Get(group='modeler', key='loop', subkey=('color', 'valid')),
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        vColor.SetName('GetColour')
-        self.winId['modeler:loop:color:valid'] = vColor.GetId()
-        
-        gridSizer.Add(item = vColor,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        # size
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Shape size"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
-        gridSizer.AddGrowableCol(0)
-
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Width:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        
-        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                            min = 0, max = 500,
-                            initial = self.settings.Get(group='modeler', key='loop', subkey=('size', 'width')))
-        width.SetName('GetValue')
-        self.winId['modeler:loop:size:width'] = width.GetId()
-        
-        gridSizer.Add(item = width,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent=panel, id=wx.ID_ANY,
-                                         label=_("Height:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos=(row, 0))
-        
-        height = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                             min = 0, max = 500,
-                             initial = self.settings.Get(group='modeler', key='loop', subkey=('size', 'height')))
-        height.SetName('GetValue')
-        self.winId['modeler:loop:size:height'] = height.GetId()
-        
-        gridSizer.Add(item = height,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
-        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
-                
-        panel.SetSizer(border)
-        
-        return panel
-
-    def OnApply(self, event):
-        """!Button 'Apply' pressed"""
-        PreferencesBaseDialog.OnApply(self, event)
-        
-        self.parent.GetModel().Update()
-        self.parent.GetCanvas().Refresh()
-
-    def OnSave(self, event):
-        """!Button 'Save' pressed"""
-        PreferencesBaseDialog.OnSave(self, event)
-        
-        self.parent.GetModel().Update()
-        self.parent.GetCanvas().Refresh()
-
-class PropertiesDialog(wx.Dialog):
-    """!Model properties dialog
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _('Model properties'),
-                 size = (350, 400),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        wx.Dialog.__init__(self, parent, id, title, size = size,
-                           style = style)
-        
-        self.metaBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                    label=" %s " % _("Metadata"))
-        self.cmdBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                   label=" %s " % _("Commands"))
-        
-        self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY,
-                                size = (300, 25))
-        self.desc = wx.TextCtrl(parent = self, id = wx.ID_ANY,
-                                style = wx.TE_MULTILINE,
-                                size = (300, 50))
-        self.author = wx.TextCtrl(parent = self, id = wx.ID_ANY,
-                                size = (300, 25))
-        
-        # commands
-        self.overwrite = wx.CheckBox(parent = self, id=wx.ID_ANY,
-                                     label=_("Allow output files to overwrite existing files"))
-        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
-        
-        # buttons
-        self.btnOk     = wx.Button(self, wx.ID_OK)
-        self.btnCancel = wx.Button(self, wx.ID_CANCEL)
-        self.btnOk.SetDefault()
-        
-        self.btnOk.SetToolTipString(_("Apply properties"))
-        self.btnOk.SetDefault()
-        self.btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-        
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-        
-        self._layout()
-
-    def _layout(self):
-        metaSizer = wx.StaticBoxSizer(self.metaBox, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        gridSizer.AddGrowableRow(1)
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                         label = _("Name:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 0))
-        gridSizer.Add(item = self.name,
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                      pos = (0, 1))
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                         label = _("Description:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (1, 0))
-        gridSizer.Add(item = self.desc,
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                      pos = (1, 1))
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                         label = _("Author(s):")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2, 0))
-        gridSizer.Add(item = self.author,
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                      pos = (2, 1))
-        metaSizer.Add(item = gridSizer)
-        
-        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
-        cmdSizer.Add(item = self.overwrite,
-                     flag = wx.EXPAND | wx.ALL, border = 3)
-        
-        btnStdSizer = wx.StdDialogButtonSizer()
-        btnStdSizer.AddButton(self.btnCancel)
-        btnStdSizer.AddButton(self.btnOk)
-        btnStdSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item=metaSizer, proportion=1,
-                      flag=wx.EXPAND | wx.ALL, border=5)
-        mainSizer.Add(item=cmdSizer, proportion=0,
-                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
-        mainSizer.Add(item=btnStdSizer, proportion=0,
-                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-    def OnCloseWindow(self, event):
-        self.Hide()
-        
-    def GetValues(self):
-        """!Get values"""
-        return { 'name'        : self.name.GetValue(),
-                 'description' : self.desc.GetValue(),
-                 'author'      : self.author.GetValue(),
-                 'overwrite'   : self.overwrite.IsChecked() }
-    
-    def Init(self, prop):
-        """!Initialize dialog"""
-        self.name.SetValue(prop['name'])
-        self.desc.SetValue(prop['description'])
-        self.author.SetValue(prop['author'])
-        if 'overwrite' in prop:
-            self.overwrite.SetValue(prop['overwrite'])
-
-class ModelParamDialog(wx.Dialog):
-    def __init__(self, parent, params, id = wx.ID_ANY, title = _("Model parameters"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        """!Model parameters dialog
-        """
-        self.parent = parent
-        self.params = params
-        self.tasks  = list() # list of tasks/pages
-        
-        wx.Dialog.__init__(self, parent = parent, id = id, title = title, style = style, **kwargs)
-        
-        self.notebook = menuform.GNotebook(parent = self, 
-                                           style = globalvar.FNPageDStyle)
-        
-        panel = self._createPages()
-        wx.CallAfter(self.notebook.SetSelection, 0)
-        
-        self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
-        self.btnRun    = wx.Button(parent = self, id = wx.ID_OK,
-                                   label = _("&Run"))
-        self.btnRun.SetDefault()
-        
-        self._layout()
-        
-        size = self.GetBestSize()
-        self.SetMinSize(size)
-        self.SetSize((size.width, size.height +
-                      panel.constrained_size[1] -
-                      panel.panelMinHeight))
-                
-    def _layout(self):
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnRun)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.notebook, proportion = 1,
-                      flag = wx.EXPAND)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        
-    def _createPages(self):
-        """!Create for each parameterized module its own page"""
-        nameOrdered = [''] * len(self.params.keys())
-        for name, params in self.params.iteritems():
-            nameOrdered[params['idx']] = name
-        for name in nameOrdered:
-            params = self.params[name]
-            panel = self._createPage(name, params)
-            if name == 'variables':
-                name = _('Variables')
-            self.notebook.AddPage(page = panel, text = name)
-        
-        return panel
-    
-    def _createPage(self, name, params):
-        """!Define notebook page"""
-        if name in globalvar.grassCmd['all']:
-            task = gtask.grassTask(name)
-        else:
-            task = gtask.grassTask()
-        task.flags  = params['flags']
-        task.params = params['params']
-        
-        panel = menuform.cmdPanel(parent = self, id = wx.ID_ANY, task = task)
-        self.tasks.append(task)
-        
-        return panel
-
-    def GetErrors(self):
-        """!Check for errors, get list of messages"""
-        errList = list()
-        for task in self.tasks:
-            errList += task.get_cmd_error()
-        
-        return errList
-    
-class ModelListCtrl(wx.ListCtrl,
-                    listmix.ListCtrlAutoWidthMixin,
-                    listmix.TextEditMixin,
-                    listmix.ColumnSorterMixin):
-    def __init__(self, parent, columns, id = wx.ID_ANY,
-                 style = wx.LC_REPORT | wx.BORDER_NONE |
-                 wx.LC_SORT_ASCENDING |wx.LC_HRULES |
-                 wx.LC_VRULES, **kwargs):
-        """!List of model variables"""
-        self.parent = parent
-        self.columns = columns
-        self.shape = None
-        try:
-            self.frame  = parent.parent
-        except AttributeError:
-            self.frame = None
-        
-        wx.ListCtrl.__init__(self, parent, id = id, style = style, **kwargs)
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        listmix.TextEditMixin.__init__(self)
-        listmix.ColumnSorterMixin.__init__(self, 4)
-        
-        i = 0
-        for col in columns:
-            self.InsertColumn(i, col)
-            self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
-            i += 1
-        
-        self.itemDataMap = {} # requested by sorter
-        self.itemCount   = 0
-        
-        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit)
-        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit)
-        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
-        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
-        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)            #wxGTK
-                
-    def OnBeginEdit(self, event):
-        """!Editing of item started"""
-        event.Allow()
-
-    def OnEndEdit(self, event):
-        """!Finish editing of item"""
-        pass
-    
-    def OnColClick(self, event):
-        """!Click on column header (order by)"""
-        event.Skip()
-
-class VariablePanel(wx.Panel):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 **kwargs):
-        """!Manage model variables panel
-        """
-        self.parent = parent
-        
-        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
-        
-        self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                    label=" %s " % _("List of variables - right-click to delete"))
-        
-        self.list = VariableListCtrl(parent = self,
-                                     columns = [_("Name"), _("Data type"),
-                                                _("Default value"), _("Description")])
-        
-        # add new category
-        self.addBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                   label = " %s " % _("Add new variable"))
-        self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        wx.CallAfter(self.name.SetFocus)
-        self.type = wx.Choice(parent = self, id = wx.ID_ANY,
-                              choices = [_("integer"),
-                                         _("float"),
-                                         _("string"),
-                                         _("raster"),
-                                         _("vector"),
-                                         _("mapset"),
-                                         _("file")])
-        self.type.SetSelection(2) # string
-        self.value = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        self.desc = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        
-        # buttons
-        self.btnAdd = wx.Button(parent = self, id = wx.ID_ADD)
-        self.btnAdd.SetToolTipString(_("Add new variable to the model"))
-        self.btnAdd.Enable(False)
-        
-        # bindings
-        self.name.Bind(wx.EVT_TEXT, self.OnText)
-        self.value.Bind(wx.EVT_TEXT, self.OnText)
-        self.desc.Bind(wx.EVT_TEXT, self.OnText)
-        self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAdd)
-        
-        self._layout()
-
-    def _layout(self):
-        """!Layout dialog"""
-        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
-        listSizer.Add(item = self.list, proportion = 1,
-                      flag = wx.EXPAND)
-        
-        addSizer = wx.StaticBoxSizer(self.addBox, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridSizer.AddGrowableCol(1)
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = "%s:" % _("Name")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 0))
-        gridSizer.Add(item = self.name,
-                      pos = (0, 1),
-                      flag = wx.EXPAND)
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = "%s:" % _("Data type")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 2))
-        gridSizer.Add(item = self.type,
-                      pos = (0, 3))
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = "%s:" % _("Default value")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (1, 0))
-        gridSizer.Add(item = self.value,
-                      pos = (1, 1), span = (1, 3),
-                      flag = wx.EXPAND)
-        gridSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = "%s:" % _("Description")),
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2, 0))
-        gridSizer.Add(item = self.desc,
-                      pos = (2, 1), span = (1, 3),
-                      flag = wx.EXPAND)
-        addSizer.Add(item = gridSizer,
-                     flag = wx.EXPAND)
-        addSizer.Add(item = self.btnAdd, proportion = 0,
-                     flag = wx.TOP | wx.ALIGN_RIGHT, border = 5)
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = listSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        mainSizer.Add(item = addSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALIGN_CENTER |
-                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        
-    def OnText(self, event):
-        """!Text entered"""
-        if self.name.GetValue():
-            self.btnAdd.Enable()
-        else:
-            self.btnAdd.Enable(False)
-    
-    def OnAdd(self, event):
-        """!Add new variable to the list"""
-        msg = self.list.Append(self.name.GetValue(),
-                               self.type.GetStringSelection(),
-                               self.value.GetValue(),
-                               self.desc.GetValue())
-        self.name.SetValue('')
-        self.name.SetFocus()
-        
-        if msg:
-            GError(parent = self,
-                   message = msg)
-        else:
-            self.type.SetSelection(2) # string
-            self.value.SetValue('')
-            self.desc.SetValue('')
-            self.UpdateModelVariables()
-        
-    def UpdateModelVariables(self):
-        """!Update model variables"""
-        variables = dict()
-        for values in self.list.GetData().itervalues():
-            name = values[0]
-            variables[name] = { 'type' : str(values[1]) }
-            if values[2]:
-                variables[name]['value'] = values[2]
-            if values[3]:
-                variables[name]['description'] = values[3]
-        
-        self.parent.GetModel().SetVariables(variables)
-        self.parent.ModelChanged()
-
-    def Update(self):
-        """!Reload list of variables"""
-        self.list.OnReload(None)
-        
-    def Reset(self):
-        """!Remove all variables"""
-        self.list.DeleteAllItems()
-        self.parent.GetModel().SetVariables([])
-        
-class VariableListCtrl(ModelListCtrl):
-    def __init__(self, parent, columns, **kwargs):
-        """!List of model variables"""
-        ModelListCtrl.__init__(self, parent, columns, **kwargs)
-
-        self.SetColumnWidth(2, 200) # default value
-
-    def GetListCtrl(self):
-        """!Used by ColumnSorterMixin"""
-        return self
-    
-    def GetData(self):
-        """!Get list data"""
-        return self.itemDataMap
-    
-    def Populate(self, data):
-        """!Populate the list"""
-        self.itemDataMap = dict()
-        i = 0
-        for name, values in data.iteritems():
-            self.itemDataMap[i] = [name, values['type'],
-                                   values.get('value', ''),
-                                   values.get('description', '')]
-            i += 1
-        
-        self.itemCount = len(self.itemDataMap.keys())
-        self.DeleteAllItems()
-        i = 0
-        for name, vtype, value, desc in self.itemDataMap.itervalues():
-            index = self.InsertStringItem(sys.maxint, name)
-            self.SetStringItem(index, 0, name)
-            self.SetStringItem(index, 1, vtype)
-            self.SetStringItem(index, 2, value)
-            self.SetStringItem(index, 3, desc)
-            self.SetItemData(index, i)
-            i += 1
-        
-    def Append(self, name, vtype, value, desc):
-        """!Append new item to the list
-
-        @return None on success
-        @return error string
-        """
-        for iname, ivtype, ivalue, idesc in self.itemDataMap.itervalues():
-            if iname == name:
-                return _("Variable <%s> already exists in the model. "
-                         "Adding variable failed.") % name
-        
-        index = self.InsertStringItem(sys.maxint, name)
-        self.SetStringItem(index, 0, name)
-        self.SetStringItem(index, 1, vtype)
-        self.SetStringItem(index, 2, value)
-        self.SetStringItem(index, 3, desc)
-        self.SetItemData(index, self.itemCount)
-        
-        self.itemDataMap[self.itemCount] = [name, vtype, value, desc]
-        self.itemCount += 1
-        
-        return None
-
-    def OnRemove(self, event):
-        """!Remove selected variable(s) from the model"""
-        item = self.GetFirstSelected()
-        while item != -1:
-            self.DeleteItem(item)
-            del self.itemDataMap[item]
-            item = self.GetFirstSelected()
-        self.parent.UpdateModelVariables()
-        
-        event.Skip()
-        
-    def OnRemoveAll(self, event):
-        """!Remove all variable(s) from the model"""
-        dlg = wx.MessageBox(parent=self,
-                            message=_("Do you want to delete all variables from "
-                                      "the model?"),
-                            caption=_("Delete variables"),
-                            style=wx.YES_NO | wx.CENTRE)
-        if dlg != wx.YES:
-            return
-        
-        self.DeleteAllItems()
-        self.itemDataMap = dict()
-        
-        self.parent.UpdateModelVariables()
-        
-    def OnEndEdit(self, event):
-        """!Finish editing of item"""
-        itemIndex = event.GetIndex()
-        columnIndex = event.GetColumn()
-        nameOld = self.GetItem(itemIndex, 0).GetText()
-
-        if columnIndex == 0: # TODO
-            event.Veto()
-        
-        self.itemDataMap[itemIndex][columnIndex] = event.GetText()
-        
-        self.parent.UpdateModelVariables()
-
-    def OnReload(self, event):
-        """!Reload list of variables"""
-        self.Populate(self.parent.parent.GetModel().GetVariables())
-
-    def OnRightUp(self, event):
-        """!Mouse right button up"""
-        if not hasattr(self, "popupID1"):
-            self.popupID1 = wx.NewId()
-            self.popupID2 = wx.NewId()
-            self.popupID3 = wx.NewId()
-            self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
-            self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
-            self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
-        
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupID1, _("Delete selected"))
-        menu.Append(self.popupID2, _("Delete all"))
-        if self.GetFirstSelected() == -1:
-            menu.Enable(self.popupID1, False)
-            menu.Enable(self.popupID2, False)
-        
-        menu.AppendSeparator()
-        menu.Append(self.popupID3, _("Reload"))
-        
-        self.PopupMenu(menu)
-        menu.Destroy()
-        
-class ModelItem(ModelObject):
-    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
-        """!Abstract class for loops and conditions"""
-        ModelObject.__init__(self, id)
-        self.parent  = parent
-        self.text    = text
-        self.items   = items  # list of items in the loop
-        
-    def GetText(self):
-        """!Get loop text"""
-        return self.text
-
-    def GetItems(self):
-        """!Get items (id)"""
-        return self.items
-
-    def SetId(self, id):
-        """!Set loop id"""
-        self.id = id
-
-    def SetText(self, cond):
-        """!Set loop text (condition)"""
-        self.text = cond
-        self.ClearText()
-        self.AddText('(' + str(self.id) + ') ' + self.text)
-
-    def GetLog(self):
-        """!Get log info"""
-        if self.text:
-            return _("Condition: ") + self.text
-        else:
-            return _("Condition: not defined")
-
-    def AddRelation(self, rel):
-        """!Record relation"""
-        self.rels.append(rel)
-        
-    def Clear(self):
-        """!Clear object, remove rels"""
-        self.rels = list()
-        
-class ModelItemDialog(wx.Dialog):
-    """!Abstract item properties dialog"""
-    def __init__(self, parent, shape, title, id = wx.ID_ANY,
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        self.parent = parent
-        self.shape = shape
-        
-        wx.Dialog.__init__(self, parent, id, title = title, style = style, **kwargs)
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.condBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label=" %s " % _("Condition"))
-        self.condText = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
-                                    value = shape.GetText())
-        
-        self.itemList = ItemCheckListCtrl(parent = self.panel,
-                                          window = self,
-                                          columns = [_("ID"), _("Name"),
-                                                     _("Command")],
-                                          shape = shape)
-        self.itemList.Populate(self.parent.GetModel().GetItems())
-        
-        self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.btnOk     = wx.Button(parent = self.panel, id = wx.ID_OK)
-        self.btnOk.SetDefault()
-        
-    def _layout(self):
-        """!Do layout (virtual method)"""
-        pass
-    
-    def GetCondition(self):
-        """!Get loop condition"""
-        return self.condText.GetValue()
-    
-class ModelLoop(ModelItem, ogl.RectangleShape):
-    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
-        """!Defines a loop"""
-        ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
-        
-        if not width:
-            width = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'width'))
-        if not height:
-            height = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'height'))
-        
-        if self.parent.GetCanvas():
-            ogl.RectangleShape.__init__(self, width, height)
-            
-            self.SetCanvas(self.parent)
-            self.SetX(x)
-            self.SetY(y)
-            self.SetPen(wx.BLACK_PEN)
-            self.SetCornerRadius(100)
-            if text:
-                self.AddText('(' + str(self.id) + ') ' + text)
-            else:
-                self.AddText('(' + str(self.id) + ')')
-        
-        self._setBrush()
-        
-    def _setBrush(self):
-        """!Set brush"""
-        if not self.isEnabled:
-            color = UserSettings.Get(group='modeler', key='disabled',
-                                     subkey='color')
-        else:
-            color = UserSettings.Get(group='modeler', key='loop',
-                                     subkey=('color', 'valid'))
-        
-        wxColor = wx.Color(color[0], color[1], color[2])
-        self.SetBrush(wx.Brush(wxColor))
-
-    def Enable(self, enabled = True):
-        """!Enable/disable action"""
-        for item in self.items:
-            if not isinstance(item, ModelAction):
-                continue
-            item.Enable(enabled)
-        
-        ModelObject.Enable(self, enabled)
-        
-    def Update(self):
-        self._setBrush()
-        
-    def GetName(self):
-        """!Get name"""
-        return _("loop")
-    
-    def SetItems(self, items):
-        """!Set items (id)"""
-        self.items = items
-
-class ModelLoopDialog(ModelItemDialog):
-    """!Loop properties dialog"""
-    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Loop properties"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        ModelItemDialog.__init__(self, parent, shape, title,
-                                 style = style, **kwargs)
-        
-        self.listBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                    label=" %s " % _("List of items in loop"))
-        
-        self.btnSeries = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                   label = _("Series"))
-        self.btnSeries.SetToolTipString(_("Define map series as condition for the loop"))
-        self.btnSeries.Bind(wx.EVT_BUTTON, self.OnSeries)
-        
-        self._layout()
-        self.SetMinSize(self.GetSize())
-        self.SetSize((500, 400))
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        condSizer = wx.StaticBoxSizer(self.condBox, wx.HORIZONTAL)
-        condSizer.Add(item = self.condText, proportion = 1,
-                      flag = wx.ALL, border = 3)
-        condSizer.Add(item = self.btnSeries, proportion = 0,
-                      flag = wx.EXPAND)
-
-        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
-        listSizer.Add(item = self.itemList, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL, border = 3)
-        
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnOk)
-        btnSizer.Realize()
-
-        sizer.Add(item = condSizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL, border = 3)
-        sizer.Add(item = listSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
-        sizer.Add(item = btnSizer, proportion=0,
-                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-        
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        
-        self.Layout()
-        
-    def GetItems(self):
-        """!Get list of selected actions"""
-        return self.itemList.GetItems()
-
-    def OnSeries(self, event):
-        """!Define map series as condition"""
-        dialog = MapLayersDialog(parent = self, title = _("Define series of maps"), modeler = True)
-        if dialog.ShowModal() != wx.ID_OK:
-            dialog.Destroy()
-            return
-        
-        cond = dialog.GetDSeries()
-        if not cond:
-            cond = 'map in %s' % map(lambda x: str(x), dialog.GetMapLayers())
-        
-        self.condText.SetValue(cond)
-                               
-        dialog.Destroy()
-
-class ItemPanel(wx.Panel):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 **kwargs):
-        """!Manage model items
-        """
-        self.parent = parent
-        
-        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
-        
-        self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                    label=" %s " % _("List of items - right-click to delete"))
-        
-        self.list = ItemListCtrl(parent = self,
-                                 columns = [_("ID"), _("Name"), _("In block"),
-                                            _("Command / Condition")])
-        
-        self._layout()
-
-    def _layout(self):
-        """!Layout dialog"""
-        listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
-        listSizer.Add(item = self.list, proportion = 1,
-                      flag = wx.EXPAND)
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = listSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        
-    def Update(self):
-        """!Reload list of variables"""
-        self.list.OnReload(None)
-        
-class ItemListCtrl(ModelListCtrl):
-    def __init__(self, parent, columns, disablePopup = False, **kwargs):
-        """!List of model actions"""
-        self.disablePopup = disablePopup
-                
-        ModelListCtrl.__init__(self, parent, columns, **kwargs)
-        self.SetColumnWidth(1, 100)
-        self.SetColumnWidth(2, 65)
-        
-    def GetListCtrl(self):
-        """!Used by ColumnSorterMixin"""
-        return self
-    
-    def GetData(self):
-        """!Get list data"""
-        return self.itemDataMap
-    
-    def Populate(self, data):
-        """!Populate the list"""
-        self.itemDataMap = dict()
-        
-        if self.shape:
-            if isinstance(self.shape, ModelCondition):
-                if self.GetName() == 'ElseBlockList':
-                    shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['else'])
-                else:
-                    shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['if'])
-            else:
-                shapeItems = map(lambda x: x.GetId(), self.shape.GetItems())
-        else:
-            shapeItems = list()
-        
-        i = 0
-        if len(self.columns) == 3: # ItemCheckList
-            checked = list()
-        for action in data:
-            if isinstance(action, ModelData) or \
-                    action == self.shape:
-                continue
-            
-            if len(self.columns) == 3:
-                self.itemDataMap[i] = [str(action.GetId()),
-                                       action.GetName(),
-                                       action.GetLog()]
-                aId = action.GetBlockId()
-                if action.GetId() in shapeItems:
-                    checked.append(aId)
-                else:
-                    checked.append(None)
-            else:
-                bId = action.GetBlockId()
-                if not bId:
-                    bId = ''
-                self.itemDataMap[i] = [str(action.GetId()),
-                                       action.GetName(),
-                                       ','.join(map(str, bId)),
-                                       action.GetLog()]
-            
-            i += 1
-        
-        self.itemCount = len(self.itemDataMap.keys())
-        self.DeleteAllItems()
-        i = 0
-        if len(self.columns) == 3:
-            for aid, name, desc in self.itemDataMap.itervalues():
-                index = self.InsertStringItem(sys.maxint, aid)
-                self.SetStringItem(index, 0, aid)
-                self.SetStringItem(index, 1, name)
-                self.SetStringItem(index, 2, desc)
-                self.SetItemData(index, i)
-                if checked[i]:
-                    self.CheckItem(index, True)
-                i += 1
-        else:
-            for aid, name, inloop, desc in self.itemDataMap.itervalues():
-                index = self.InsertStringItem(sys.maxint, aid)
-                self.SetStringItem(index, 0, aid)
-                self.SetStringItem(index, 1, name)
-                self.SetStringItem(index, 2, inloop)
-                self.SetStringItem(index, 3, desc)
-                self.SetItemData(index, i)
-                i += 1
-                
-    def OnRemove(self, event):
-        """!Remove selected action(s) from the model"""
-        model = self.frame.GetModel()
-        canvas = self.frame.GetCanvas()
-        
-        item = self.GetFirstSelected()
-        while item != -1:
-            self.DeleteItem(item)
-            del self.itemDataMap[item]
-            
-            aId = self.GetItem(item, 0).GetText()
-            action = model.GetItem(int(aId))
-            if not action:
-                item = self.GetFirstSelected()
-                continue
-            
-            model.RemoveItem(action)
-            canvas.GetDiagram().RemoveShape(action)
-            self.frame.ModelChanged()
-            
-            item = self.GetFirstSelected()
-        
-        canvas.Refresh()
-        
-        event.Skip()
-    
-    def OnRemoveAll(self, event):
-        """!Remove all variable(s) from the model"""
-        deleteDialog = wx.MessageBox(parent=self,
-                                     message=_("Selected data records (%d) will permanently deleted "
-                                               "from table. Do you want to delete them?") % \
-                                         (len(self.listOfSQLStatements)),
-                                     caption=_("Delete records"),
-                                     style=wx.YES_NO | wx.CENTRE)
-        if deleteDialog != wx.YES:
-            return False
-        
-        self.DeleteAllItems()
-        self.itemDataMap = dict()
-
-        self.parent.UpdateModelVariables()
-
-    def OnEndEdit(self, event):
-        """!Finish editing of item"""
-        itemIndex = event.GetIndex()
-        columnIndex = event.GetColumn()
-        
-        self.itemDataMap[itemIndex][columnIndex] = event.GetText()
-        
-        aId = int(self.GetItem(itemIndex, 0).GetText())
-        action = self.frame.GetModel().GetItem(aId)
-        if not action:
-            event.Veto()
-        if columnIndex == 0:
-            action.SetId(int(event.GetText()))
-        
-        self.frame.ModelChanged()
-
-    def OnReload(self, event = None):
-        """!Reload list of actions"""
-        self.Populate(self.frame.GetModel().GetItems())
-
-    def OnRightUp(self, event):
-        """!Mouse right button up"""
-        if self.disablePopup:
-            return
-        
-        if not hasattr(self, "popupID1"):
-            self.popupID1 = wx.NewId()
-            self.popupID2 = wx.NewId()
-            self.popupID3 = wx.NewId()
-            self.popupID4 = wx.NewId()
-            self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
-            self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
-            self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
-            self.Bind(wx.EVT_MENU, self.OnNormalize, id = self.popupID4)
-
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupID1, _("Delete selected"))
-        menu.Append(self.popupID2, _("Delete all"))
-        if self.GetFirstSelected() == -1:
-            menu.Enable(self.popupID1, False)
-            menu.Enable(self.popupID2, False)
-        
-        menu.AppendSeparator()
-        menu.Append(self.popupID4, _("Normalize"))
-        menu.Append(self.popupID3, _("Reload"))
-        
-        self.PopupMenu(menu)
-        menu.Destroy()
-    
-    def OnNormalize(self, event):
-        """!Update id of actions"""
-        model = self.frame.GetModel()
-        
-        aId = 1
-        for item in model.GetItems():
-            item.SetId(aId)
-            aId += 1
-        
-        self.OnReload(None)
-        self.frame.GetCanvas().Refresh()
-        self.frame.ModelChanged()
-
-class ItemCheckListCtrl(ItemListCtrl, listmix.CheckListCtrlMixin):
-    def __init__(self, parent, shape, columns, window = None, **kwargs):
-        self.parent = parent
-        self.window = window
-        
-        ItemListCtrl.__init__(self, parent, columns, disablePopup = True, **kwargs)
-        listmix.CheckListCtrlMixin.__init__(self)
-        self.SetColumnWidth(0, 50)
-        
-        self.shape  = shape
-        
-    def OnBeginEdit(self, event):
-        """!Disable editing"""
-        event.Veto()
-        
-    def OnCheckItem(self, index, flag):
-        """!Item checked/unchecked"""
-        name = self.GetName()
-        if name == 'IfBlockList' and self.window:
-            self.window.OnCheckItemIf(index, flag)
-        elif name == 'ElseBlockList' and self.window:
-            self.window.OnCheckItemElse(index, flag)
-        
-    def GetItems(self):
-        """!Get list of selected actions"""
-        ids = { 'checked'   : list(),
-                'unchecked' : list() }
-        for i in range(self.GetItemCount()):
-            iId = int(self.GetItem(i, 0).GetText())
-            if self.IsChecked(i):
-                ids['checked'].append(iId)
-            else:
-                ids['unchecked'].append(iId)
-            
-        return ids
-
-    def CheckItemById(self, aId, flag):
-        """!Check/uncheck given item by id"""
-        for i in range(self.GetItemCount()):
-            iId = int(self.GetItem(i, 0).GetText())
-            if iId == aId:
-                self.CheckItem(i, flag)
-                break
-        
-class ModelCondition(ModelItem, ogl.PolygonShape):
-    def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '',
-                 items = { 'if' : [], 'else' : [] }):
-        """!Defines a if-else condition"""
-        ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
-        
-        if not width:
-            self.width = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'width'))
-        else:
-            self.width = width
-        if not height:
-            self.height = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'height'))
-        else:
-            self.height = height
-        
-        if self.parent.GetCanvas():
-            ogl.PolygonShape.__init__(self)
-            
-            points = [(0, - self.height / 2),
-                      (self.width / 2, 0),
-                      (0, self.height / 2),
-                      (- self.width / 2, 0)]
-            self.Create(points)
-            
-            self.SetCanvas(self.parent)
-            self.SetX(x)
-            self.SetY(y)
-            self.SetPen(wx.BLACK_PEN)
-            if text:
-                self.AddText('(' + str(self.id) + ') ' + text)
-            else:
-                self.AddText('(' + str(self.id) + ')')
-
-    def GetName(self):
-        """!Get name"""
-        return _("if-else")
-
-    def GetWidth(self):
-        """!Get object width"""
-        return self.width
-
-    def GetHeight(self):
-        """!Get object height"""
-        return self.height
-
-    def SetItems(self, items, branch = 'if'):
-        """!Set items (id)
-
-        @param items list of items
-        @param branch 'if' / 'else'
-        """
-        if branch in ['if', 'else']:
-            self.items[branch] = items
-        
-class ModelConditionDialog(ModelItemDialog):
-    """!Condition properties dialog"""
-    def __init__(self, parent, shape, id = wx.ID_ANY, title = _("If-else properties"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        ModelItemDialog.__init__(self, parent, shape, title,
-                                 style = style, **kwargs)
-        
-        self.listBoxIf = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                      label=" %s " % _("List of items in 'if' block"))
-        self.itemListIf = self.itemList
-        self.itemListIf.SetName('IfBlockList')
-        
-        self.listBoxElse = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                        label=" %s " % _("List of items in 'else' block"))
-        self.itemListElse = ItemCheckListCtrl(parent = self.panel,
-                                              window = self,
-                                              columns = [_("ID"), _("Name"),
-                                                         _("Command")],
-                                              shape = shape)
-        self.itemListElse.SetName('ElseBlockList')
-        self.itemListElse.Populate(self.parent.GetModel().GetItems())
-        
-        self._layout()
-        self.SetMinSize(self.GetSize())
-        self.SetSize((500, 400))
-        
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        condSizer = wx.StaticBoxSizer(self.condBox, wx.VERTICAL)
-        condSizer.Add(item = self.condText, proportion = 1,
-                      flag = wx.EXPAND)
-        
-        listIfSizer = wx.StaticBoxSizer(self.listBoxIf, wx.VERTICAL)
-        listIfSizer.Add(item = self.itemListIf, proportion = 1,
-                        flag = wx.EXPAND)
-        listElseSizer = wx.StaticBoxSizer(self.listBoxElse, wx.VERTICAL)
-        listElseSizer.Add(item = self.itemListElse, proportion = 1,
-                          flag = wx.EXPAND)
-        
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(self.btnCancel)
-        btnSizer.AddButton(self.btnOk)
-        btnSizer.Realize()
-
-        sizer.Add(item = condSizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL, border = 3)
-        sizer.Add(item = listIfSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
-        sizer.Add(item = listElseSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
-        sizer.Add(item = btnSizer, proportion=0,
-                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-        
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        
-        self.Layout()
-
-    def OnCheckItemIf(self, index, flag):
-        """!Item in if-block checked/unchecked"""
-        if flag is False:
-            return
-        
-        aId = int(self.itemListIf.GetItem(index, 0).GetText())
-        if aId in self.itemListElse.GetItems()['checked']:
-            self.itemListElse.CheckItemById(aId, False)
-            
-    def OnCheckItemElse(self, index, flag):
-        """!Item in else-block checked/unchecked"""
-        if flag is False:
-            return
-        
-        aId = int(self.itemListElse.GetItem(index, 0).GetText())
-        if aId in self.itemListIf.GetItems()['checked']:
-            self.itemListIf.CheckItemById(aId, False)
-        
-    def GetItems(self):
-        """!Get items"""
-        return { 'if'   : self.itemListIf.GetItems(),
-                 'else' : self.itemListElse.GetItems() }
-
-class WritePythonFile:
-    def __init__(self, fd, model):
-        """!Class for exporting model to Python script
-
-        @param fd file desciptor
-        """
-        self.fd     = fd
-        self.model  = model
-        self.indent = 4
-
-        self._writePython()
-        
-    def _writePython(self):
-        """!Write model to file"""
-        properties = self.model.GetProperties()
-        
-        self.fd.write(
-r"""#!/usr/bin/env python
-#
-############################################################################
-#
-# MODULE:       %s
-#
-# AUTHOR(S):	%s
-#               
-# PURPOSE:      %s
-#
-# DATE:         %s
-#
-#############################################################################
-""" % (properties['name'],
-       properties['author'],
-       properties['description'],
-       time.asctime()))
-        
-        self.fd.write(
-r"""
-import sys
-import os
-import atexit
-
-import grass.script as grass
-""")
-        
-        # cleanup()
-        rast, vect, rast3d, msg = self.model.GetIntermediateData()
-        self.fd.write(
-r"""
-def cleanup():
-""")
-        if rast:
-            self.fd.write(
-r"""    grass.run_command('g.remove',
-                      rast=%s)
-""" % ','.join(map(lambda x: "'" + x + "'", rast)))
-        if vect:
-            self.fd.write(
-r"""    grass.run_command('g.remove',
-                      vect = %s)
-""" % ','.join(map(lambda x: "'" + x + "'", vect)))
-        if rast3d:
-            self.fd.write(
-r"""    grass.run_command('g.remove',
-                      rast3d = %s)
-""" % ','.join(map(lambda x: "'" + x + "'", rast3d)))
-        if not rast and not vect and not rast3d:
-            self.fd.write('    pass\n')
-        
-        self.fd.write("\ndef main():\n")
-        for item in self.model.GetItems():
-            self._writePythonItem(item)
-        
-        self.fd.write("\n    return 0\n")
-        
-        self.fd.write(
-r"""
-if __name__ == "__main__":
-    options, flags = grass.parser()
-    atexit.register(cleanup)
-    sys.exit(main())
-""")
-        
-    def _writePythonItem(self, item, ignoreBlock = True, variables = []):
-        """!Write model object to Python file"""
-        if isinstance(item, ModelAction):
-            if ignoreBlock and item.GetBlockId(): # ignore items in loops of conditions
-                return
-            self._writePythonAction(item, variables = variables)
-        elif isinstance(item, ModelLoop) or isinstance(item, ModelCondition):
-            # substitute condition
-            variables = self.model.GetVariables()
-            cond = item.GetText()
-            for variable in variables:
-                pattern = re.compile('%' + variable)
-                if pattern.search(cond):
-                    value = variables[variable].get('value', '')
-                    if variables[variable].get('type', 'string') == 'string':
-                        value = '"' + value + '"'
-                    cond = pattern.sub(value, cond)
-            if isinstance(item, ModelLoop):
-                condVar, condText = map(lambda x: x.strip(), re.split('\s*in\s*', cond))
-                cond = "%sfor %s in " % (' ' * self.indent, condVar)
-                if condText[0] == '`' and condText[-1] == '`':
-                    task = menuform.GUI(show = None).ParseCommand(cmd = utils.split(condText[1:-1]))
-                    cond += "grass.read_command("
-                    cond += self._getPythonActionCmd(task, len(cond), variables = [condVar]) + ".splitlines()"
-                else:
-                    cond += condText
-                self.fd.write('%s:\n' % cond)
-                self.indent += 4
-                for action in item.GetItems():
-                    self._writePythonItem(action, ignoreBlock = False, variables = [condVar])
-                self.indent -= 4
-            else: # ModelCondition
-                self.fd.write('%sif %s:\n' % (' ' * self.indent, cond))
-                self.indent += 4
-                condItems = item.GetItems()
-                for action in condItems['if']:
-                    self._writePythonItem(action, ignoreBlock = False)
-                if condItems['else']:
-                    self.indent -= 4
-                    self.fd.write('%selse:\n' % (' ' * self.indent))
-                    self.indent += 4
-                    for action in condItems['else']:
-                        self._writePythonItem(action, ignoreBlock = False)
-                self.indent += 4
-        
-    def _writePythonAction(self, item, variables = []):
-        """!Write model action to Python file"""
-        task = menuform.GUI(show = None).ParseCommand(cmd = item.GetLog(string = False))
-        strcmd = "%sgrass.run_command(" % (' ' * self.indent)
-        self.fd.write(strcmd + self._getPythonActionCmd(task, len(strcmd), variables) + '\n')
-        
-    def _getPythonActionCmd(self, task, cmdIndent, variables = []):
-        opts = task.get_options()
-        
-        ret = ''
-        flags = ''
-        params = list()
-        
-        for f in opts['flags']:
-            if f.get('value', False):
-                name = f.get('name', '')
-                if len(name) > 1:
-                    params.append('%s = True' % name)
-                else:
-                    flags += name
-            
-        for p in opts['params']:
-            name = p.get('name', None)
-            value = p.get('value', None)
-            if name and value:
-                ptype = p.get('type', 'string')
-                if value[0] == '%':
-                    params.append("%s = %s" % (name, value[1:]))
-                elif ptype == 'string':
-                    params.append('%s = "%s"' % (name, value))
-                else:
-                    params.append("%s = %s" % (name, value))
-        
-        ret += '"%s"' % task.get_name()
-        if flags:
-            ret += ",\n%sflags = '%s'" % (' ' * cmdIndent, flags)
-        if len(params) > 0:
-            ret += ",\n"
-            for opt in params[:-1]:
-                ret += "%s%s,\n" % (' ' * cmdIndent, opt)
-            ret += "%s%s)" % (' ' * cmdIndent, params[-1])
-        else:
-            ret += ")"
-        
-        return ret
-
-def main():
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    app = wx.PySimpleApp()
-    wx.InitAllImageHandlers()
-    frame = ModelFrame(parent = None)
-    if len(sys.argv) > 1:
-        frame.LoadModelFile(sys.argv[1])
-    frame.Show()
-    
-    app.MainLoop()
-    
-if __name__ == "__main__":
-    main()

Deleted: grass/trunk/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/goutput.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/goutput.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1156 +0,0 @@
-"""!
- at package goutput
-
- at brief Command output log widget
-
-Classes:
-- GMConsole
-- GMStc
-- GMStdout
-- GMStderr
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Michael Barton (Arizona State University)
- at author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
-"""
-
-import os
-import sys
-import textwrap
-import time
-import threading
-import Queue
-import codecs
-import locale
-
-import wx
-import wx.stc
-from wx.lib.newevent import NewEvent
-
-import grass.script as grass
-from   grass.script import task as gtask
-
-import globalvar
-import gcmd
-import utils
-import preferences
-import menuform
-import prompt
-
-from debug       import Debug
-from preferences import globalSettings as UserSettings
-from ghelp       import SearchModuleWindow
-
-wxCmdOutput,   EVT_CMD_OUTPUT   = NewEvent()
-wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
-wxCmdRun,      EVT_CMD_RUN      = NewEvent()
-wxCmdDone,     EVT_CMD_DONE     = NewEvent()
-wxCmdAbort,    EVT_CMD_ABORT    = NewEvent()
-wxCmdPrepare,  EVT_CMD_PREPARE  = NewEvent()
-
-def GrassCmd(cmd, stdout = None, stderr = None):
-    """!Return GRASS command thread"""
-    return gcmd.CommandThread(cmd,
-                              stdout = stdout, stderr = stderr)
-
-class CmdThread(threading.Thread):
-    """!Thread for GRASS commands"""
-    requestId = 0
-    def __init__(self, parent, requestQ, resultQ, **kwds):
-        threading.Thread.__init__(self, **kwds)
-
-        self.setDaemon(True)
-
-        self.parent = parent # GMConsole
-        self._want_abort_all = False
-        
-        self.requestQ = requestQ
-        self.resultQ = resultQ
-
-        self.start()
-
-    def RunCmd(self, *args, **kwds):
-        CmdThread.requestId += 1
-        
-        self.requestCmd = None
-        self.requestQ.put((CmdThread.requestId, args, kwds))
-        
-        return CmdThread.requestId
-
-    def SetId(self, id):
-        """!Set starting id"""
-        CmdThread.requestId = id
-        
-    def run(self):
-        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-        while True:
-            requestId, args, kwds = self.requestQ.get()
-            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-                if key in kwds:
-                    vars()[key] = kwds[key]
-                    del kwds[key]
-                else:
-                    vars()[key] = None
-            
-            if not vars()['callable']:
-                vars()['callable'] = GrassCmd
-            
-            requestTime = time.time()
-            
-            # prepare
-            event = wxCmdPrepare(cmd = args[0],
-                                 time = requestTime,
-                                 pid = requestId,
-                                 onPrepare = vars()['onPrepare'],
-                                 userData = vars()['userData'])
-            wx.PostEvent(self.parent, event)
-            
-            # run command
-            event = wxCmdRun(cmd = args[0],
-                             pid = requestId)
-            
-            wx.PostEvent(self.parent, event)
-            
-            time.sleep(.1)
-            self.requestCmd = vars()['callable'](*args, **kwds)
-            if self._want_abort_all:
-                self.requestCmd.abort()
-                if self.requestQ.empty():
-                    self._want_abort_all = False
-            
-            self.resultQ.put((requestId, self.requestCmd.run()))
-            
-            try:
-                returncode = self.requestCmd.module.returncode
-            except AttributeError:
-                returncode = 0 # being optimistic
-            
-            try:
-                aborted = self.requestCmd.aborted
-            except AttributeError:
-                aborted = False
-            
-            time.sleep(.1)
-
-            # set default color table for raster data
-            if UserSettings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'enabled') and \
-                    args[0][0][:2] == 'r.':
-                colorTable = UserSettings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'selection')
-                mapName = None
-                if args[0][0] == 'r.mapcalc':
-                    try:
-                        mapName = args[0][1].split('=', 1)[0].strip()
-                    except KeyError:
-                        pass
-                else:
-                    moduleInterface = menuform.GUI(show = None).ParseCommand(args[0])
-                    outputParam = moduleInterface.get_param(value = 'output', raiseError = False)
-                    if outputParam and outputParam['prompt'] == 'raster':
-                        mapName = outputParam['value']
-                
-                if mapName:
-                    argsColor = list(args)
-                    argsColor[0] = [ 'r.colors',
-                                     'map=%s' % mapName,
-                                     'color=%s' % colorTable ]
-                    self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
-                    self.resultQ.put((requestId, self.requestCmdColor.run()))
-            
-            event = wxCmdDone(cmd = args[0],
-                              aborted = aborted,
-                              returncode = returncode,
-                              time = requestTime,
-                              pid = requestId,
-                              onDone = vars()['onDone'],
-                              userData = vars()['userData'])
-            
-            # send event
-            wx.PostEvent(self.parent, event)
-            
-    def abort(self, abortall = True):
-        """!Abort command(s)"""
-        if abortall:
-            self._want_abort_all = True
-        self.requestCmd.abort()
-        if self.requestQ.empty():
-            self._want_abort_all = False
-        
-class GMConsole(wx.SplitterWindow):
-    """!Create and manage output console for commands run by GUI.
-    """
-    def __init__(self, parent, id = wx.ID_ANY, margin = False,
-                 notebook = None,
-                 style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
-                 **kwargs):
-        wx.SplitterWindow.__init__(self, parent, id, style = style, *kwargs)
-        self.SetName("GMConsole")
-        
-        self.panelOutput = wx.Panel(parent = self, id = wx.ID_ANY)
-        self.panelPrompt = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        # initialize variables
-        self.parent          = parent # GMFrame | CmdPanel | ?
-        if notebook:
-            self._notebook = notebook
-        else:
-            self._notebook = self.parent.notebook
-        self.lineWidth       = 80
-        
-        # remember position of line begining (used for '\r')
-        self.linePos         = -1
-        
-        # create queues
-        self.requestQ = Queue.Queue()
-        self.resultQ = Queue.Queue()
-        
-        # progress bar
-        self.progressbar = wx.Gauge(parent = self.panelOutput, id = wx.ID_ANY,
-                                    range = 100, pos = (110, 50), size = (-1, 25),
-                                    style = wx.GA_HORIZONTAL)
-        self.progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
-        
-        # text control for command output
-        self.cmdOutput = GMStc(parent = self.panelOutput, id = wx.ID_ANY, margin = margin,
-                               wrap = None) 
-        self.cmdOutputTimer = wx.Timer(self.cmdOutput, id = wx.ID_ANY)
-        self.cmdOutput.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
-        self.cmdOutput.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
-        self.Bind(EVT_CMD_RUN,     self.OnCmdRun)
-        self.Bind(EVT_CMD_DONE,    self.OnCmdDone)
-        self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
-        
-        # search & command prompt
-        self.cmdPrompt = prompt.GPromptSTC(parent = self)
-        
-        if self.parent.GetName() != 'LayerManager':
-            self.search = None
-            self.cmdPrompt.Hide()
-        else:
-            self.infoCollapseLabelExp = _("Click here to show search module engine")
-            self.infoCollapseLabelCol = _("Click here to hide search module engine")
-            self.searchPane = wx.CollapsiblePane(parent = self.panelOutput,
-                                                 label = self.infoCollapseLabelExp,
-                                                 style = wx.CP_DEFAULT_STYLE |
-                                                 wx.CP_NO_TLW_RESIZE | wx.EXPAND)
-            self.MakeSearchPaneContent(self.searchPane.GetPane())
-            self.searchPane.Collapse(True)
-            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSearchPaneChanged, self.searchPane) 
-            self.search.Bind(wx.EVT_TEXT,             self.OnUpdateStatusBar)
-        
-        # stream redirection
-        self.cmdStdOut = GMStdout(self)
-        self.cmdStdErr = GMStderr(self)
-        
-        # thread
-        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
-        
-        self.outputBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
-                                      label = " %s " % _("Output window"))
-        self.cmdBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
-                                   label = " %s " % _("Command prompt"))
-        
-        # buttons
-        self.btnOutputClear = wx.Button(parent = self.panelOutput, id = wx.ID_CLEAR)
-        self.btnOutputClear.SetToolTipString(_("Clear output window content"))
-        self.btnCmdClear = wx.Button(parent = self.panelOutput, id = wx.ID_CLEAR)
-        self.btnCmdClear.SetToolTipString(_("Clear command prompt content"))
-        if self.parent.GetName() != 'LayerManager':
-            self.btnCmdClear.Hide()
-        self.btnOutputSave  = wx.Button(parent = self.panelOutput, id = wx.ID_SAVE)
-        self.btnOutputSave.SetToolTipString(_("Save output window content to the file"))
-        # abort
-        self.btnCmdAbort = wx.Button(parent = self.panelOutput, id = wx.ID_STOP)
-        self.btnCmdAbort.SetToolTipString(_("Abort running command"))
-        self.btnCmdAbort.Enable(False)
-        
-        self.btnCmdClear.Bind(wx.EVT_BUTTON,     self.cmdPrompt.OnCmdErase)
-        self.btnOutputClear.Bind(wx.EVT_BUTTON,  self.ClearHistory)
-        self.btnOutputSave.Bind(wx.EVT_BUTTON,   self.SaveHistory)
-        self.btnCmdAbort.Bind(wx.EVT_BUTTON,     self.OnCmdAbort)
-        self.btnCmdAbort.Bind(EVT_CMD_ABORT,     self.OnCmdAbort)
-        
-        self._layout()
-        
-    def _layout(self):
-        """!Do layout"""
-        outputSizer = wx.BoxSizer(wx.VERTICAL)
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        outBtnSizer = wx.StaticBoxSizer(self.outputBox, wx.HORIZONTAL)
-        cmdBtnSizer = wx.StaticBoxSizer(self.cmdBox, wx.HORIZONTAL)
-        
-        if self.cmdPrompt.IsShown():
-            promptSizer = wx.BoxSizer(wx.VERTICAL)
-            promptSizer.Add(item = self.cmdPrompt, proportion = 1,
-                        flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
-        
-        if self.search and self.search.IsShown():
-            outputSizer.Add(item = self.searchPane, proportion = 0,
-                            flag = wx.EXPAND | wx.ALL, border = 3)
-        outputSizer.Add(item = self.cmdOutput, proportion = 1,
-                        flag = wx.EXPAND | wx.ALL, border = 3)
-        outputSizer.Add(item = self.progressbar, proportion = 0,
-                        flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
-        outBtnSizer.Add(item = self.btnOutputClear, proportion = 1,
-                        flag = wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, border = 5)
-        outBtnSizer.Add(item = self.btnOutputSave, proportion = 1,
-                        flag = wx.ALIGN_RIGHT | wx.RIGHT, border = 5)
-        
-        cmdBtnSizer.Add(item = self.btnCmdClear, proportion = 1,
-                        flag = wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border = 5)
-        cmdBtnSizer.Add(item = self.btnCmdAbort, proportion = 1,
-                        flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
-        
-        btnSizer.Add(item = outBtnSizer, proportion = 1,
-                     flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
-        btnSizer.Add(item = cmdBtnSizer, proportion = 1,
-                     flag = wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
-        outputSizer.Add(item = btnSizer, proportion = 0,
-                        flag = wx.EXPAND)
-        
-        outputSizer.Fit(self)
-        outputSizer.SetSizeHints(self)
-        self.panelOutput.SetSizer(outputSizer)
-        
-        if self.cmdPrompt.IsShown():
-            promptSizer.Fit(self)
-            promptSizer.SetSizeHints(self)
-            self.panelPrompt.SetSizer(promptSizer)
-        
-        # split window
-        if self.cmdPrompt.IsShown():
-            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -50)
-        else:
-            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -45)
-            self.Unsplit()
-        self.SetMinimumPaneSize(self.btnCmdClear.GetSize()[1] + 25)
-        
-        self.SetSashGravity(1.0)
-        
-        # layout
-        self.SetAutoLayout(True)
-        self.Layout()
-
-    def MakeSearchPaneContent(self, pane):
-        """!Create search pane"""
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        self.search = SearchModuleWindow(parent = pane, cmdPrompt = self.cmdPrompt)
-        
-        border.Add(item = self.search, proportion = 0,
-                   flag = wx.EXPAND | wx.ALL, border = 1)
-        
-        pane.SetSizer(border)
-        border.Fit(pane)
-        
-    def OnSearchPaneChanged(self, event):
-        """!Collapse search module box"""
-        if self.searchPane.IsExpanded():
-            self.searchPane.SetLabel(self.infoCollapseLabelCol)
-        else:
-            self.searchPane.SetLabel(self.infoCollapseLabelExp)
-        
-        self.panelOutput.Layout()
-        self.panelOutput.SendSizeEvent()
-        
-    def GetPanel(self, prompt = True):
-        """!Get panel
-
-        @param prompt get prompt / output panel
-
-        @return wx.Panel reference
-        """
-        if prompt:
-            return self.panelPrompt
-
-        return self.panelOutput
-    
-    def Redirect(self):
-        """!Redirect stdout/stderr
-        """
-        if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
-            # don't redirect when debugging is enabled
-            sys.stdout = self.cmdStdOut
-            sys.stderr = self.cmdStdErr
-        else:
-            enc = locale.getdefaultlocale()[1]
-            if enc:
-                sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
-                sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
-            else:
-                sys.stdout = sys.__stdout__
-                sys.stderr = sys.__stderr__
-        
-    def WriteLog(self, text, style = None, wrap = None,
-                 switchPage = False):
-        """!Generic method for writing log message in 
-        given style
-
-        @param line text line
-        @param style text style (see GMStc)
-        @param stdout write to stdout or stderr
-        """
-
-        self.cmdOutput.SetStyle()
-
-        if switchPage:
-            self._notebook.SetSelectionByName('output')
-        
-        if not style:
-            style = self.cmdOutput.StyleDefault
-        
-        # p1 = self.cmdOutput.GetCurrentPos()
-        p1 = self.cmdOutput.GetEndStyled()
-        # self.cmdOutput.GotoPos(p1)
-        self.cmdOutput.DocumentEnd()
-        
-        for line in text.splitlines():
-            # fill space
-            if len(line) < self.lineWidth:
-                diff = self.lineWidth - len(line) 
-                line += diff * ' '
-            
-            self.cmdOutput.AddTextWrapped(line, wrap = wrap) # adds '\n'
-            
-            p2 = self.cmdOutput.GetCurrentPos()
-            
-            self.cmdOutput.StartStyling(p1, 0xff)
-            self.cmdOutput.SetStyling(p2 - p1, style)
-        
-        self.cmdOutput.EnsureCaretVisible()
-        
-    def WriteCmdLog(self, line, pid = None, switchPage = True):
-        """!Write message in selected style
-        
-        @param line message to be printed
-        @param pid process pid or None
-        @param switchPage True to switch page
-        """
-        if pid:
-            line = '(' + str(pid) + ') ' + line
-        self.WriteLog(line, style = self.cmdOutput.StyleCommand, switchPage = switchPage)
-
-    def WriteWarning(self, line):
-        """!Write message in warning style"""
-        self.WriteLog(line, style = self.cmdOutput.StyleWarning, switchPage = True)
-
-    def WriteError(self, line):
-        """!Write message in error style"""
-        self.WriteLog(line, style = self.cmdOutput.StyleError, switchPage = True)
-
-    def RunCmd(self, command, compReg = True, switchPage = False,
-               onDone = None, onPrepare = None, userData = None):
-        """!Run command typed into console command prompt (GPrompt).
-        
-        @todo Display commands (*.d) are captured and processed
-        separately by mapdisp.py. Display commands are rendered in map
-        display widget that currently has the focus (as indicted by
-        mdidx).
-        
-        @param command command given as a list (produced e.g. by utils.split())
-        @param compReg True use computation region
-        @param switchPage switch to output page
-        @param onDone function to be called when command is finished
-        @param onPrepare function to be called before command is launched
-        @param userData data defined for the command
-        """
-        if len(command) == 0:
-            Debug.msg(2, "GPrompt:RunCmd(): empty command")
-            return 0
-        
-        # update history file
-        env = grass.gisenv()
-        try:
-            fileHistory = codecs.open(os.path.join(env['GISDBASE'],
-                                                   env['LOCATION_NAME'],
-                                                   env['MAPSET'],
-                                                   '.bash_history'),
-                                      encoding = 'utf-8', mode = 'a')
-        except IOError, e:
-            self.WriteError(e)
-            fileHistory = None
-        
-        if fileHistory:
-            try:
-                fileHistory.write(' '.join(command) + os.linesep)
-            finally:
-                fileHistory.close()
-        
-        # update history items
-        if self.parent.GetName() == 'LayerManager':
-            try:
-                self.parent.cmdinput.SetHistoryItems()
-            except AttributeError:
-                pass
-        
-        if command[0] in globalvar.grassCmd['all']:
-            # send GRASS command without arguments to GUI command interface
-            # except display commands (they are handled differently)
-            if self.parent.GetName() == "LayerManager" and \
-                    command[0][0:2] == "d." and \
-                    'help' not in ' '.join(command[1:]):
-                # display GRASS commands
-                try:
-                    layertype = {'d.rast'         : 'raster',
-                                 'd.rast3d'       : '3d-raster',
-                                 'd.rgb'          : 'rgb',
-                                 'd.his'          : 'his',
-                                 'd.shaded'       : 'shaded',
-                                 'd.legend'       : 'rastleg',
-                                 'd.rast.arrow'   : 'rastarrow',
-                                 'd.rast.num'     : 'rastnum',
-                                 'd.rast.leg'     : 'maplegend',
-                                 'd.vect'         : 'vector',
-                                 'd.thematic.area': 'thememap',
-                                 'd.vect.chart'   : 'themechart',
-                                 'd.grid'         : 'grid',
-                                 'd.geodesic'     : 'geodesic',
-                                 'd.rhumbline'    : 'rhumb',
-                                 'd.labels'       : 'labels',
-                                 'd.barscale'     : 'barscale',
-                                 'd.redraw'       : 'redraw'}[command[0]]
-                except KeyError:
-                    gcmd.GMessage(parent = self.parent,
-                                  message = _("Command '%s' not yet implemented in the WxGUI. "
-                                              "Try adding it as a command layer instead.") % command[0])
-                    return 1
-                
-                if layertype == 'barscale':
-                    self.parent.curr_page.maptree.GetMapDisplay().OnAddBarscale(None)
-                elif layertype == 'rastleg':
-                    self.parent.curr_page.maptree.GetMapDisplay().OnAddLegend(None)
-                elif layertype == 'redraw':
-                    self.parent.curr_page.maptree.GetMapDisplay().OnRender(None)
-                else:
-                    # add layer into layer tree
-                    lname, found = utils.GetLayerNameFromCmd(command, fullyQualified = True,
-                                                             layerType = layertype)
-                    if self.parent.GetName() == "LayerManager":
-                        self.parent.curr_page.maptree.AddLayer(ltype = layertype,
-                                                               lname = lname,
-                                                               lcmd = command)
-            
-            else:
-                # other GRASS commands (r|v|g|...)
-                if len(command) == 1 and command[0] != 'v.krige':
-                    # no arguments given
-                    menuform.GUI(parent = self).ParseCommand(command)
-                    return 0
-                
-                task = menuform.GUI(show = None).ParseCommand(command)
-                if task:
-                    # check for <input>=-
-                    for p in task.get_options()['params']:
-                        if p.get('prompt', '') == 'input' and \
-                                p.get('element', '') == 'file' and \
-                                p.get('age', 'new') == 'old' and \
-                                p.get('value', '') == '-':
-                            gcmd.GError(parent = self,
-                                        message = _("Unable to run command:\n%(cmd)s\n\n"
-                                                    "Option <%(opt)s>: read from standard input is not "
-                                                    "supported by wxGUI") % { 'cmd': ' '.join(command),
-                                                                          'opt': p.get('name', '') }
-                                        )
-                            return 1
-                
-                # switch to 'Command output' if required
-                if switchPage:
-                    self._notebook.SetSelectionByName('output')
-                    
-                    self.parent.SetFocus()
-                    self.parent.Raise()
-                
-                # activate computational region (set with g.region)
-                # for all non-display commands.
-                if compReg:
-                    tmpreg = os.getenv("GRASS_REGION")
-                    if "GRASS_REGION" in os.environ:
-                        del os.environ["GRASS_REGION"]
-                
-                # process GRASS command with argument
-                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
-                                      onDone = onDone, onPrepare = onPrepare, userData = userData)
-                self.cmdOutputTimer.Start(50)
-                
-                # deactivate computational region and return to display settings
-                if compReg and tmpreg:
-                    os.environ["GRASS_REGION"] = tmpreg
-        else:
-            # Send any other command to the shell. Send output to
-            # console output window
-            if len(command) == 1:
-                try:
-                    task = gtask.parse_interface(command[0])
-                except:
-                    task = None
-            else:
-                task = None
-                
-            if task:
-                # process GRASS command without argument
-                menuform.GUI(parent = self).ParseCommand(command)
-            else:
-                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
-                                      onDone = onDone, onPrepare = onPrepare, userData = userData)
-            self.cmdOutputTimer.Start(50)
-        
-        return 0
-
-    def ClearHistory(self, event):
-        """!Clear history of commands"""
-        self.cmdOutput.SetReadOnly(False)
-        self.cmdOutput.ClearAll()
-        self.cmdOutput.SetReadOnly(True)
-        self.progressbar.SetValue(0)
-
-    def GetProgressBar(self):
-        """!Return progress bar widget"""
-        return self.progressbar
-    
-    def GetLog(self, err = False):
-        """!Get widget used for logging
-
-        @param err True to get stderr widget
-        """
-        if err:
-            return self.cmdStdErr
-        
-        return self.cmdStdOut
-    
-    def SaveHistory(self, event):
-        """!Save history of commands"""
-        self.history = self.cmdOutput.GetSelectedText()
-        if self.history == '':
-            self.history = self.cmdOutput.GetText()
-
-        # add newline if needed
-        if len(self.history) > 0 and self.history[-1] != '\n':
-            self.history += '\n'
-
-        wildcard = "Text file (*.txt)|*.txt"
-        dlg = wx.FileDialog(self, message = _("Save file as..."), defaultDir = os.getcwd(),
-                            defaultFile = "grass_cmd_history.txt", wildcard = wildcard,
-                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
-
-        # Show the dialog and retrieve the user response. If it is the OK response,
-        # process the data.
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-
-            output = open(path, "w")
-            output.write(self.history)
-            output.close()
-
-        dlg.Destroy()
-
-    def GetCmd(self):
-        """!Get running command or None"""
-        return self.requestQ.get()
-    
-    def SetCopyingOfSelectedText(self, copy):
-        """!Enable or disable copying of selected text in to clipboard.
-        Effects prompt and output.
-        
-        @param copy True for enable, False for disable
-        """
-        if copy:
-            self.cmdPrompt.Bind(wx.stc.EVT_STC_PAINTED, self.cmdPrompt.OnTextSelectionChanged)
-            self.cmdOutput.Bind(wx.stc.EVT_STC_PAINTED, self.cmdOutput.OnTextSelectionChanged)
-        else:
-            self.cmdPrompt.Unbind(wx.stc.EVT_STC_PAINTED)
-            self.cmdOutput.Unbind(wx.stc.EVT_STC_PAINTED)
-        
-    def OnUpdateStatusBar(self, event):
-        """!Update statusbar text"""
-        if event.GetString():
-            nItems = len(self.cmdPrompt.GetCommandItems())
-            self.parent.SetStatusText(_('%d modules match') % nItems, 0)
-        else:
-            self.parent.SetStatusText('', 0)
-        
-        event.Skip()
-
-    def OnCmdOutput(self, event):
-        """!Print command output"""
-        message = event.text
-        type  = event.type
-        if self._notebook.GetSelection() != self._notebook.GetPageIndexByName('output'):
-            page = self._notebook.GetPageIndexByName('output')
-            textP = self._notebook.GetPageText(page)
-            if textP[-1] != ')':
-                textP += ' (...)'
-            self._notebook.SetPageText(page, textP)
-        
-        # message prefix
-        if type == 'warning':
-            messege = 'WARNING: ' + message
-        elif type == 'error':
-            message = 'ERROR: ' + message
-        
-        p1 = self.cmdOutput.GetEndStyled()
-        self.cmdOutput.GotoPos(p1)
-        
-        if '\b' in message:
-            if self.linepos < 0:
-                self.linepos = p1
-            last_c = ''
-            for c in message:
-                if c == '\b':
-                    self.linepos -= 1
-                else:
-                    if c == '\r':
-                        pos = self.cmdOutput.GetCurLine()[1]
-                        # self.cmdOutput.SetCurrentPos(pos)
-                    else:
-                        self.cmdOutput.SetCurrentPos(self.linepos)
-                    self.cmdOutput.ReplaceSelection(c)
-                    self.linepos = self.cmdOutput.GetCurrentPos()
-                    if c != ' ':
-                        last_c = c
-            if last_c not in ('0123456789'):
-                self.cmdOutput.AddTextWrapped('\n', wrap = None)
-                self.linepos = -1
-        else:
-            self.linepos = -1 # don't force position
-            if '\n' not in message:
-                self.cmdOutput.AddTextWrapped(message, wrap = 60)
-            else:
-                self.cmdOutput.AddTextWrapped(message, wrap = None)
-
-        p2 = self.cmdOutput.GetCurrentPos()
-        
-        if p2 >= p1:
-            self.cmdOutput.StartStyling(p1, 0xff)
-        
-            if type == 'error':
-                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleError)
-            elif type == 'warning':
-                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleWarning)
-            elif type == 'message':
-                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleMessage)
-            else: # unknown
-                self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleUnknown)
-        
-        self.cmdOutput.EnsureCaretVisible()
-        
-    def OnCmdProgress(self, event):
-        """!Update progress message info"""
-        self.progressbar.SetValue(event.value)
-
-    def OnCmdAbort(self, event):
-        """!Abort running command"""
-        self.cmdThread.abort()
-        
-    def OnCmdRun(self, event):
-        """!Run command"""
-        if self.parent.GetName() == 'Modeler':
-            self.parent.OnCmdRun(event)
-        
-        self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
-        self.btnCmdAbort.Enable()
-
-    def OnCmdPrepare(self, event):
-        """!Prepare for running command"""
-        if self.parent.GetName() == 'Modeler':
-            self.parent.OnCmdPrepare(event)
-        
-        event.Skip()
-        
-    def OnCmdDone(self, event):
-        """!Command done (or aborted)"""
-        if self.parent.GetName() == 'Modeler':
-            self.parent.OnCmdDone(event)
-        
-        if event.aborted:
-            # Thread aborted (using our convention of None return)
-            self.WriteLog(_('Please note that the data are left in inconsistent state '
-                            'and may be corrupted'), self.cmdOutput.StyleWarning)
-            self.WriteCmdLog('(%s) %s (%d sec)' % (str(time.ctime()),
-                                                   _('Command aborted'),
-                                                   (time.time() - event.time)))
-            # pid=self.cmdThread.requestId)
-            self.btnCmdAbort.Enable(False)
-        else:
-            try:
-                # Process results here
-                ctime = time.time() - event.time
-                if ctime < 60:
-                    stime = _("%d sec") % int(ctime)
-                else:
-                    mtime = int(ctime / 60)
-                    stime = _("%d min %d sec") % (mtime, 
-                                                  int(ctime - (mtime * 60)))
-                
-                self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()),
-                                                   _('Command finished'),
-                                                   (stime)))
-            except KeyError:
-                # stopped deamon
-                pass
-
-            self.btnCmdAbort.Enable(False)
-        
-        if event.onDone:
-            event.onDone(cmd = event.cmd, returncode = event.returncode)
-        
-        self.progressbar.SetValue(0) # reset progress bar on '0%'
-
-        self.cmdOutputTimer.Stop()
-
-        if event.cmd[0] == 'g.gisenv':
-            Debug.SetLevel()
-            self.Redirect()
-        
-        if self.parent.GetName() == "LayerManager":
-            self.btnCmdAbort.Enable(False)
-            if event.cmd[0] not in globalvar.grassCmd['all'] or \
-                    event.cmd[0] == 'r.mapcalc':
-                return
-            
-            display = self.parent.GetLayerTree().GetMapDisplay()
-            if not display or not display.IsAutoRendered():
-                return
-            mapLayers = map(lambda x: x.GetName(),
-                            display.GetMap().GetListOfLayers(l_type = 'raster') +
-                            display.GetMap().GetListOfLayers(l_type = 'vector'))
-            
-            try:
-                task = menuform.GUI(show = None).ParseCommand(event.cmd)
-            except gcmd.GException:
-                task = None
-                return
-            
-            for p in task.get_options()['params']:
-                if p.get('prompt', '') not in ('raster', 'vector'):
-                    continue
-                mapName = p.get('value', '')
-                if '@' not in mapName:
-                    mapName = mapName + '@' + grass.gisenv()['MAPSET']
-                if mapName in mapLayers:
-                    display.GetWindow().UpdateMap(render = True)
-                    return
-        elif self.parent.GetName() == 'Modeler':
-            pass
-        else: # standalone dialogs
-            dialog = self.parent.parent
-            if hasattr(self.parent.parent, "btn_abort"):
-                dialog.btn_abort.Enable(False)
-            
-            if hasattr(self.parent.parent, "btn_cancel"):
-                dialog.btn_cancel.Enable(True)
-            
-            if hasattr(self.parent.parent, "btn_clipboard"):
-                dialog.btn_clipboard.Enable(True)
-            
-            if hasattr(self.parent.parent, "btn_help"):
-                dialog.btn_help.Enable(True)
-            
-            if hasattr(self.parent.parent, "btn_run"):
-                dialog.btn_run.Enable(True)
-            
-            if event.returncode == 0 and not event.aborted:
-                try:
-                    winName = self.parent.parent.parent.GetName()
-                except AttributeError:
-                    winName = ''
-                
-                if winName == 'LayerManager':
-                    mapTree = self.parent.parent.parent.GetLayerTree()
-                elif winName == 'LayerTree':
-                    mapTree = self.parent.parent.parent
-                elif winName: # GMConsole
-                    mapTree = self.parent.parent.parent.parent.GetLayerTree()
-                else:
-                    mapTree = None
-                
-                cmd = dialog.notebookpanel.createCmd(ignoreErrors = True)
-                if hasattr(dialog, "addbox") and dialog.addbox.IsChecked():
-                    # add created maps into layer tree
-                    for p in dialog.task.get_options()['params']:
-                        prompt = p.get('prompt', '')
-                        if prompt in ('raster', 'vector', '3d-raster') and \
-                                p.get('age', 'old') == 'new' and \
-                                p.get('value', None):
-                            name, found = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
-                                                                    param = p.get('name', ''))
-                            
-                            if mapTree.GetMap().GetListOfLayers(l_name = name):
-                                continue
-                            
-                            if prompt == 'raster':
-                                lcmd = ['d.rast',
-                                        'map=%s' % name]
-                            else:
-                                lcmd = ['d.vect',
-                                        'map=%s' % name]
-                            mapTree.AddLayer(ltype = prompt,
-                                             lcmd = lcmd,
-                                             lname = name)
-            
-            if hasattr(dialog, "get_dcmd") and \
-                    dialog.get_dcmd is None and \
-                    hasattr(dialog, "closebox") and \
-                    dialog.closebox.IsChecked() and \
-                    (event.returncode == 0 or event.aborted):
-                self.cmdOutput.Update()
-                time.sleep(2)
-                dialog.Close()
-        
-    def OnProcessPendingOutputWindowEvents(self, event):
-        self.ProcessPendingEvents()
-
-    def ResetFocus(self):
-        """!Reset focus"""
-        self.cmdPrompt.SetFocus()
-        
-class GMStdout:
-    """!GMConsole standard output
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, parent):
-        self.parent = parent # GMConsole
-
-    def write(self, s):
-        if len(s) == 0 or s == '\n':
-            return
-
-        for line in s.splitlines():
-            if len(line) == 0:
-                continue
-            
-            evt = wxCmdOutput(text = line + '\n',
-                              type = '')
-            wx.PostEvent(self.parent.cmdOutput, evt)
-        
-class GMStderr:
-    """!GMConsole standard error output
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, parent):
-        self.parent = parent # GMConsole
-        
-        self.type = ''
-        self.message = ''
-        self.printMessage = False
-        
-    def flush(self):
-        pass
-    
-    def write(self, s):
-        if "GtkPizza" in s:
-            return
-        
-        # remove/replace escape sequences '\b' or '\r' from stream
-        progressValue = -1
-        
-        for line in s.splitlines():
-            if len(line) == 0:
-                continue
-            
-            if 'GRASS_INFO_PERCENT' in line:
-                value = int(line.rsplit(':', 1)[1].strip())
-                if value >= 0 and value < 100:
-                    progressValue = value
-                else:
-                    progressValue = 0
-            elif 'GRASS_INFO_MESSAGE' in line:
-                self.type = 'message'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_WARNING' in line:
-                self.type = 'warning'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_ERROR' in line:
-                self.type = 'error'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_END' in line:
-                self.printMessage = True
-            elif self.type == '':
-                if len(line) == 0:
-                    continue
-                evt = wxCmdOutput(text = line,
-                                  type = '')
-                wx.PostEvent(self.parent.cmdOutput, evt)
-            elif len(line) > 0:
-                self.message += line.strip() + '\n'
-
-            if self.printMessage and len(self.message) > 0:
-                evt = wxCmdOutput(text = self.message,
-                                  type = self.type)
-                wx.PostEvent(self.parent.cmdOutput, evt)
-
-                self.type = ''
-                self.message = ''
-                self.printMessage = False
-
-        # update progress message
-        if progressValue > -1:
-            # self.gmgauge.SetValue(progressValue)
-            evt = wxCmdProgress(value = progressValue)
-            wx.PostEvent(self.parent.progressbar, evt)
-            
-class GMStc(wx.stc.StyledTextCtrl):
-    """!Styled GMConsole
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """    
-    def __init__(self, parent, id, margin = False, wrap = None):
-        wx.stc.StyledTextCtrl.__init__(self, parent, id)
-        self.parent = parent
-        self.SetUndoCollection(True)
-        self.SetReadOnly(True)
-
-        #
-        # styles
-        #                
-        self.SetStyle()
-        
-        #
-        # line margins
-        #
-        # TODO print number only from cmdlog
-        self.SetMarginWidth(1, 0)
-        self.SetMarginWidth(2, 0)
-        if margin:
-            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
-            self.SetMarginWidth(0, 30)
-        else:
-            self.SetMarginWidth(0, 0)
-
-        #
-        # miscellaneous
-        #
-        self.SetViewWhiteSpace(False)
-        self.SetTabWidth(4)
-        self.SetUseTabs(False)
-        self.UsePopUp(True)
-        self.SetSelBackground(True, "#FFFF00")
-        self.SetUseHorizontalScrollBar(True)
-
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
-        
-    def OnTextSelectionChanged(self, event):
-        """!Copy selected text to clipboard and skip event.
-        The same function is in TextCtrlAutoComplete class (prompt.py).
-        """
-        self.Copy()
-        event.Skip()
-        
-    def SetStyle(self):
-        """!Set styles for styled text output windows with type face 
-        and point size selected by user (Courier New 10 is default)"""
-
-        settings = preferences.Settings()
-        
-        typeface = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'type')   
-        if typeface == "":
-            typeface = "Courier New"
-        
-        typesize = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'size')
-        if typesize == None or typesize <= 0:
-            typesize = 10
-        typesize = float(typesize)
-        
-        self.StyleDefault     = 0
-        self.StyleDefaultSpec = "face:%s,size:%d,fore:#000000,back:#FFFFFF" % (typeface, typesize)
-        self.StyleCommand     = 1
-        self.StyleCommandSpec = "face:%s,size:%d,,fore:#000000,back:#bcbcbc" % (typeface, typesize)
-        self.StyleOutput      = 2
-        self.StyleOutputSpec  = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
-        # fatal error
-        self.StyleError       = 3
-        self.StyleErrorSpec   = "face:%s,size:%d,,fore:#7F0000,back:#FFFFFF" % (typeface, typesize)
-        # warning
-        self.StyleWarning     = 4
-        self.StyleWarningSpec = "face:%s,size:%d,,fore:#0000FF,back:#FFFFFF" % (typeface, typesize)
-        # message
-        self.StyleMessage     = 5
-        self.StyleMessageSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
-        # unknown
-        self.StyleUnknown     = 6
-        self.StyleUnknownSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
-        
-        # default and clear => init
-        self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.StyleDefaultSpec)
-        self.StyleClearAll()
-        self.StyleSetSpec(self.StyleCommand, self.StyleCommandSpec)
-        self.StyleSetSpec(self.StyleOutput,  self.StyleOutputSpec)
-        self.StyleSetSpec(self.StyleError,   self.StyleErrorSpec)
-        self.StyleSetSpec(self.StyleWarning, self.StyleWarningSpec)
-        self.StyleSetSpec(self.StyleMessage, self.StyleMessageSpec)
-        self.StyleSetSpec(self.StyleUnknown, self.StyleUnknownSpec)        
-
-    def OnDestroy(self, evt):
-        """!The clipboard contents can be preserved after
-        the app has exited"""
-        
-        wx.TheClipboard.Flush()
-        evt.Skip()
-
-    def AddTextWrapped(self, txt, wrap = None):
-        """!Add string to text area.
-
-        String is wrapped and linesep is also added to the end
-        of the string"""
-        # allow writing to output window
-        self.SetReadOnly(False)
-        
-        if wrap:
-            txt = textwrap.fill(txt, wrap) + '\n'
-        else:
-            if txt[-1] != '\n':
-                txt += '\n'
-        
-        if '\r' in txt:
-            self.parent.linePos = -1
-            for seg in txt.split('\r'):
-                if self.parent.linePos > -1:
-                    self.SetCurrentPos(self.parent.linePos)
-                    self.ReplaceSelection(seg)
-                else:
-                    self.parent.linePos = self.GetCurrentPos()
-                    self.AddText(seg)
-        else:
-            self.parent.linePos = self.GetCurrentPos()
-            try:
-                self.AddText(txt)
-            except UnicodeDecodeError:
-                enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
-                if enc:
-                    txt = unicode(txt, enc)
-                elif 'GRASS_DB_ENCODING' in os.environ:
-                    txt = unicode(txt, os.environ['GRASS_DB_ENCODING'])
-                else:
-                    txt = utils.EncodeString(txt)
-                
-                self.AddText(txt)
-        
-        # reset output window to read only
-        self.SetReadOnly(True)
-    

Deleted: grass/trunk/gui/wxpython/gui_modules/gpyshell.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gpyshell.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gpyshell.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,113 +0,0 @@
-"""!
- at package gpyshell.py
-
- at brief wxGUI Interactive Python Shell
-
-Classes:
- - PyShellWindow
-
- at todo run pyshell and evaluate code in a separate instance of python
-& design the widget communicate back and forth with it
-
-(C) 2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-
-import wx
-from wx.py.shell import Shell as PyShell
-from wx.py.version import VERSION
-
-import grass.script as grass
-
-class PyShellWindow(wx.Panel):
-    """!Python Shell Window"""
-    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
-        self.parent = parent # GMFrame
-        
-        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
-        
-        self.intro = _("Welcome to wxGUI Interactive Python Shell %s") % VERSION + "\n\n" + \
-            _("Type %s for more GRASS scripting related information.") % "\"help(grass)\"" + "\n" + \
-            _("Type %s to add raster or vector to the layer tree.") % "\"AddLayer()\"" + "\n\n"
-        self.shell = PyShell(parent = self, id = wx.ID_ANY,
-                             introText = self.intro, locals = {'grass' : grass,
-                                                               'AddLayer' : self.AddLayer})
-        
-        sys.displayhook = self._displayhook
-        
-        self.btnClear = wx.Button(self, wx.ID_CLEAR)
-        self.btnClear.Bind(wx.EVT_BUTTON, self.OnClear)
-        self.btnClear.SetToolTipString(_("Delete all text from the shell"))
-                
-        self._layout()
-        
-    def _displayhook(self, value):
-        print value # do not modify __builtin__._
-        
-    def _layout(self):
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        sizer.Add(item = self.shell, proportion = 1,
-                  flag = wx.EXPAND)
-        
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = self.btnClear, proportion = 0,
-                     flag = wx.EXPAND | wx.RIGHT, border = 5)
-        sizer.Add(item = btnSizer, proportion = 0,
-                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        
-        sizer.Fit(self)
-        sizer.SetSizeHints(self)
-        
-        self.SetSizer(sizer)
-        
-        self.Fit()
-        self.SetAutoLayout(True)        
-        self.Layout()
-
-    def AddLayer(self, name, ltype = 'auto'):
-        """!Add selected map to the layer tree
-
-        @param name name of raster/vector map to be added
-        @param type map type ('raster', 'vector', 'auto' for autodetection)
-        """
-        fname = None
-        if ltype == 'raster' or ltype != 'vector':
-            # check for raster
-            fname = grass.find_file(name, element = 'cell')['fullname']
-            if fname:
-                ltype = 'raster'
-                lcmd = 'd.rast'
-        
-        if not fname and (ltype == 'vector' or ltype != 'raster'):
-            # if not found check for vector
-            fname = grass.find_file(name, element = 'vector')['fullname']
-            if fname:
-                ltype = 'vector'
-                lcmd = 'd.vect'
-        
-        if not fname:
-            return _("Raster or vector map <%s> not found") % (name)
-        
-        self.parent.GetLayerTree().AddLayer(ltype = ltype,
-                                            lname = fname,
-                                            lchecked = True,
-                                            lcmd = [lcmd, 'map=%s' % fname])
-        if ltype == 'raster':
-            return _('Raster map <%s> added') % fname
-        
-        return _('Vector map <%s> added') % fname
-    
-    def OnClear(self, event):
-        """!Delete all text from the shell
-        """
-        self.shell.clear()
-        self.shell.showIntro(self.intro)
-        self.shell.prompt()

Deleted: grass/trunk/gui/wxpython/gui_modules/gselect.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gselect.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/gselect.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1840 +0,0 @@
-"""!
- at package gselect
-
- at brief Custom control that selects elements
-
-Classes:
- - Select
- - VectorSelect
- - TreeCrtlComboPopup
- - VectorDBInfo
- - LayerSelect
- - DriverSelect
- - DatabaseSelect
- - ColumnSelect
- - DbaseSelect
- - LocationSelect
- - MapsetSelect
- - SubGroupSelect
- - FormatSelect
- - GdalSelect
- - ProjSelect
- - ElementSelect
- - OgrTypeSelect
-
-(C) 2007-2011 by the GRASS Development Team This program is free
-software under the GNU General Public License (>=v2). Read the file
-COPYING that comes with GRASS for details.
-
- at author Michael Barton
- at author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
-"""
-
-import os
-import sys
-import glob
-
-import wx
-import wx.combo
-import wx.lib.filebrowsebutton as filebrowse
-from wx.lib.newevent import NewEvent
-
-import globalvar
-
-sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
-import grass.script as grass
-from   grass.script import task as gtask
-
-import gcmd
-import utils
-from preferences import globalSettings as UserSettings
-from debug       import Debug
-
-wxGdalSelect, EVT_GDALSELECT = NewEvent()
-
-class Select(wx.combo.ComboCtrl):
-    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                 type = None, multiple = False, mapsets = None,
-                 updateOnPopup = True, onPopup = None,
-                 fullyQualified = True):
-        """!Custom control to create a ComboBox with a tree control to
-        display and select GIS elements within acessible mapsets.
-        Elements can be selected with mouse. Can allow multiple
-        selections, when argument multiple=True. Multiple selections
-        are separated by commas.
-
-        @param type type of GIS elements ('raster, 'vector', ...)
-        @param multiple multiple input allowed?
-        @param mapsets force list of mapsets (otherwise search path)
-        @param updateOnPopup True for updating list of elements on popup
-        @param onPopup function to be called on Popup
-        @param fullyQualified True to provide fully qualified names (map at mapset)
-        """
-        wx.combo.ComboCtrl.__init__(self, parent=parent, id=id, size=size)
-        self.GetChildren()[0].SetName("Select")
-        self.GetChildren()[0].type = type
-        
-        self.tcp = TreeCtrlComboPopup()
-        self.SetPopupControl(self.tcp)
-        self.SetPopupExtents(0, 100)
-        if type:
-            self.tcp.SetData(type = type, mapsets = mapsets,
-                             multiple = multiple,
-                             updateOnPopup = updateOnPopup, onPopup = onPopup,
-                             fullyQualified = fullyQualified)
-        self.GetChildren()[0].Bind(wx.EVT_KEY_UP, self.OnKeyUp)
-     
-    def OnKeyUp(self, event):
-        """!Shows popupwindow if down arrow key is released"""
-        if event.GetKeyCode() == wx.WXK_DOWN:
-            self.ShowPopup() 
-        else:
-            event.Skip()
-        
-    def SetElementList(self, type, mapsets = None):
-        """!Set element list
-
-        @param type GIS element type
-        @param mapsets list of acceptable mapsets (None for all in search path)
-        """
-        self.tcp.SetData(type = type, mapsets = mapsets)
-        
-    def GetElementList(self):
-        """!Load elements"""
-        self.tcp.GetElementList()
-    
-    def SetType(self, etype, multiple = False, mapsets = None,
-                updateOnPopup = True, onPopup = None):
-        """!Param set element type for widget
-
-        @param etype element type, see gselect.ElementSelect
-        """
-        self.tcp.SetData(type = etype, mapsets = mapsets,
-                         multiple = multiple,
-                         updateOnPopup = updateOnPopup, onPopup = onPopup)
-        
-class VectorSelect(Select):
-    def __init__(self, parent, ftype, **kwargs):
-        """!Custom to create a ComboBox with a tree control to display and
-        select vector maps. Control allows to filter vector maps. If you
-        don't need this feature use Select class instead
-        
-        @ftype filter vector maps based on feature type
-        """
-        Select.__init__(self, parent = parent, id = wx.ID_ANY,
-                        type = 'vector', **kwargs)
-        
-        self.ftype = ftype
-        
-        # remove vector maps which do not contain given feature type
-        self.tcp.SetFilter(self._isElement)
-        
-    def _isElement(self, vectorName):
-        """!Check if element should be filtered out"""
-        try:
-            if int(grass.vector_info_topo(vectorName)[self.ftype]) < 1:
-                return False
-        except KeyError:
-            return False
-        
-        return True
-
-class TreeCtrlComboPopup(wx.combo.ComboPopup):
-    """!Create a tree ComboBox for selecting maps and other GIS elements
-    in accessible mapsets within the current location
-    """
-    # overridden ComboPopup methods
-    def Init(self):
-        self.value = [] # for multiple is False -> len(self.value) in [0,1]
-        self.curitem = None
-        self.multiple = False
-        self.type = None
-        self.mapsets = None
-        self.updateOnPopup = True
-        self.onPopup = None
-        self.fullyQualified = True
-        
-        self.SetFilter(None)
-        
-    def Create(self, parent):
-        self.seltree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT
-                                   |wx.TR_HAS_BUTTONS
-                                   |wx.TR_SINGLE
-                                   |wx.TR_LINES_AT_ROOT
-                                   |wx.SIMPLE_BORDER
-                                   |wx.TR_FULL_ROW_HIGHLIGHT)
-        self.seltree.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
-        self.seltree.Bind(wx.EVT_MOTION, self.OnMotion)
-        self.seltree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
-        self.seltree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.mapsetExpanded)
-        self.seltree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.mapsetCollapsed)
-        self.seltree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.mapsetActivated)
-        self.seltree.Bind(wx.EVT_TREE_SEL_CHANGED, self.mapsetSelected)
-        self.seltree.Bind(wx.EVT_TREE_DELETE_ITEM, lambda x: None)
-        
-    # the following dummy handler are needed to keep tree events from propagating up to
-    # the parent GIS Manager layer tree
-    def mapsetExpanded(self, event):
-        pass
-
-    def mapsetCollapsed(self, event):
-        pass
-
-    def mapsetActivated(self, event):
-        pass
-
-    def mapsetSelected(self, event):
-        pass
-    # end of dummy events
-
-    def GetControl(self):
-        return self.seltree
-
-    def GetStringValue(self):
-        """!Get value as a string separated by commas"""
-        return ','.join(self.value)
-    
-    def SetFilter(self, filter):
-        """!Set filter for GIS elements, see e.g. VectorSelect"""
-        self.filterElements = filter
-    
-    def OnPopup(self, force = False):
-        """!Limited only for first selected"""
-        if not force and not self.updateOnPopup:
-            return
-        if self.onPopup:
-            selected, exclude = self.onPopup(self.type)
-        else:
-            selected = None
-            exclude  = False
- 
-        self.GetElementList(selected, exclude)
-        
-        # selects map starting according to written text
-        inputText = self.GetCombo().GetValue().strip()
-        if inputText:
-            root = self.seltree.GetRootItem()
-            match = self.FindItem(root, inputText, startLetters = True)
-            self.seltree.EnsureVisible(match)
-            self.seltree.SelectItem(match)
-            
-      
-    def GetElementList(self, elements = None, exclude = False):
-        """!Get filtered list of GIS elements in accessible mapsets
-        and display as tree with all relevant elements displayed
-        beneath each mapset branch
-        """
-        # update list
-        self.seltree.DeleteAllItems()
-        self._getElementList(self.type, self.mapsets, elements, exclude)
-        
-        if len(self.value) > 0:
-            root = self.seltree.GetRootItem()
-            if not root:
-                return
-            item = self.FindItem(root, self.value[0])
-            try:
-                self.seltree.EnsureVisible(item)
-                self.seltree.SelectItem(item)
-            except:
-                pass
-            
-    def SetStringValue(self, value):
-        # this assumes that item strings are unique...
-        root = self.seltree.GetRootItem()
-        if not root:
-            return
-        found = self.FindItem(root, value)
-        winValue = self.GetCombo().GetValue().strip(',')
-        self.value = []
-        if winValue:
-            self.value = winValue.split(',')
-        
-        if found:
-            self.value.append(found)
-            self.seltree.SelectItem(found)
-        
-    def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
-        """!Reads UserSettings to get height (which was 200 in old implementation).
-        """
-        height = UserSettings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
-        return wx.Size(minWidth, min(height, maxHeight))
-
-    def _getElementList(self, element, mapsets = None, elements = None, exclude = False):
-        """!Get list of GIS elements in accessible mapsets and display as tree
-        with all relevant elements displayed beneath each mapset branch
-
-        @param element GIS element
-        @param mapsets list of acceptable mapsets (None for all mapsets in search path)
-        @param elements list of forced GIS elements
-        @param exclude True to exclude, False for forcing the list (elements)
-        """
-        # get current mapset
-        curr_mapset = grass.gisenv()['MAPSET']
-        
-        # map element types to g.mlist types
-        elementdict = {'cell':'rast',
-                       'raster':'rast',
-                       'rast':'rast',
-                       'raster files':'rast',
-                       'grid3':'rast3d',
-                       'rast3d':'rast3d',
-                       '3d-raster':'rast3d',
-                       'raster3D':'rast3d',
-                       'raster3D files':'rast3d',
-                       'vector':'vect',
-                       'vect':'vect',
-                       'binary vector files':'vect',
-                       'dig':'oldvect',
-                       'oldvect':'oldvect',
-                       'old vector':'oldvect',
-                       'dig_ascii':'asciivect',
-                       'asciivect':'asciivect',
-                       'asciivector':'asciivect',
-                       'ascii vector files':'asciivect',
-                       'icons':'icon',
-                       'icon':'icon',
-                       'paint icon files':'icon',
-                       'paint/labels':'labels',
-                       'labels':'labels',
-                       'label':'labels',
-                       'paint label files':'labels',
-                       'site_lists':'sites',
-                       'sites':'sites',
-                       'site list':'sites',
-                       'site list files':'sites',
-                       'windows':'region',
-                       'region':'region',
-                       'region definition':'region',
-                       'region definition files':'region',
-                       'windows3d':'region3d',
-                       'region3d':'region3d',
-                       'region3D definition':'region3d',
-                       'region3D definition files':'region3d',
-                       'group':'group',
-                       'imagery group':'group',
-                       'imagery group files':'group',
-                       '3d.view':'3dview',
-                       '3dview':'3dview',
-                       '3D viewing parameters':'3dview',
-                       '3D view parameters':'3dview'}
-        
-        if element not in elementdict:
-            self.AddItem(_('Not selectable element'))
-            return
-        
-        if globalvar.have_mlist:
-            filesdict = grass.mlist_grouped(elementdict[element],
-                                            check_search_path = False)
-        else:
-            filesdict = grass.list_grouped(elementdict[element],
-                                           check_search_path = False)
-        
-        # list of mapsets in current location
-        if mapsets is None:
-            mapsets = grass.mapsets(search_path = True)
-        
-        # current mapset first
-        if curr_mapset in mapsets and mapsets[0] != curr_mapset:
-            mapsets.remove(curr_mapset)
-            mapsets.insert(0, curr_mapset)
-        
-        first_mapset = None
-        for mapset in mapsets:
-            mapset_node = self.AddItem(_('Mapset') + ': ' + mapset)
-            if not first_mapset:
-                first_mapset = mapset_node
-            
-            self.seltree.SetItemTextColour(mapset_node, wx.Colour(50, 50, 200))
-            if mapset not in filesdict:
-                continue
-            try:
-                elem_list = filesdict[mapset]
-                elem_list.sort()
-                for elem in elem_list:
-                    if elem != '':
-                        fullqElem = elem + '@' + mapset
-                        if elements is not None:
-                            if (exclude and fullqElem in elements) or \
-                                    (not exclude and fullqElem not in elements):
-                                continue
-                        
-                        if self.filterElements:
-                            if self.filterElements(fullqElem):
-                                self.AddItem(elem, parent = mapset_node)
-                        else:
-                            self.AddItem(elem, parent = mapset_node)
-            except StandardError, e:
-                sys.stderr.write(_("GSelect: invalid item: %s") % e)
-                continue
-            
-            if self.seltree.ItemHasChildren(mapset_node):
-                sel = UserSettings.Get(group='appearance', key='elementListExpand',
-                                       subkey='selection')
-                collapse = True
-
-                if sel == 0: # collapse all except PERMANENT and current
-                    if mapset in ('PERMANENT', curr_mapset):
-                        collapse = False
-                elif sel == 1: # collapse all except PERMANENT
-                    if mapset == 'PERMANENT':
-                        collapse = False
-                elif sel == 2: # collapse all except current
-                    if mapset == curr_mapset:
-                        collapse = False
-                elif sel == 3: # collapse all
-                    pass
-                elif sel == 4: # expand all
-                    collapse = False
-                
-                if collapse:
-                    self.seltree.Collapse(mapset_node)
-                else:
-                    self.seltree.Expand(mapset_node)
-        
-        if first_mapset:
-            # select first mapset (MSW hack)
-            self.seltree.SelectItem(first_mapset)
-    
-    # helpers
-    def FindItem(self, parentItem, text, startLetters = False):
-        """!Finds item with given name or starting with given text"""
-        startletters = startLetters
-        item, cookie = self.seltree.GetFirstChild(parentItem)
-        while wx.TreeItemId.IsOk(item):
-            if self.seltree.GetItemText(item) == text:
-                return item
-            if self.seltree.ItemHasChildren(item):
-                item = self.FindItem(item, text, startLetters = startletters)
-                if wx.TreeItemId.IsOk(item):
-                    return item
-            elif startletters and self.seltree.GetItemText(item).startswith(text.split('@', 1)[0]):
-                return item
-            item, cookie = self.seltree.GetNextChild(parentItem, cookie)
-        return wx.TreeItemId()
-    
-    def AddItem(self, value, parent=None):
-        if not parent:
-            root = self.seltree.GetRootItem()
-            if not root:
-                root = self.seltree.AddRoot("<hidden root>")
-            parent = root
-
-        item = self.seltree.AppendItem(parent, text=value)
-        return item
-    
-    # able to recieve only wx.EVT_KEY_UP
-    def OnKeyUp(self, event):
-        """!Enables to select items using keyboard"""
-        
-        item = self.seltree.GetSelection()
-        if event.GetKeyCode() == wx.WXK_DOWN:
-            self.seltree.SelectItem(self.seltree.GetNextVisible(item))
-            
-        # problem with GetPrevVisible   
-        elif event.GetKeyCode() == wx.WXK_UP: 
-            if self.seltree.ItemHasChildren(item) and self.seltree.IsExpanded(self.seltree.GetPrevSibling(item)):
-                itemPrev = self.seltree.GetLastChild(self.seltree.GetPrevSibling(item))
-            else:
-                itemPrev = self.seltree.GetPrevSibling(item)
-                if not wx.TreeItemId.IsOk(itemPrev):
-                    itemPrev = self.seltree.GetItemParent(item)
-                    if item == self.seltree.GetFirstChild(self.seltree.GetRootItem())[0]:
-                        itemPrev = item
-            self.seltree.SelectItem(itemPrev)
-        
-        # selects first item starting with the written text in next mapset
-        elif event.GetKeyCode() == wx.WXK_TAB:
-            selected = self.seltree.GetSelection()
-            if self.seltree.ItemHasChildren(selected):
-                parent = selected
-            else:
-                parent = self.seltree.GetItemParent(selected)
-            nextSibling = self.seltree.GetNextSibling(parent)
-            if wx.TreeItemId.IsOk(nextSibling):
-                match = self.FindItem(nextSibling, self.GetCombo().GetValue().strip(), True) 
-            else: 
-                match = self.FindItem(self.seltree.GetFirstChild(self.seltree.GetItemParent(parent))[0],
-                                        self.GetCombo().GetValue().strip(), True) 
-            self.seltree.SelectItem(match)
-            
-        elif event.GetKeyCode() == wx.WXK_RIGHT:
-            if self.seltree.ItemHasChildren(item):
-                self.seltree.Expand(item)
-        
-        elif event.GetKeyCode() == wx.WXK_LEFT:
-            if self.seltree.ItemHasChildren(item):
-                self.seltree.Collapse(item)
-                
-        elif event.GetKeyCode() == wx.WXK_ESCAPE:
-            self.Dismiss()
-            
-        elif event.GetKeyCode() == wx.WXK_RETURN:
-            if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
-                self.value = [] 
-            else:
-                mapsetItem = self.seltree.GetItemParent(item)
-                fullName = self.seltree.GetItemText(item)
-                if self.fullyQualified:
-                    fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
-                
-                if self.multiple is True:
-                    # text item should be unique
-                    self.value.append(fullName)
-                else:
-                    self.value = [fullName]
-            
-            self.Dismiss()
-        
-    def OnMotion(self, evt):
-        """!Have the selection follow the mouse, like in a real combobox
-        """
-        item, flags = self.seltree.HitTest(evt.GetPosition())
-        if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
-            self.seltree.SelectItem(item)
-            self.curitem = item
-        evt.Skip()
-
-    def OnLeftDown(self, evt):
-        """!Do the combobox selection
-        """
-        item, flags = self.seltree.HitTest(evt.GetPosition())
-        if item and flags & wx.TREE_HITTEST_ONITEMLABEL:
-            self.curitem = item
-            
-            if self.seltree.GetRootItem() == self.seltree.GetItemParent(item):
-                self.value = [] # cannot select mapset item
-            else:
-                mapsetItem = self.seltree.GetItemParent(item)
-                fullName = self.seltree.GetItemText(item)
-                if self.fullyQualified:
-                    fullName += '@' + self.seltree.GetItemText(mapsetItem).split(':', -1)[1].strip()
-                
-                if self.multiple is True:
-                    # text item should be unique
-                    self.value.append(fullName)
-                else:
-                    self.value = [fullName]
-            
-            self.Dismiss()
-        
-        evt.Skip()
-
-    def SetData(self, **kargs):
-        """!Set object properties"""
-        if 'type' in kargs:
-            self.type = kargs['type']
-        if 'mapsets' in kargs:
-            self.mapsets = kargs['mapsets']
-        if 'multiple' in kargs:
-            self.multiple = kargs['multiple']
-        if 'updateOnPopup' in kargs:
-            self.updateOnPopup = kargs['updateOnPopup']
-        if 'onPopup' in kargs:
-            self.onPopup = kargs['onPopup']
-        if 'fullyQualified' in kargs:
-            self.fullyQualified = kargs['fullyQualified']
-        
-    def GetType(self):
-        """!Get element type
-        """
-        return self.type
-    
-class VectorDBInfo:
-    """!Class providing information about attribute tables
-    linked to a vector map"""
-    def __init__(self, map):
-        self.map = map
-
-        # dictionary of layer number and associated (driver, database, table)
-        self.layers = {}
-         # dictionary of table and associated columns (type, length, values, ids)
-        self.tables = {}
-        
-        if not self._CheckDBConnection(): # -> self.layers
-            return
-
-        self._DescribeTables() # -> self.tables
-
-    def _CheckDBConnection(self):
-        """!Check DB connection"""
-        nuldev = file(os.devnull, 'w+')
-        self.layers = grass.vector_db(map = self.map, stderr = nuldev)
-        nuldev.close()
-        
-        return bool(len(self.layers.keys()) > 0)
-        
-    def _DescribeTables(self):
-        """!Describe linked tables"""
-        for layer in self.layers.keys():
-            # determine column names and types
-            table = self.layers[layer]["table"]
-            columns = {} # {name: {type, length, [values], [ids]}}
-            i = 0
-            Debug.msg(1, "gselect.VectorDBInfo._DescribeTables(): table=%s driver=%s database=%s" % \
-                          (self.layers[layer]["table"], self.layers[layer]["driver"],
-                           self.layers[layer]["database"]))
-            for item in grass.db_describe(table = self.layers[layer]["table"],
-                                          driver = self.layers[layer]["driver"],
-                                          database = self.layers[layer]["database"])['cols']:
-                name, type, length = item
-                # FIXME: support more datatypes
-                if type.lower() == "integer":
-                    ctype = int
-                elif type.lower() == "double precision":
-                    ctype = float
-                else:
-                    ctype = str
-
-                columns[name.strip()] = { 'index'  : i,
-                                          'type'   : type.lower(),
-                                          'ctype'  : ctype,
-                                          'length' : int(length),
-                                          'values' : [],
-                                          'ids'    : []}
-                i += 1
-            
-            # check for key column
-            # v.db.connect -g/p returns always key column name lowercase
-            if self.layers[layer]["key"] not in columns.keys():
-                for col in columns.keys():
-                    if col.lower() == self.layers[layer]["key"]:
-                        self.layers[layer]["key"] = col.upper()
-                        break
-            
-            self.tables[table] = columns
-            
-        return True
-    
-    def Reset(self):
-        """!Reset"""
-        for layer in self.layers:
-            table = self.layers[layer]["table"] # get table desc
-            columns = self.tables[table]
-            for name in self.tables[table].keys():
-                self.tables[table][name]['values'] = []
-                self.tables[table][name]['ids']    = []
-    
-    def GetName(self):
-        """!Get vector name"""
-        return self.map
-    
-    def GetKeyColumn(self, layer):
-        """!Get key column of given layer
-        
-        @param layer vector layer number
-        """
-        return str(self.layers[layer]['key'])
-    
-    def GetTable(self, layer):
-        """!Get table name of given layer
-        
-        @param layer vector layer number
-        """
-        return self.layers[layer]['table']
-    
-    def GetDbSettings(self, layer):
-        """!Get database settins
-
-        @param layer layer number
-        
-        @return (driver, database)
-        """
-        return self.layers[layer]['driver'], self.layers[layer]['database']
-    
-    def GetTableDesc(self, table):
-        """!Get table columns
-
-        @param table table name
-        """
-        return self.tables[table]
-
-class LayerSelect(wx.ComboBox):
-    def __init__(self, parent, id = wx.ID_ANY,
-                 size = globalvar.DIALOG_COMBOBOX_SIZE,
-                 vector = None, dsn = None, choices = [], all = False, default = None):
-        """!Creates combo box for selecting vector map layer names
-
-        @param vector vector map name (native or connected via v.external)
-        @param dsn    OGR data source name
-        """
-        super(LayerSelect, self).__init__(parent, id, size = size, choices = choices)
-
-        self.all = all
-        
-        self.SetName("LayerSelect")
-
-        # default value
-        self.default = default
-
-        self.InsertLayers(vector = vector, dsn = dsn)
-        
-    def InsertLayers(self, vector = None, dsn = None):
-        """!Insert layers for a vector into the layer combobox
-
-        @param vector vector map name (native or connected via v.external)
-        @param dsn    OGR data source name
-        """
-        layers = list()
-        if self.all:
-            layers.append('-1')
-
-        if vector:
-            # TODO: use Vect_get_field2() in C modules where possible
-            # currently the following is identical to
-            # layers = utils.GetVectorNumberOfLayers(self, vector)
-
-            ret = gcmd.RunCommand('v.db.connect',
-                                  read = True,
-                                  quiet = True,
-                                  fs = '|',
-                                  flags = 'g',
-                                  map = vector)
-            if ret:
-                for line in ret.splitlines():
-                    layerinfo = line.split('|')
-                    layername = layerinfo[0].split('/')
-                    # use this to get layer names
-                    # but only when all modules use Vect_get_field2()
-                    # which is not the case right now
-                    ### layers.append(layername[len(layername) - 1])
-                    layers.append(layername[0])
-
-        elif dsn:
-            ret = gcmd.RunCommand('v.in.ogr',
-                                  read = True,
-                                  quiet = True,
-                                  flags = 'l',
-                                  dsn = dsn)
-            if ret:
-                layers = ret.splitlines()
-    
-        if self.default:
-            if len(layers) == 0:
-                layers.insert(0, str(self.default))
-            elif self.default not in layers:
-                layers.append(self.default)
-
-        if len(layers) > 0:
-            self.SetItems(layers)
-        
-class DriverSelect(wx.ComboBox):
-    """!Creates combo box for selecting database driver.
-    """
-    def __init__(self, parent, choices, value,
-                 id=wx.ID_ANY, pos=wx.DefaultPosition,
-                 size=globalvar.DIALOG_LAYER_SIZE, **kargs):
-
-        super(DriverSelect, self).__init__(parent, id, value, pos, size,
-                                           choices, style=wx.CB_READONLY)
-        
-        self.SetName("DriverSelect")
-        
-        self.SetStringSelection(value)
-
-class DatabaseSelect(wx.TextCtrl):
-    """!Creates combo box for selecting database driver.
-    """
-    def __init__(self, parent, value='',
-                 id=wx.ID_ANY, pos=wx.DefaultPosition,
-                 size=globalvar.DIALOG_TEXTCTRL_SIZE, **kargs):
-        
-        super(DatabaseSelect, self).__init__(parent, id, value, pos, size)
-                               
-        self.SetName("DatabaseSelect")
-
-class TableSelect(wx.ComboBox):
-    """!Creates combo box for selecting attribute tables from the database
-    """
-    def __init__(self, parent,
-                 id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
-                 size=globalvar.DIALOG_COMBOBOX_SIZE,
-                 choices=[]):
-
-        super(TableSelect, self).__init__(parent, id, value, pos, size, choices,
-                                          style=wx.CB_READONLY)
-
-        self.SetName("TableSelect")
-
-        if not choices:
-            self.InsertTables()
-                
-    def InsertTables(self, driver=None, database=None):
-        """!Insert attribute tables into combobox"""
-        items = []
-
-        if not driver or not database:
-            connect = grass.db_connection()
-            
-            driver = connect['driver']
-            database = connect['database']
-        
-        ret = gcmd.RunCommand('db.tables',
-                              flags = 'p',
-                              read = True,
-                              driver = driver,
-                              database = database)
-        
-        if ret:
-            for table in ret.splitlines():
-                items.append(table)
-            
-        self.SetItems(items)
-        self.SetValue('')
-        
-class ColumnSelect(wx.ComboBox):
-    """!Creates combo box for selecting columns in the attribute table
-    for a vector map.
-
-    @param parent window parent
-    @param id window id
-    @param value default value
-    @param size window size
-    @param vector vector map name
-    @param layer layer number
-    @param param parameters list (see menuform.py)
-    @param **kwags wx.ComboBox parameters
-    """
-    def __init__(self, parent, id = wx.ID_ANY, value = '', 
-                 size=globalvar.DIALOG_COMBOBOX_SIZE,
-                 vector = None, layer = 1, param = None, **kwargs):
-        self.defaultValue = value
-        self.param = param
-        
-        super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
-        self.SetName("ColumnSelect")
-        
-        if vector:
-            self.InsertColumns(vector, layer)
-    
-    def InsertColumns(self, vector, layer, excludeKey = False, excludeCols = None, type = None, dbInfo = None):
-        """!Insert columns for a vector attribute table into the columns combobox
-
-        @param vector vector name
-        @param layer vector layer number
-        @param excludeKey exclude key column from the list?
-        @param excludeCols list of columns to be removed from the list
-        @param type only columns of given type (given as list)
-        """
-        if not dbInfo:
-            dbInfo = VectorDBInfo(vector)
-        
-        try:
-            table = dbInfo.GetTable(int(layer))
-            columnchoices = dbInfo.GetTableDesc(table)
-            keyColumn = dbInfo.GetKeyColumn(int(layer))
-            columns = len(columnchoices.keys()) * ['']
-            for key, val in columnchoices.iteritems():
-                columns[val['index']] = key
-            if excludeKey: # exclude key column
-                columns.remove(keyColumn)
-            if excludeCols: # exclude key column
-                for key in columnchoices.iterkeys():
-                    if key in excludeCols:
-                        columns.remove(key)
-            if type: # only selected column types
-                for key, value in columnchoices.iteritems():
-                    if value['type'] not in type:
-                        try:
-                            columns.remove(key)
-                        except ValueError:
-                            pass
-        except (KeyError, ValueError):
-            columns = list()
-            
-        self.SetItems(columns)
-        self.SetValue(self.defaultValue)
-        
-        if self.param:
-            self.param['value'] = ''
-        
-    def InsertTableColumns(self, table, driver=None, database=None):
-        """!Insert table columns
-
-        @param table table name
-        @param driver driver name
-        @param database database name
-        """
-        columns = list()
-        
-        ret = gcmd.RunCommand('db.columns',
-                              read = True,
-                              driver = driver,
-                              database = database,
-                              table = table)
-        
-        if ret:
-            columns = ret.splitlines()
-        
-        self.SetItems(columns)
-        self.SetValue(self.defaultValue)
-        
-        if self.param:
-            self.param['value'] = ''
-
-class DbaseSelect(wx.lib.filebrowsebutton.DirBrowseButton):
-    """!Widget for selecting GRASS Database"""
-    def __init__(self, parent, **kwargs):
-        super(DbaseSelect, self).__init__(parent, id = wx.ID_ANY,
-                                          size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
-                                          dialogTitle = _('Choose GIS Data Directory'),
-                                          buttonText = _('Browse'),
-                                          startDirectory = grass.gisenv()['GISDBASE'],
-                                          **kwargs)
-        
-class LocationSelect(wx.ComboBox):
-    """!Widget for selecting GRASS location"""
-    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
-                 gisdbase = None, **kwargs):
-        super(LocationSelect, self).__init__(parent, id, size = size, 
-                                             style = wx.CB_READONLY, **kwargs)
-        self.SetName("LocationSelect")
-        
-        if not gisdbase:
-            self.gisdbase = grass.gisenv()['GISDBASE']
-        else:
-            self.gisdbase = gisdbase
-        
-        self.SetItems(utils.GetListOfLocations(self.gisdbase))
-
-    def UpdateItems(self, dbase):
-        """!Update list of locations
-
-        @param dbase path to GIS database
-        """
-        self.gisdbase = dbase
-        if dbase:
-            self.SetItems(utils.GetListOfLocations(self.gisdbase))
-        else:
-            self.SetItems([])
-        
-class MapsetSelect(wx.ComboBox):
-    """!Widget for selecting GRASS mapset"""
-    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
-                 gisdbase = None, location = None, setItems = True,
-                 searchPath = False, new = False, **kwargs):
-        style = 0
-        if not new:
-            style = wx.CB_READONLY
-        super(MapsetSelect, self).__init__(parent, id, size = size, 
-                                           style = style, **kwargs)
-        self.searchPath = searchPath
-        
-        self.SetName("MapsetSelect")
-        if not gisdbase:
-            self.gisdbase = grass.gisenv()['GISDBASE']
-        else:
-            self.gisdbase = gisdbase
-        
-        if not location:
-            self.location = grass.gisenv()['LOCATION_NAME']
-        else:
-            self.location = location
-        
-        if setItems:
-            self.SetItems(self._getMapsets())
-        
-    def UpdateItems(self, location, dbase = None):
-        """!Update list of mapsets for given location
-
-        @param dbase path to GIS database (None to use currently selected)
-        @param location name of location
-        """
-        if dbase:
-            self.gisdbase = dbase
-        self.location = location
-        if location:
-            self.SetItems(self._getMapsets())
-        else:
-            self.SetItems([])
-     
-    def _getMapsets(self):
-        if self.searchPath:
-            return gcmd.RunCommand('g.mapsets',
-                                   read = True,
-                                   flags = 'p',
-                                   fs = 'newline').splitlines()
-        
-        return utils.GetListOfMapsets(self.gisdbase, self.location, selectable = False)
-            
-class SubGroupSelect(wx.ComboBox):
-    """!Widget for selecting subgroups"""
-    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE, 
-                 **kwargs):
-        super(SubGroupSelect, self).__init__(parent, id, size = size, 
-                                             style = wx.CB_READONLY, **kwargs)
-        self.SetName("SubGroupSelect")
-
-    def Insert(self, group):
-        """!Insert subgroups for defined group"""
-        if not group:
-            return
-        gisenv = grass.gisenv()
-        try:
-            name, mapset = group.split('@', 1)
-        except ValueError:
-            name = group
-            mapset = gisenv['MAPSET']
-        
-        path = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], mapset,
-                            'group', name, 'subgroup')
-        try:
-            self.SetItems(os.listdir(path))
-        except OSError:
-            self.SetItems([])
-        self.SetValue('')
-
-class FormatSelect(wx.Choice):
-    def __init__(self, parent, ogr = False,
-                 sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_SPIN_SIZE, 
-                 **kwargs):
-        """!Widget for selecting external (GDAL/OGR) format
-
-        @param parent parent window
-        @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
-        @param ogr True for OGR otherwise GDAL
-        """
-        super(FormatSelect, self).__init__(parent, id, size = size, 
-                                           style = wx.CB_READONLY, **kwargs)
-        self.SetName("FormatSelect")
-        
-        if ogr:
-            ftype = 'ogr'
-        else:
-            ftype = 'gdal'
-        
-        formats = list()
-        for f in utils.GetFormats()[ftype].values():
-            formats += f
-        self.SetItems(formats)
-        
-    def GetExtension(self, name):
-        """!Get file extension by format name"""
-        formatToExt = {
-            # raster
-            'GeoTIFF' : 'tif',
-            'Erdas Imagine Images (.img)' : 'img',
-            'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
-            'Arc/Info Binary Grid' : 'adf',
-            'Portable Network Graphics' : 'png',
-            'JPEG JFIF' : 'jpg',
-            'Japanese DEM (.mem)' : 'mem',
-            'Graphics Interchange Format (.gif)' : 'gif',
-            'X11 PixMap Format' : 'xpm',
-            'MS Windows Device Independent Bitmap' : 'bmp',
-            'SPOT DIMAP' : 'dim',
-            'RadarSat 2 XML Product' : 'xml',
-            'EarthWatch .TIL' : 'til',
-            'ERMapper .ers Labelled' : 'ers',
-            'ERMapper Compressed Wavelets' : 'ecw',
-            'GRIdded Binary (.grb)' : 'grb',
-            'EUMETSAT Archive native (.nat)' : 'nat',
-            'Idrisi Raster A.1' : 'rst',
-            'Golden Software ASCII Grid (.grd)' : 'grd',
-            'Golden Software Binary Grid (.grd)' : 'grd',
-            'Golden Software 7 Binary Grid (.grd)' : 'grd',
-            'R Object Data Store' : 'r',
-            'USGS DOQ (Old Style)' : 'doq',
-            'USGS DOQ (New Style)' : 'doq',
-            'ENVI .hdr Labelled' : 'hdr',
-            'ESRI .hdr Labelled' : 'hdr',
-            'Generic Binary (.hdr Labelled)' : 'hdr',
-            'PCI .aux Labelled' : 'aux',
-            'EOSAT FAST Format' : 'fst',
-            'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
-            'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
-            'Swedish Grid RIK (.rik)' : 'rik',
-            'USGS Optional ASCII DEM (and CDED)' : 'dem',
-            'Northwood Numeric Grid Format .grd/.tab' : '',
-            'Northwood Classified Grid Format .grc/.tab' : '',
-            'ARC Digitized Raster Graphics' : 'arc',
-            'Magellan topo (.blx)' : 'blx',
-            'SAGA GIS Binary Grid (.sdat)' : 'sdat',
-            # vector
-            'ESRI Shapefile' : 'shp',
-            'UK .NTF'        : 'ntf',
-            'SDTS'           : 'ddf',
-            'DGN'            : 'dgn',
-            'VRT'            : 'vrt',
-            'REC'            : 'rec',
-            'BNA'            : 'bna',
-            'CSV'            : 'csv',
-            'GML'            : 'gml',
-            'GPX'            : 'gpx',
-            'KML'            : 'kml',
-            'GMT'            : 'gmt',
-            'PGeo'           : 'mdb',
-            'XPlane'         : 'dat',
-            'AVCBin'         : 'adf',
-            'AVCE00'         : 'e00',
-            'DXF'            : 'dxf',
-            'Geoconcept'     : 'gxt',
-            'GeoRSS'         : 'xml',
-            'GPSTrackMaker'  : 'gtm',
-            'VFK'            : 'vfk'
-            }
-        
-        try:
-            return formatToExt[name]
-        except KeyError:
-            return ''
-        
-class GdalSelect(wx.Panel):
-    def __init__(self, parent, panel, ogr = False, dest = False, 
-                 default = 'file', exclude = [], envHandler = None):
-        """!Widget for selecting GDAL/OGR datasource, format
-        
-        @param parent parent window
-        @param ogr    use OGR selector instead of GDAL
-        @param dest   True for output (destination)
-        @param default deafult type (ignored when dest == True)
-        @param exclude list of types to be excluded
-        """
-        self.parent = parent
-        self.ogr    = ogr
-        self.dest   = dest 
-        wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
-
-        self.settingsBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                        label = " %s " % _("Settings"))
-        
-        self.inputBox = wx.StaticBox(parent = self, id = wx.ID_ANY)
-        if dest:
-            self.inputBox.SetLabel(" %s " % _("Output settings"))
-        else:
-            self.inputBox.SetLabel(" %s " % _("Source settings"))
-        
-        # source type
-        sources = list()
-        self.sourceMap = { 'file' : -1,
-                           'dir'  : -1,
-                           'db'   : -1,
-                           'pro'  : -1,
-                           'native' : -1 }
-        idx = 0
-        if dest:
-            sources.append(_("Native"))
-            self.sourceMap['native'] = idx
-            idx += 1
-        if 'file' not in exclude:
-            sources.append(_("File"))
-            self.sourceMap['file'] = idx
-            idx += 1
-        if 'directory' not in exclude:
-            sources.append(_("Directory"))
-            self.sourceMap['dir'] = idx
-            idx += 1
-        if 'database' not in exclude:
-            sources.append(_("Database"))
-            self.sourceMap['db'] = idx
-            idx += 1
-        if 'protocol' not in exclude:
-            sources.append(_("Protocol"))
-            self.sourceMap['pro'] = idx
-        
-        if self.ogr:
-            self.settingsFile = os.path.join(utils.GetSettingsPath(), 'wxOGR')
-        else:
-            self.settingsFile = os.path.join(utils.GetSettingsPath(), 'wxGDAL')
-        
-        self._settings = self._loadSettings()
-        self.settingsChoice = wx.Choice(parent = self, id = wx.ID_ANY)
-        self.settingsChoice.Bind(wx.EVT_CHOICE, self.OnSettingsLoad)
-        self.settingsChoice.SetItems(self._settings.keys())
-        self.btnSettings = wx.Button(parent = self, id = wx.ID_SAVE)
-        self.btnSettings.Bind(wx.EVT_BUTTON, self.OnSettingsSave)
-        
-        self.source = wx.RadioBox(parent = self, id = wx.ID_ANY,
-                                  style = wx.RA_SPECIFY_COLS,
-                                  choices = sources)
-        if dest:
-            self.source.SetLabel(" %s " % _('Output type'))
-        else:
-            self.source.SetLabel(" %s " % _('Source type'))
-        
-        self.source.SetSelection(0)
-        self.source.Bind(wx.EVT_RADIOBOX, self.OnSetType)
-        
-        # dsn widgets
-        if not ogr:
-            filemask = 'GeoTIFF (%s)|%s|%s (*.*)|*.*' % \
-                (self._getExtPattern('tif'), self._getExtPattern('tif'), _('All files'))
-        else:
-            filemask = 'ESRI Shapefile (%s)|%s|%s (*.*)|*.*' % \
-                (self._getExtPattern('shp'), self._getExtPattern('shp'), _('All files'))
-        
-        dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
-                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText = '',
-                                              dialogTitle=_('Choose file to import'),
-                                              buttonText=_('Browse'),
-                                              startDirectory=os.getcwd(),
-                                              changeCallback=self.OnSetDsn,
-                                              fileMask=filemask)
-        dsnFile.Hide()
-        
-        dsnDir = filebrowse.DirBrowseButton(parent=self, id=wx.ID_ANY, 
-                                            size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
-                                            dialogTitle=_('Choose input directory'),
-                                            buttonText=_('Browse'),
-                                            startDirectory=os.getcwd(),
-                                            changeCallback=self.OnSetDsn)
-        dsnDir.SetName('GdalSelect')
-        dsnDir.Hide()
-        
-        dsnDbFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
-                                                size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
-                                                dialogTitle=_('Choose file'),
-                                                buttonText=_('Browse'),
-                                                startDirectory=os.getcwd(),
-                                                changeCallback=self.OnSetDsn)
-        dsnDbFile.Hide()
-        dsnDbFile.SetName('GdalSelect')
-
-        dsnDbText = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        dsnDbText.Hide()
-        dsnDbText.Bind(wx.EVT_TEXT, self.OnSetDsn)
-        dsnDbText.SetName('GdalSelect')
-
-        dsnDbChoice = wx.Choice(parent = self, id = wx.ID_ANY)
-        dsnDbChoice.Hide()
-        dsnDbChoice.Bind(wx.EVT_CHOICE, self.OnSetDsn)
-        dsnDbChoice.SetName('GdalSelect')
-
-        dsnPro = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        dsnPro.Hide()
-        dsnPro.Bind(wx.EVT_TEXT, self.OnSetDsn)
-        dsnPro.SetName('GdalSelect')
-
-        # format
-        self.format = FormatSelect(parent = self,
-                                   ogr = ogr)
-        self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
-        self.extension = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        self.extension.Bind(wx.EVT_TEXT, self.OnSetExtension)
-        self.extension.Hide()
-        
-        if ogr:
-            fType = 'ogr'
-        else:
-            fType = 'gdal'
-        self.input = { 'file' : [_("File:"),
-                                 dsnFile,
-                                 utils.GetFormats(writableOnly = dest)[fType]['file']],
-                       'dir'  : [_("Name:"),
-                                 dsnDir,
-                                 utils.GetFormats(writableOnly = dest)[fType]['file']],
-                       'db'   : [_("Name:"),
-                                 dsnDbText,
-                                 utils.GetFormats(writableOnly = dest)[fType]['database']],
-                       'pro'  : [_("Protocol:"),
-                                 dsnPro,
-                                 utils.GetFormats(writableOnly = dest)[fType]['protocol']],
-                       'db-win' : { 'file'   : dsnDbFile,
-                                    'text'   : dsnDbText,
-                                    'choice' : dsnDbChoice },
-                       'native' : [_("Name:"), dsnDir, ''],
-                       }
-        
-        if self.dest:
-            current = gcmd.RunCommand('v.external.out',
-                                      parent = self,
-                                      read = True, parse = grass.parse_key_val,
-                                      flags = 'g')
-            if current['format'] == 'native':
-                self.dsnType = 'native'
-            elif current['format'] in utils.GetFormats()['ogr']['database']:
-                self.dsnType = 'db'
-            else:
-                self.dsnType = 'dir'
-        else:
-            self.dsnType = default
-        
-        self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                     label = self.input[self.dsnType][0],
-                                     size = (75, -1))
-        self.extensionText = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                           label = _("Extension:"))
-        self.extensionText.Hide()
-        
-        self.creationOpt = wx.TextCtrl(parent = self, id = wx.ID_ANY)
-        if not self.dest:
-            self.creationOpt.Hide()
-        
-        self._layout()
-        
-        self.OnSetType(event = None, sel = self.sourceMap[self.dsnType])
-        if self.dest:
-            if current['format'] != 'native':
-                self.OnSetFormat(event = None, format = current['format'])
-                self.OnSetDsn(event = None, path = current['dsn'])
-                self.creationOpt.SetValue(current['options'])
-        else:
-            if not ogr:
-                self.OnSetFormat(event = None, format = 'GeoTIFF')
-            else:
-                self.OnSetFormat(event = None, format = 'ESRI Shapefile')
-        
-    def _layout(self):
-        """!Layout"""
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
-        settingsSizer.Add(item = wx.StaticText(parent = self,
-                                               id = wx.ID_ANY,
-                                               label = _("Load settings:")),
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT,
-                          border  = 5)
-        settingsSizer.Add(item = self.settingsChoice,
-                          proportion = 1,
-                          flag = wx.EXPAND)
-        settingsSizer.Add(item = self.btnSettings,
-                          flag = wx.LEFT,
-                          border = 5)
-        
-        inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
-        
-        self.dsnSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        #self.dsnSizer.AddGrowableRow(0)
-        self.dsnSizer.AddGrowableCol(3)
-        
-        row = 0
-        self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                               label = _("Format:")),
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 0))
-        self.dsnSizer.Add(item=self.format,
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 1))
-        self.dsnSizer.Add(item = self.extensionText,
-                          flag=wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 2))
-        self.dsnSizer.Add(item=self.extension,
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 3))
-        row += 1
-        self.dsnSizer.Add(item = self.dsnText,
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 0))
-        self.dsnSizer.Add(item = self.input[self.dsnType][1],
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                          pos = (row, 1), span = (1, 3))
-        row += 1
-        if self.creationOpt.IsShown():
-            self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                                   label = _("Creation options:")),
-                              flag = wx.ALIGN_CENTER_VERTICAL,
-                              pos = (row, 0))
-            self.dsnSizer.Add(item = self.creationOpt,
-                              flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                              pos = (row, 1), span = (1, 3))
-            row += 1
-        
-        inputSizer.Add(item=self.dsnSizer, proportion = 1,
-                       flag=wx.EXPAND | wx.BOTTOM, border = 10)
-        
-        mainSizer.Add(item=settingsSizer, proportion=0,
-                      flag=wx.ALL | wx.EXPAND, border=5)
-        mainSizer.Add(item=self.source, proportion=0,
-                      flag=wx.LEFT | wx.RIGHT | wx.EXPAND, border=5)
-        mainSizer.Add(item=inputSizer, proportion=0,
-                      flag=wx.ALL | wx.EXPAND, border=5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-    def _getExtPatternGlob(self, ext):
-        """!Get pattern for case-insensitive globing"""
-        pattern = '*.'
-        for c in ext:
-            pattern += '[%s%s]' % (c.lower(), c.upper())
-        return pattern
-    
-    def _getExtPattern(self, ext):
-        """!Get pattern for case-insensitive file mask"""
-        return '*.%s;*.%s' % (ext.lower(), ext.upper())
-
-    def OnSettingsLoad(self, event):
-        """!Load named settings"""
-        name = event.GetString()
-        if name not in self._settings:
-            gcmd.GError(parent = self,
-                        message = _("Settings <%s> not found") % name)
-            return
-        data = self._settings[name]
-        self.OnSetType(event = None, sel = self.sourceMap[data[0]])
-        self.OnSetFormat(event = None, format = data[2])
-        self.OnSetDsn(event = None, path = data[1])
-        self.creationOpt.SetValue(data[3])
-        
-    def OnSettingsSave(self, event):
-        """!Save settings"""
-        dlg = wx.TextEntryDialog(parent = self,
-                                 message = _("Name:"),
-                                 caption = _("Save settings"))
-        if dlg.ShowModal() != wx.ID_OK:
-            return
-        
-        if not dlg.GetValue():
-            gcmd.GMessage(parent = self,
-                          message = _("Name not given, settings is not saved."))
-            return
-        
-        name = dlg.GetValue()
-        try:
-            fd = open(self.settingsFile, 'a')
-            fd.write(name + ';' + self.dsnType + ';' +
-                     self.GetDsn() + ';' +
-                     self.format.GetStringSelection())
-            fd.write('\n')
-        except IOError:
-            gcmd.GError(parent = self,
-                        message = _("Unable to save settings"))
-            return
-        fd.close()
-        
-        self._settings = self._loadSettings()
-        self.settingsChoice.Append(name)
-        self.settingsChoice.SetStringSelection(name)
-        
-        dlg.Destroy()
-                
-    def _loadSettings(self):
-        """!Load settings from the file
-
-        The file is defined by self.SettingsFile.
-        
-        @return parsed dict
-        @return empty dict on error
-        """
-        data = dict()
-        if not os.path.exists(self.settingsFile):
-            return data
-        
-        try:
-            fd = open(self.settingsFile, 'r')
-            for line in fd.readlines():
-                try:
-                    lineData = line.rstrip('\n').split(';')
-                    if len(lineData) > 4:
-                        # type, dsn, format, options
-                        data[lineData[0]] = (lineData[1], lineData[2], lineData[3], lineData[4])
-                    else:
-                        data[lineData[0]] = (lineData[1], lineData[2], lineData[3], '')
-                except ValueError:
-                    pass
-        except IOError:
-            return data
-        
-        fd.close()
-        
-        return data
-
-    def OnSetType(self, event, sel = None):
-        """!Datasource type changed"""
-        if event:
-            sel = event.GetSelection()
-        else:
-            self.source.SetSelection(sel)
-        win = self.input[self.dsnType][1]
-        if win:
-            self.dsnSizer.Remove(win)
-            win.Hide()
-        
-        if sel == self.sourceMap['file']:   # file
-            self.dsnType = 'file'
-            format = self.input[self.dsnType][2][0]
-            try:
-                ext = self.format.GetExtension(format)
-                if not ext:
-                    raise KeyError
-                format += ' (%s)|%s|%s (*.*)|*.*' % \
-                    (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
-            except KeyError:
-                format += '%s (*.*)|*.*' % _('All files')
-            
-            win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
-                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
-                                              dialogTitle=_('Choose file to import'),
-                                              buttonText=_('Browse'),
-                                              startDirectory=os.getcwd(),
-                                              changeCallback=self.OnSetDsn,
-                                              fileMask = format)
-            self.input[self.dsnType][1] = win
-        
-        elif sel == self.sourceMap['dir']: # directory
-            self.dsnType = 'dir'
-        elif sel == self.sourceMap['db']:  # database
-            self.dsnType = 'db'
-        elif sel == self.sourceMap['pro']: # protocol
-            self.dsnType = 'pro'
-        elif sel == self.sourceMap['native']:
-            self.dsnType = 'native'
-        
-        if self.dsnType == 'db':
-            self.input[self.dsnType][1] = self.input['db-win']['text']
-        win = self.input[self.dsnType][1]
-                
-        self.dsnSizer.Add(item = self.input[self.dsnType][1],
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                          pos = (1, 1), span = (1, 3))
-        win.SetValue('')
-        win.Show()
-        
-        if sel == self.sourceMap['native']: # native
-            win.Enable(False)
-            self.format.Enable(False)
-            self.creationOpt.Enable(False)
-            self.parent.btnOk.Enable(True)
-        else:
-            if not self.format.IsEnabled():
-                win.Enable(True)
-                self.format.Enable(True)
-                self.creationOpt.Enable(True)
-            self.dsnText.SetLabel(self.input[self.dsnType][0])
-            self.format.SetItems(self.input[self.dsnType][2])
-            if self.parent.GetName() == 'MultiImportDialog':
-                self.parent.list.DeleteAllItems()
-        
-        if sel in (self.sourceMap['file'],
-                   self.sourceMap['dir']):
-            if not self.ogr:
-                self.OnSetFormat(event = None, format = 'GeoTIFF')
-            else:
-                self.OnSetFormat(event = None, format = 'ESRI Shapefile')
-        
-        if sel == self.sourceMap['dir'] and not self.dest:
-            if not self.extension.IsShown():
-                self.extensionText.Show()
-                self.extension.Show()
-        else:
-            if self.extension.IsShown():
-                self.extensionText.Hide()
-                self.extension.Hide()
-        
-        self.dsnSizer.Layout()
-        
-    def GetDsn(self):
-        """!Get datasource name"""
-        if self.format.GetStringSelection() == 'PostgreSQL':
-            return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
-        
-        return self.input[self.dsnType][1].GetValue()
-    
-    def OnSetDsn(self, event, path = None):
-        """!Input DXF file/OGR dsn defined, update list of layer
-        widget"""
-        if event:
-            path = event.GetString()
-        else:
-            if self.format.GetStringSelection() == 'PostgreSQL':
-                for item in path.split(':', 1)[1].split(','):
-                    key, value = item.split('=', 1)
-                    if key == 'dbname':
-                        self.input[self.dsnType][1].SetStringSelection(value)
-                        break
-            else:
-                self.input[self.dsnType][1].SetValue(path)
-
-        if not path:
-            if self.dest:
-                self.parent.btnOk.Enable(False)
-            return
-        
-        if self.dest:
-            self.parent.btnOk.Enable(True)
-        else:
-            self._reloadLayers()
-        
-        if event:
-            event.Skip()
-        
-    def _reloadLayers(self):
-        """!Reload list of layers"""
-        dsn = self.GetDsn()
-        if not dsn:
-            return
-        
-        data = list()        
-        layerId = 1
-        
-        if self.ogr:
-            ret = gcmd.RunCommand('v.in.ogr',
-                                  quiet = True,
-                                  read = True,
-                                  flags = 'a',
-                                  dsn = dsn)
-                
-            if not ret:
-                self.parent.list.LoadData()
-                if hasattr(self, "btn_run"):
-                    self.btn_run.Enable(False)
-                return
-            
-            layerId = 1
-            for line in ret.splitlines():
-                layerName, featureType = map(lambda x: x.strip(), line.split(' ', 1))
-                grassName = utils.GetValidLayerName(layerName)
-                data.append((layerId, layerName, featureType, grassName))
-                layerId += 1
-        else:
-            if self.dsnType == 'file':
-                baseName = os.path.basename(dsn)
-                grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
-                data.append((layerId, baseName, grassName))
-            elif self.dsnType == 'dir':
-                ext = self.extension.GetValue()
-                for filename in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
-                    baseName = os.path.basename(filename)
-                    grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
-                    data.append((layerId, baseName, grassName))
-                    layerId += 1
-        if self.ogr:
-            dsn += '@OGR'
-        
-        evt = wxGdalSelect(dsn = dsn)
-        evt.SetId(self.input[self.dsnType][1].GetId())
-        wx.PostEvent(self.parent, evt)
-        
-        if self.parent.GetName() == 'MultiImportDialog':
-            self.parent.list.LoadData(data)
-            if len(data) > 0:
-                self.parent.btn_run.Enable(True)
-            else:
-                self.parent.btn_run.Enable(False)
-        
-    def OnSetExtension(self, event):
-        """!Extension changed"""
-        if not self.dest:
-            # reload layers
-            self._reloadLayers()
-        
-    def OnSetFormat(self, event, format = None):
-        """!Format changed"""
-        if self.dsnType not in ['file', 'dir', 'db']:
-            return
-        
-        win = self.input[self.dsnType][1]
-        self.dsnSizer.Remove(win)
-        
-        if self.dsnType == 'file':
-            win.Destroy()
-        else: # database
-            win.Hide()
-        
-        if event:
-            format = event.GetString()
-        else:
-            self.format.SetStringSelection(format)
-        
-        if self.dsnType == 'file':
-            try:
-                ext = self.format.GetExtension(format)
-                if not ext:
-                    raise KeyError
-                format += ' (%s)|%s|%s (*.*)|*.*' % \
-                    (self._getExtPattern(ext), self._getExtPattern(ext), _('All files'))
-            except KeyError:
-                format += '%s (*.*)|*.*' % _('All files')
-            
-            win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY, 
-                                              size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
-                                              dialogTitle=_('Choose file'),
-                                              buttonText=_('Browse'),
-                                              startDirectory=os.getcwd(),
-                                              changeCallback=self.OnSetDsn,
-                                              fileMask = format)
-            
-        elif self.dsnType == 'dir':
-            pass
-        
-        else: # database
-            if format == 'SQLite' or format == 'Rasterlite':
-                win = self.input['db-win']['file']
-            elif format == 'PostgreSQL' or format == 'PostGIS WKT Raster driver':
-                if grass.find_program('psql', ['--help']):
-                    win = self.input['db-win']['choice']
-                    if not win.GetItems():
-                        p = grass.Popen(['psql', '-ltA'], stdout = grass.PIPE)
-                        ret = p.communicate()[0]
-                        if ret:
-                            db = list()
-                            for line in ret.splitlines():
-                                sline = line.split('|')
-                                if len(sline) < 2:
-                                    continue
-                                dbname = sline[0]
-                                if dbname:
-                                    db.append(dbname)
-                            win.SetItems(db)
-                    if self.dest and win.GetStringSelection():
-                        self.parent.btnOk.Enable(True)
-                else:
-                    win = self.input['db-win']['text']
-            else:
-                win = self.input['db-win']['text']
-        
-        self.input[self.dsnType][1] = win
-        if not win.IsShown():
-            win.Show()
-        self.dsnSizer.Add(item = self.input[self.dsnType][1],
-                          flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                          pos = (1, 1), span = (1, 3))
-        self.dsnSizer.Layout()
-        
-        # update extension
-        self.extension.SetValue(self.GetFormatExt())
-
-        if not self.dest:
-            # reload layers
-            self._reloadLayers()
-        
-    def GetType(self):
-        """!Get source type"""
-        return self.dsnType
-
-    def GetDsn(self):
-        """!Get DSN"""
-        if self.format.GetStringSelection() == 'PostgreSQL':
-            return 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
-        
-        return self.input[self.dsnType][1].GetValue()
-
-    def GetDsnWin(self):
-        """!Get list of DSN windows"""
-        win = list()
-        for stype in ('file', 'dir', 'pro'):
-            win.append(self.input[stype][1])
-        for stype in ('file', 'text', 'choice'):
-            win.append(self.input['db-win'][stype])
-        
-        return win
-    
-    def GetFormat(self):
-        """!Get format as string"""
-        return self.format.GetStringSelection().replace(' ', '_')
-    
-    def GetFormatExt(self):
-        """!Get format extension"""
-        return self.format.GetExtension(self.format.GetStringSelection())
-    
-    def GetOptions(self):
-        """!Get creation options"""
-        if not self.creationOpt.IsShown():
-            return ''
-        
-        return self.creationOpt.GetValue()
-    
-class ProjSelect(wx.ComboBox):
-    """!Widget for selecting input raster/vector map used by
-    r.proj/v.proj modules."""
-    def __init__(self, parent, isRaster, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
-                 **kwargs):
-        super(ProjSelect, self).__init__(parent, id, size = size, 
-                                         style = wx.CB_READONLY, **kwargs)
-        self.SetName("ProjSelect")
-        self.isRaster = isRaster
-        
-    def UpdateItems(self, dbase, location, mapset):
-        """!Update list of maps
-        
-        """
-        if not dbase:
-            dbase = grass.gisenv()['GISDBASE']
-        if not mapset:
-            mapset = grass.gisenv()['MAPSET']
-        if self.isRaster:
-            ret = gcmd.RunCommand('r.proj',
-                                  quiet = True,
-                                  read = True,
-                                  flags = 'l',
-                                  dbase = dbase,
-                                  location = location,
-                                  mapset = mapset)
-        else:
-            ret = gcmd.RunCommand('v.proj',
-                                  quiet = True,
-                                  read = True,
-                                  flags = 'l',
-                                  dbase = dbase,
-                                  location = location,
-                                  mapset = mapset)
-        listMaps = list()
-        if ret:
-            for line in ret.splitlines():
-                listMaps.append(line.strip())
-        utils.ListSortLower(listMaps)
-        
-        self.SetItems(listMaps)
-        self.SetValue('')
-
-class ElementSelect(wx.Choice):
-    def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE, 
-                 **kwargs):
-        """!Widget for selecting GIS element
-        
-        @param parent parent window
-        """
-        super(ElementSelect, self).__init__(parent, id, size = size, 
-                                            style = wx.CB_READONLY, **kwargs)
-        self.SetName("ElementSelect")
-        
-        task = gtask.parse_interface('g.list')
-        p = task.get_param(value = 'type')
-        self.values = p.get('values', [])
-        self.valuesDesc = p.get('values_desc', [])
-        
-        self.SetItems(self.valuesDesc)
-
-    def GetValue(self, name):
-        """!Translate value
-
-        @param name element name
-        """
-        idx = self.valuesDesc.index(name)
-        if idx > -1:
-            return self.values[idx]
-        return ''
-
-class OgrTypeSelect(wx.Panel):
-    def __init__(self, parent, panel, **kwargs):
-        """!Widget to choose OGR feature type
-
-        @param parent parent window
-        @param panel wx.Panel instance used as parent window
-        """
-        wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
-        
-        self.ftype = wx.Choice(parent = self, id = wx.ID_ANY,
-                               size = (200, -1),
-                               choices = (_("Point"), _("LineString"), _("Polygon")))
-        self._layout()
-
-    def _layout(self):
-        """!Do layout"""
-        sizer = wx.BoxSizer(wx.HORIZONTAL)
-        sizer.Add(item = wx.StaticText(parent = self,
-                                       id = wx.ID_ANY,
-                                       label = _("Feature type:")),
-                  proportion = 1,
-                  flag = wx.ALIGN_CENTER_VERTICAL,
-                  border  = 5)
-        sizer.Add(item = self.ftype,
-                  proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_RIGHT)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def GetType(self):
-        """!Get selected type as string
-
-        @return feature type as string
-        """
-        sel = self.ftype.GetSelection()
-        if sel == 0:
-            return 'point'
-        elif sel == 1:
-            return 'line'
-        elif sel == 2:
-            return 'boundary'

Deleted: grass/trunk/gui/wxpython/gui_modules/histogram.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/histogram.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/histogram.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,463 +0,0 @@
-"""!
- at package histogram.py
-
-Plotting histogram
-
-Classes:
- - BufferedWindow
- - HistFrame
-
-(C) 2007, 2010-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton
- at author Various updates by Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-
-import wx
-
-import render
-import menuform
-import disp_print
-import utils
-import gdialogs
-import globalvar
-
-from toolbars    import HistogramToolbar
-from preferences import DefaultFontDialog
-from debug       import Debug
-from icon        import Icons
-from gcmd        import GError
-
-class BufferedWindow(wx.Window):
-    """!A Buffered window class.
-
-    When the drawing needs to change, you app needs to call the
-    UpdateHist() method. Since the drawing is stored in a bitmap, you
-    can also save the drawing to file by calling the
-    SaveToFile(self,file_name,file_type) method.
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
-                 Map = None, **kwargs):
-        
-        wx.Window.__init__(self, parent, id = id, style = style, **kwargs)
-        
-        self.parent = parent
-        self.Map = Map
-        self.mapname = self.parent.mapname
-        
-        #
-        # Flags
-        #
-        self.render = True  # re-render the map from GRASS or just redraw image
-        self.resize = False # indicates whether or not a resize event has taken place
-        self.dragimg = None # initialize variable for map panning
-        self.pen = None     # pen for drawing zoom boxes, etc.
-        
-        #
-        # Event bindings
-        #
-        self.Bind(wx.EVT_PAINT,        self.OnPaint)
-        self.Bind(wx.EVT_SIZE,         self.OnSize)
-        self.Bind(wx.EVT_IDLE,         self.OnIdle)
-        
-        #
-        # Render output objects
-        #
-        self.mapfile = None # image file to be rendered
-        self.img = ""       # wx.Image object (self.mapfile)
-        
-        self.imagedict = {} # images and their PseudoDC ID's for painting and dragging
-        
-        self.pdc = wx.PseudoDC()
-        self._buffer = '' # will store an off screen empty bitmap for saving to file
-        
-        # make sure that extents are updated at init
-        self.Map.region = self.Map.GetRegion()
-        self.Map.SetRegion() 
-        
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
-        
-    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0,0,0,0]):
-        """!Draws histogram or clears window
-        """
-        if drawid == None:
-            if pdctype == 'image' :
-                drawid = imagedict[img]
-            elif pdctype == 'clear':
-                drawid == None
-            else:
-                drawid = wx.NewId()
-        else:
-            pdc.SetId(drawid)
-        
-        pdc.BeginDrawing()
-        
-        Debug.msg (3, "BufferedWindow.Draw(): id=%s, pdctype=%s, coord=%s" % (drawid, pdctype, coords))
-        
-        if pdctype == 'clear': # erase the display
-            bg = wx.WHITE_BRUSH
-            pdc.SetBackground(bg)
-            pdc.Clear()
-            self.Refresh()
-            pdc.EndDrawing()
-            return
-        
-        if pdctype == 'image':
-            bg = wx.TRANSPARENT_BRUSH
-            pdc.SetBackground(bg)
-            bitmap = wx.BitmapFromImage(img)
-            w,h = bitmap.GetSize()
-            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
-            pdc.SetIdBounds(drawid, (coords[0],coords[1],w,h))
-        
-        pdc.EndDrawing()
-        self.Refresh()
-        
-    def OnPaint(self, event):
-        """!Draw psuedo DC to buffer
-        """
-        dc = wx.BufferedPaintDC(self, self._buffer)
-        
-        # use PrepareDC to set position correctly
-        self.PrepareDC(dc)
-        # we need to clear the dc BEFORE calling PrepareDC
-        bg = wx.Brush(self.GetBackgroundColour())
-        dc.SetBackground(bg)
-        dc.Clear()
-        # create a clipping rect from our position and size
-        # and the Update Region
-        rgn = self.GetUpdateRegion()
-        r = rgn.GetBox()
-        # draw to the dc using the calculated clipping rect
-        self.pdc.DrawToDCClipped(dc,r)
-        
-    def OnSize(self, event):
-        """!Init image size to match window size
-        """
-        # set size of the input image
-        self.Map.width, self.Map.height = self.GetClientSize()
-        
-        # Make new off screen bitmap: this bitmap will always have the
-        # current drawing in it, so it can be used to save the image to
-        # a file, or whatever.
-        self._buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
-        
-        # get the image to be rendered
-        self.img = self.GetImage()
-        
-        # update map display
-        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
-            self.img = self.img.Scale(self.Map.width, self.Map.height)
-            self.render = False
-            self.UpdateHist()
-        
-        # re-render image on idle
-        self.resize = True
-        
-    def OnIdle(self, event):
-        """!Only re-render a histogram image from GRASS during idle
-        time instead of multiple times during resizing.
-        """
-        if self.resize:
-            self.render = True
-            self.UpdateHist()
-        event.Skip()
-        
-    def SaveToFile(self, FileName, FileType, width, height):
-        """!This will save the contents of the buffer to the specified
-        file. See the wx.Windows docs for wx.Bitmap::SaveFile for the
-        details
-        """
-        busy = wx.BusyInfo(message=_("Please wait, exporting image..."),
-                           parent=self)
-        wx.Yield()
-        
-        self.Map.ChangeMapSize((width, height))
-        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
-        self.Map.Render(force=True, windres = True)
-        img = self.GetImage()
-        self.Draw(self.pdc, img, drawid = 99)
-        dc = wx.BufferedPaintDC(self, ibuffer)
-        dc.Clear()
-        self.PrepareDC(dc)
-        self.pdc.DrawToDC(dc)
-        ibuffer.SaveFile(FileName, FileType)
-        
-        busy.Destroy()
-        
-    def GetImage(self):
-        """!Converts files to wx.Image
-        """
-        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
-                os.path.getsize(self.Map.mapfile):
-            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
-        else:
-            img = None
-        
-        self.imagedict[img] = 99 # set image PeudoDC ID
-        return img
-    
-    def UpdateHist(self, img = None):
-        """!Update canvas if histogram options changes or window
-        changes geometry
-        """
-        Debug.msg (2, "BufferedWindow.UpdateHist(%s): render=%s" % (img, self.render))
-        oldfont = ""
-        oldencoding = ""
-        
-        if self.render:
-            # render new map images
-            # set default font and encoding environmental variables
-            if "GRASS_FONT" in os.environ:
-                oldfont = os.environ["GRASS_FONT"]
-            if self.parent.font != "": os.environ["GRASS_FONT"] = self.parent.font
-            if "GRASS_ENCODING" in os.environ:
-                oldencoding = os.environ["GRASS_ENCODING"]
-            if self.parent.encoding != None and self.parent.encoding != "ISO-8859-1":
-                os.environ[GRASS_ENCODING] = self.parent.encoding
-            
-            # using active comp region
-            self.Map.GetRegion(update = True)
-            
-            self.Map.width, self.Map.height = self.GetClientSize()
-            self.mapfile = self.Map.Render(force = self.render)
-            self.img = self.GetImage()
-            self.resize = False
-        
-        if not self.img: return
-        try:
-            id = self.imagedict[self.img]
-        except:
-            return
-        
-        # paint images to PseudoDC
-        self.pdc.Clear()
-        self.pdc.RemoveAll()
-        self.Draw(self.pdc, self.img, drawid = id) # draw map image background
-        
-        self.resize = False
-        
-        # update statusbar
-        # Debug.msg (3, "BufferedWindow.UpdateHist(%s): region=%s" % self.Map.region)
-        self.Map.SetRegion()
-        self.parent.statusbar.SetStatusText("Image/Raster map <%s>" % self.parent.mapname)
-        
-        # set default font and encoding environmental variables
-        if oldfont != "":
-            os.environ["GRASS_FONT"] = oldfont
-        if oldencoding != "":
-            os.environ["GRASS_ENCODING"] = oldencoding
-        
-    def EraseMap(self):
-        """!Erase the map display
-        """
-        self.Draw(self.pdc, pdctype = 'clear')
-        
-class HistFrame(wx.Frame):
-    """!Main frame for hisgram display window. Uses d.histogram
-    rendered onto canvas
-    """
-    def __init__(self, parent = None, id = wx.ID_ANY,
-                 title = _("GRASS GIS Histogram of raster map"),
-                 style = wx.DEFAULT_FRAME_STYLE, **kwargs):
-        wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.Map   = render.Map()  # instance of render.Map to be associated with display
-        self.layer = None          # reference to layer with histogram
-        
-        # Init variables
-        self.params = {}  # previously set histogram parameters
-        self.propwin = '' # ID of properties dialog
-        
-        self.font = ""
-        self.encoding = 'ISO-8859-1' # default encoding for display fonts
-        
-        self.toolbar = HistogramToolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-
-        # Add statusbar
-        self.mapname = ''
-        self.statusbar = self.CreateStatusBar(number = 1, style = 0)
-        # self.statusbar.SetStatusWidths([-2, -1])
-        hist_frame_statusbar_fields = ["Histogramming %s" % self.mapname]
-        for i in range(len(hist_frame_statusbar_fields)):
-            self.statusbar.SetStatusText(hist_frame_statusbar_fields[i], i)
-        
-        # Init map display
-        self.InitDisplay() # initialize region values
-        
-        # initialize buffered DC
-        self.HistWindow = BufferedWindow(self, id = wx.ID_ANY, Map = self.Map) # initialize buffered DC
-        
-        # Bind various events
-        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
-        
-        # Init print module and classes
-        self.printopt = disp_print.PrintOptions(self, self.HistWindow)
-        
-        # Add layer to the map
-        self.layer = self.Map.AddLayer(type = "command", name = 'histogram', command = ['d.histogram'],
-                                       l_active = False, l_hidden = False, l_opacity = 1, l_render = False)
-        
-    def InitDisplay(self):
-        """!Initialize histogram display, set dimensions and region
-        """
-        self.width, self.height = self.GetClientSize()
-        self.Map.geom = self.width, self.height
-        
-    def OnOptions(self, event):
-        """!Change histogram settings"""
-        cmd = ['d.histogram']
-        if self.mapname != '':
-            cmd.append('map=%s' % self.mapname)
-        
-        menuform.GUI(parent = self).ParseCommand(cmd,
-                                                 completed = (self.GetOptData, None, self.params))
-        
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """!Callback method for histogram command generated by dialog
-        created in menuform.py
-        """
-        if dcmd:
-            name, found = utils.GetLayerNameFromCmd(dcmd, fullyQualified = True,
-                                                    layerType = 'raster')
-            if not found:
-                GError(parent = propwin,
-                       message = _("Raster map <%s> not found") % name)
-                return
-            
-            self.SetHistLayer(name)
-        self.params = params
-        self.propwin = propwin
-        
-        self.HistWindow.UpdateHist()
-        
-    def SetHistLayer(self, name):
-        """!Set histogram layer
-        """
-        self.mapname = name
-        
-        self.layer = self.Map.ChangeLayer(layer = self.layer,
-                                          command = [['d.histogram', 'map=%s' % self.mapname],],
-                                          active = True)
-        
-        return self.layer
-
-    def SetHistFont(self, event):
-        """!Set font for histogram. If not set, font will be default
-        display font.
-        """
-        dlg = DefaultFontDialog(parent = self, id = wx.ID_ANY,
-                                title = _('Select font for histogram text'))        
-        dlg.fontlb.SetStringSelection(self.font, True)
-        
-        if dlg.ShowModal() == wx.ID_CANCEL:
-            dlg.Destroy()
-            return
-        
-        # set default font type, font, and encoding to whatever selected in dialog
-        if dlg.font != None:
-            self.font = dlg.font
-        if dlg.encoding != None:
-            self.encoding = dlg.encoding
-        
-        dlg.Destroy()
-        self.HistWindow.UpdateHist()
-
-    def OnErase(self, event):
-        """!Erase the histogram display
-        """
-        self.HistWindow.Draw(self.HistWindow.pdc, pdctype = 'clear')
-        
-    def OnRender(self, event):
-        """!Re-render histogram
-        """
-        self.HistWindow.UpdateHist()
-        
-    def GetWindow(self):
-        """!Get buffered window"""
-        return self.HistWindow
-    
-    def SaveToFile(self, event):
-        """!Save to file
-        """
-        filetype, ltype = gdialogs.GetImageHandlers(self.HistWindow.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.HistWindow.SaveToFile(path, fileType,
-                                       width, height)
-        
-        self.HistWindow.UpdateHist()
-        dlg.Destroy()
-        
-    def PrintMenu(self, event):
-        """!Print options and output menu
-        """
-        point = wx.GetMousePosition()
-        printmenu = wx.Menu()
-        # Add items to the menu
-        setup = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('Page setup'))
-        printmenu.AppendItem(setup)
-        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
-        
-        preview = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('Print preview'))
-        printmenu.AppendItem(preview)
-        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
-        
-        doprint = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('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 OnQuit(self, event):
-        self.Close(True)
-        
-    def OnCloseWindow(self, event):
-        """!Window closed
-        Also remove associated rendered images
-        """
-        try:
-            self.propwin.Close(True)
-        except:
-            pass
-        self.Map.Clean()
-        self.Destroy()
-        

Deleted: grass/trunk/gui/wxpython/gui_modules/layertree.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/layertree.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/layertree.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1658 +0,0 @@
-"""!
- at package layertree.py
-
- at brief Utility classes for map layer management.
-
-Classes:
- - AbstractLayer
- - Layer
- - LayerTree
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
- 
- at author Michael Barton (Arizona State University)
- at author Jachym Cepicky (Mendel University of Agriculture)
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import string
-
-import wx
-try:
-    import wx.lib.agw.customtreectrl as CT
-except ImportError:
-    import wx.lib.customtreectrl as CT
-import wx.combo
-import wx.lib.newevent
-import wx.lib.buttons  as  buttons
-try:
-    import treemixin 
-except ImportError:
-    from wx.lib.mixins import treemixin
-
-import globalvar
-
-from grass.script import core as grass
-
-import gdialogs
-import menuform
-import toolbars
-import mapdisp
-import render
-import histogram
-import utils
-from wxplot      import ProfileFrame
-from debug       import Debug
-from icon        import Icons
-from preferences import globalSettings as UserSettings
-from vdigit      import haveVDigit
-from gcmd        import GWarning
-
-TREE_ITEM_HEIGHT = 25
-
-class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
-    """!Creates layer tree structure
-    """
-    def __init__(self, parent,
-                 id = wx.ID_ANY, style = wx.SUNKEN_BORDER,
-                 ctstyle = CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
-                 CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
-                 CT.TR_MULTIPLE, **kwargs):
-        
-        if 'style' in kwargs:
-            ctstyle |= kwargs['style']
-            del kwargs['style']
-        self.disp_idx = kwargs['idx']
-        del kwargs['idx']
-        self.lmgr = kwargs['lmgr']
-        del kwargs['lmgr']
-        self.notebook = kwargs['notebook']   # GIS Manager notebook for layer tree
-        del kwargs['notebook']
-        self.auimgr = kwargs['auimgr']       # aui manager
-        del kwargs['auimgr']
-        showMapDisplay = kwargs['showMapDisplay']
-        del kwargs['showMapDisplay']
-        self.treepg = parent                 # notebook page holding layer tree
-        self.Map = render.Map()              # instance of render.Map to be associated with display
-        self.root = None                     # ID of layer tree root node
-        self.groupnode = 0                   # index value for layers
-        self.optpage = {}                    # dictionary of notebook option pages for each map layer
-        self.layer_selected = None           # ID of currently selected layer
-        self.saveitem = {}                   # dictionary to preserve layer attributes for drag and drop
-        self.first = True                    # indicates if a layer is just added or not
-        self.flag = ''                       # flag for drag and drop hittest
-        self.rerender = False                # layer change requires a rerendering if auto render
-        self.reorder = False                 # layer change requires a reordering
-        
-        try:
-            ctstyle |= CT.TR_ALIGN_WINDOWS
-        except AttributeError:
-            pass
-        
-        if globalvar.hasAgw:
-            super(LayerTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
-        else:
-            super(LayerTree, self).__init__(parent, id, style = ctstyle, **kwargs)
-        self.SetName("LayerTree")
-        
-        ### SetAutoLayout() causes that no vertical scrollbar is displayed
-        ### when some layers are not visible in layer tree
-        # self.SetAutoLayout(True)
-        self.SetGradientStyle(1)
-        self.EnableSelectionGradient(True)
-        self._setGradient()
-        
-        # init associated map display
-        pos = wx.Point((self.disp_idx + 1) * 25, (self.disp_idx + 1) * 25)
-        self.mapdisplay = mapdisp.MapFrame(self,
-                                           id = wx.ID_ANY, pos = pos,
-                                           size = globalvar.MAP_WINDOW_SIZE,
-                                           style = wx.DEFAULT_FRAME_STYLE,
-                                           tree = self, notebook = self.notebook,
-                                           lmgr = self.lmgr, page = self.treepg,
-                                           Map = self.Map, auimgr = self.auimgr)
-        
-        # title
-        self.mapdisplay.SetTitle(_("GRASS GIS Map Display: %(id)d  - Location: %(loc)s") % \
-                                     { 'id' : self.disp_idx + 1,
-                                       'loc' : grass.gisenv()["LOCATION_NAME"] })
-        
-        # show new display
-        if showMapDisplay is True:
-            self.mapdisplay.Show()
-            self.mapdisplay.Refresh()
-            self.mapdisplay.Update()
-        
-        self.root = self.AddRoot(_("Map Layers"))
-        self.SetPyData(self.root, (None, None))
-        
-        # create image list to use with layer tree
-        il = wx.ImageList(16, 16, mask = False)
-        
-        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
-        self.folder_open = il.Add(trart)
-        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
-        self.folder = il.Add(trart)
-        
-        bmpsize = (16, 16)
-        icons = Icons['layerManager']
-        trgif = icons["addRast"].GetBitmap(bmpsize)
-        self.rast_icon = il.Add(trgif)
-        
-        trgif = icons["addRast3d"].GetBitmap(bmpsize)
-        self.rast3d_icon = il.Add(trgif)
-        
-        trgif = icons["addRgb"].GetBitmap(bmpsize)
-        self.rgb_icon = il.Add(trgif)
-        
-        trgif = icons["addHis"].GetBitmap(bmpsize)
-        self.his_icon = il.Add(trgif)
-        
-        trgif = icons["addShaded"].GetBitmap(bmpsize)
-        self.shaded_icon = il.Add(trgif)
-        
-        trgif = icons["addRArrow"].GetBitmap(bmpsize)
-        self.rarrow_icon = il.Add(trgif)
-        
-        trgif = icons["addRNum"].GetBitmap(bmpsize)
-        self.rnum_icon = il.Add(trgif)
-        
-        trgif = icons["addVect"].GetBitmap(bmpsize)
-        self.vect_icon = il.Add(trgif)
-        
-        trgif = icons["addThematic"].GetBitmap(bmpsize)
-        self.theme_icon = il.Add(trgif)
-        
-        trgif = icons["addChart"].GetBitmap(bmpsize)
-        self.chart_icon = il.Add(trgif)
-        
-        trgif = icons["addGrid"].GetBitmap(bmpsize)
-        self.grid_icon = il.Add(trgif)
-        
-        trgif = icons["addGeodesic"].GetBitmap(bmpsize)
-        self.geodesic_icon = il.Add(trgif)
-        
-        trgif = icons["addRhumb"].GetBitmap(bmpsize)
-        self.rhumb_icon = il.Add(trgif)
-        
-        trgif = icons["addLabels"].GetBitmap(bmpsize)
-        self.labels_icon = il.Add(trgif)
-        
-        trgif = icons["addCmd"].GetBitmap(bmpsize)
-        self.cmd_icon = il.Add(trgif)
-        
-        self.AssignImageList(il)
-        
-        self.Bind(wx.EVT_TREE_ITEM_EXPANDING,   self.OnExpandNode)
-        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED,   self.OnCollapseNode)
-        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED,   self.OnActivateLayer)
-        self.Bind(wx.EVT_TREE_SEL_CHANGED,      self.OnChangeSel)
-        self.Bind(CT.EVT_TREE_ITEM_CHECKED,     self.OnLayerChecked)
-        self.Bind(wx.EVT_TREE_DELETE_ITEM,      self.OnDeleteLayer)
-        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnLayerContextMenu)
-        self.Bind(wx.EVT_TREE_END_DRAG,         self.OnEndDrag)
-        self.Bind(wx.EVT_TREE_END_LABEL_EDIT,   self.OnRenamed)
-        self.Bind(wx.EVT_KEY_UP,                self.OnKeyUp)
-        self.Bind(wx.EVT_IDLE,                  self.OnIdle)
-
-    def _setGradient(self, iType = None):
-        """!Set gradient for items
-
-        @param iType bgmap, vdigit or None
-        """
-        if iType == 'bgmap':
-            self.SetFirstGradientColour(wx.Colour(0, 100, 0))
-            self.SetSecondGradientColour(wx.Colour(0, 150, 0))
-        elif iType == 'vdigit':
-            self.SetFirstGradientColour(wx.Colour(100, 0, 0))
-            self.SetSecondGradientColour(wx.Colour(150, 0, 0))
-        else:
-            self.SetFirstGradientColour(wx.Colour(100, 100, 100))
-            self.SetSecondGradientColour(wx.Colour(150, 150, 150))
-        
-    def GetMap(self):
-        """!Get map instace"""
-        return self.Map
-    
-    def GetMapDisplay(self):
-        """!Get associated MapFrame"""
-        return self.mapdisplay
-    
-    def OnIdle(self, event):
-        """!Only re-order and re-render a composite map image from GRASS during
-        idle time instead of multiple times during layer changing.
-        """
-        if self.rerender:
-            if self.mapdisplay.GetToolbar('vdigit'):
-                vector = True
-            else:
-                vector = False
-            if self.mapdisplay.IsAutoRendered():
-                self.mapdisplay.MapWindow.UpdateMap(render = True, renderVector = vector)
-                if self.lmgr.IsPaneShown('toolbarNviz'): # nviz
-                    self.mapdisplay.MapWindow3D.UpdateMap(render = True)
-            self.rerender = False
-        
-        event.Skip()
-        
-    def OnKeyUp(self, event):
-        """!Key pressed"""
-        key = event.GetKeyCode()
-        
-        if key == wx.WXK_DELETE and self.lmgr and \
-                not self.GetEditControl():
-            self.lmgr.OnDeleteLayer(None)
-        
-        event.Skip()
-        
-    def OnLayerContextMenu (self, event):
-        """!Contextual menu for item/layer"""
-        if not self.layer_selected:
-            event.Skip()
-            return
-
-        ltype = self.GetPyData(self.layer_selected)[0]['type']
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        
-        Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \
-                       ltype)
-
-        if not hasattr (self, "popupID"):
-            self.popupID = dict()
-            for key in ('remove', 'rename', 'opacity', 'nviz', 'zoom',
-                        'region', 'export', 'attr', 'edit0', 'edit1',
-                        'bgmap', 'topo', 'meta', 'null', 'zoom1', 'region1',
-                        'color', 'hist', 'univar', 'prof', 'properties', 'sql'):
-                self.popupID[key] = wx.NewId()
-        
-        self.popupMenu = wx.Menu()
-        
-        numSelected = len(self.GetSelections())
-        
-        self.popupMenu.Append(self.popupID['remove'], text = _("Remove"))
-        self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id = self.popupID['remove'])
-        
-        if ltype != "command":
-            self.popupMenu.Append(self.popupID['rename'], text = _("Rename"))
-            self.Bind(wx.EVT_MENU, self.OnRenameLayer, id = self.popupID['rename'])
-            if numSelected > 1:
-                self.popupMenu.Enable(self.popupID['rename'], False)
-        
-        # map layer items
-        if ltype not in ("group", "command"):
-            self.popupMenu.AppendSeparator()
-            self.popupMenu.Append(self.popupID['opacity'], text = _("Change opacity level"))
-            self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id = self.popupID['opacity'])
-            self.popupMenu.Append(self.popupID['properties'], text = _("Properties"))
-            self.Bind(wx.EVT_MENU, self.OnPopupProperties, id = self.popupID['properties'])
-            
-            if numSelected > 1:
-                self.popupMenu.Enable(self.popupID['opacity'], False)
-                self.popupMenu.Enable(self.popupID['properties'], False)
-            
-            if ltype in ('raster', 'vector', '3d-raster') and self.lmgr.IsPaneShown('toolbarNviz'):
-                self.popupMenu.Append(self.popupID['nviz'], _("3D view properties"))
-                self.Bind (wx.EVT_MENU, self.OnNvizProperties, id = self.popupID['nviz'])
-            
-            if ltype in ('raster', 'vector', 'rgb'):
-                self.popupMenu.Append(self.popupID['zoom'], text = _("Zoom to selected map(s)"))
-                self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id = self.popupID['zoom'])
-                self.popupMenu.Append(self.popupID['region'], text = _("Set computational region from selected map(s)"))
-                self.Bind(wx.EVT_MENU, self.OnSetCompRegFromMap, id = self.popupID['region'])
-        
-        # specific items
-        try:
-            mltype = self.GetPyData(self.layer_selected)[0]['type']
-        except:
-            mltype = None
-        
-        # vector layers (specific items)
-        if mltype and mltype == "vector":
-            self.popupMenu.AppendSeparator()
-            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
-            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.out.ogr',
-                                                                        'input=%s' % mapLayer.GetName()]),
-                      id = self.popupID['export'])
-            
-            self.popupMenu.AppendSeparator()
-
-            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
-            self.Bind (wx.EVT_MENU, self.OnVectorColorTable, id = self.popupID['color'])
-
-            self.popupMenu.Append(self.popupID['attr'], text = _("Show attribute data"))
-            self.Bind(wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id = self.popupID['attr'])
-
-            self.popupMenu.Append(self.popupID['edit0'], text = _("Start editing"))
-            self.popupMenu.Append(self.popupID['edit1'], text = _("Stop editing"))
-            self.popupMenu.Enable(self.popupID['edit1'], False)
-            self.Bind (wx.EVT_MENU, self.OnStartEditing, id = self.popupID['edit0'])
-            self.Bind (wx.EVT_MENU, self.OnStopEditing,  id = self.popupID['edit1'])
-            
-            layer = self.GetPyData(self.layer_selected)[0]['maplayer']
-            # enable editing only for vector map layers available in the current mapset
-            digitToolbar = self.mapdisplay.GetToolbar('vdigit')
-            if digitToolbar:
-                # background vector map
-                self.popupMenu.Append(self.popupID['bgmap'],
-                                      text = _("Use as background vector map for digitizer"),
-                                      kind = wx.ITEM_CHECK)
-                self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap'])
-                if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
-                                    internal = True) == layer.GetName():
-                    self.popupMenu.Check(self.popupID['bgmap'], True)
-            
-            self.popupMenu.Append(self.popupID['topo'], text = _("Rebuild topology"))
-            self.Bind(wx.EVT_MENU, self.OnTopology, id = self.popupID['topo'])
-
-            # determine format
-            if layer and layer.GetType() == 'vector':
-                if 'info' not in self.GetPyData(self.layer_selected)[0]:
-                    info = grass.parse_command('v.info',
-                                               flags = 'g',
-                                               map = layer.GetName())
-                    self.GetPyData(self.layer_selected)[0]['info'] = info
-                info = self.GetPyData(self.layer_selected)[0]['info']
-                if info and info['format'] == 'ogr,PostgreSQL':
-                    self.popupMenu.Append(self.popupID['sql'], text = _("SQL Spatial Query"))
-                    self.Bind(wx.EVT_MENU, self.OnSqlQuery, id = self.popupID['sql'])
-            
-            if layer.GetMapset() != grass.gisenv()['MAPSET']:
-                # only vector map in current mapset can be edited
-                self.popupMenu.Enable (self.popupID['edit0'], False)
-                self.popupMenu.Enable (self.popupID['edit1'], False)
-                self.popupMenu.Enable (self.popupID['topo'], False)
-            elif digitToolbar and digitToolbar.GetLayer():
-                # vector map already edited
-                vdigitLayer = digitToolbar.GetLayer()
-                if vdigitLayer is layer:
-                    self.popupMenu.Enable(self.popupID['edit0'],  False)
-                    self.popupMenu.Enable(self.popupID['edit1'],  True)
-                    self.popupMenu.Enable(self.popupID['remove'], False)
-                    self.popupMenu.Enable(self.popupID['bgmap'],  False)
-                    self.popupMenu.Enable(self.popupID['topo'],   False)
-                else:
-                    self.popupMenu.Enable(self.popupID['edit0'], False)
-                    self.popupMenu.Enable(self.popupID['edit1'], False)
-                    self.popupMenu.Enable(self.popupID['bgmap'], True)
-            
-            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
-            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
-            if numSelected > 1:
-                self.popupMenu.Enable(self.popupID['attr'],   False)
-                self.popupMenu.Enable(self.popupID['edit0'],  False)
-                self.popupMenu.Enable(self.popupID['edit1'],  False)
-                self.popupMenu.Enable(self.popupID['meta'],   False)
-                self.popupMenu.Enable(self.popupID['bgmap'],  False)
-                self.popupMenu.Enable(self.popupID['topo'],   False)
-                self.popupMenu.Enable(self.popupID['export'], False)
-        
-        # raster layers (specific items)
-        elif mltype and mltype == "raster":
-            self.popupMenu.Append(self.popupID['zoom1'], text = _("Zoom to selected map(s) (ignore NULLs)"))
-            self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id = self.popupID['zoom1'])
-            self.popupMenu.Append(self.popupID['region1'], text = _("Set computational region from selected map(s) (ignore NULLs)"))
-            self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id = self.popupID['region1'])
-            
-            self.popupMenu.AppendSeparator()
-            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
-            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.out.gdal',
-                                                                        'input=%s' % mapLayer.GetName()]),
-                      id = self.popupID['export'])
-            
-            self.popupMenu.AppendSeparator()
-            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
-            self.Bind (wx.EVT_MENU, self.OnRasterColorTable, id = self.popupID['color'])
-            self.popupMenu.Append(self.popupID['hist'], _("Histogram"))
-            self.Bind (wx.EVT_MENU, self.OnHistogram, id = self.popupID['hist'])
-            self.popupMenu.Append(self.popupID['univar'], _("Univariate raster statistics"))
-            self.Bind (wx.EVT_MENU, self.OnUnivariateStats, id = self.popupID['univar'])
-            self.popupMenu.Append(self.popupID['prof'], _("Profile"))
-            self.Bind (wx.EVT_MENU, self.OnProfile, id = self.popupID['prof'])
-            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
-            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
-            
-            if numSelected > 1:
-                self.popupMenu.Enable(self.popupID['zoom1'],   False)
-                self.popupMenu.Enable(self.popupID['region1'], False)
-                self.popupMenu.Enable(self.popupID['color'],   False)
-                self.popupMenu.Enable(self.popupID['hist'],    False)
-                self.popupMenu.Enable(self.popupID['univar'],  False)
-                self.popupMenu.Enable(self.popupID['prof'],    False)
-                self.popupMenu.Enable(self.popupID['meta'],    False)
-                self.popupMenu.Enable(self.popupID['nviz'],    False)
-                self.popupMenu.Enable(self.popupID['export'],  False)
-
-        self.PopupMenu(self.popupMenu)
-        self.popupMenu.Destroy()
-        
-    def OnTopology(self, event):
-        """!Rebuild topology of selected vector map"""
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        cmd = ['v.build',
-               'map=%s' % mapLayer.GetName()]
-        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
-        
-    def OnSqlQuery(self, event):
-        """!Show SQL query window for PostGIS layers
-        """
-        dlg = gdialogs.SqlQueryFrame(parent = self)
-        dlg.CentreOnScreen()
-        dlg.Show()
-        
-    def OnMetadata(self, event):
-        """!Print metadata of raster/vector map layer
-        TODO: Dialog to modify metadata
-        """
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        mltype = self.GetPyData(self.layer_selected)[0]['type']
-
-        if mltype == 'raster':
-            cmd = ['r.info']
-        elif mltype == 'vector':
-            cmd = ['v.info']
-        cmd.append('map=%s' % mapLayer.GetName())
-
-        # print output to command log area
-        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
-
-    def OnSetCompRegFromRaster(self, event):
-        """!Set computational region from selected raster map (ignore NULLs)"""
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        
-        cmd = ['g.region',
-               '-p',
-               'zoom=%s' % mapLayer.GetName()]
-        
-        # print output to command log area
-        self.lmgr.goutput.RunCmd(cmd)
-         
-    def OnSetCompRegFromMap(self, event):
-        """!Set computational region from selected raster/vector map
-        """
-        rast = []
-        vect = []
-        rast3d = []
-        for layer in self.GetSelections():
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            mltype = self.GetPyData(layer)[0]['type']
-                
-            if mltype == 'raster':
-                rast.append(mapLayer.GetName())
-            elif mltype == 'vector':
-                vect.append(mapLayer.GetName())
-            elif mltype == '3d-raster':
-                rast3d.append(mapLayer.GetName())
-            elif mltype == 'rgb':
-                for rname in mapLayer.GetName().splitlines():
-                    rast.append(rname)
-        
-        cmd = ['g.region']
-        if rast:
-            cmd.append('rast=%s' % ','.join(rast))
-        if vect:
-            cmd.append('vect=%s' % ','.join(vect))
-        if rast3d:
-            cmd.append('rast3d=%s' % ','.join(rast3d))
-        
-        # print output to command log area
-        if len(cmd) > 1:
-            cmd.append('-p')
-            self.lmgr.goutput.RunCmd(cmd)
-        
-    def OnProfile(self, event):
-        """!Plot profile of given raster map layer"""
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        if not mapLayer.GetName():
-            wx.MessageBox(parent = self,
-                          message = _("Unable to create profile of "
-                                    "raster map."),
-                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return False
-
-        if not hasattr (self, "profileFrame"):
-            self.profileFrame = None
-
-        if hasattr (self.mapdisplay, "profile") and self.mapdisplay.profile:
-            self.profileFrame = self.mapdisplay.profile
-
-        if not self.profileFrame:
-            self.profileFrame = ProfileFrame(parent = self.mapdisplay,
-                                             rasterList = [mapLayer.GetName()])
-            # show new display
-            self.profileFrame.Show()
-        
-    def OnRasterColorTable(self, event):
-        """!Set color table for raster map"""
-        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
-        menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['r.colors',
-                                                                          'map=%s' % name])
-
-    def OnVectorColorTable(self, event):
-        """!Set color table for vector map"""
-        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
-        menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['v.colors',
-                                                                          'map=%s' % name])
-        
-    def OnHistogram(self, event):
-        """
-        Plot histogram for given raster map layer
-        """
-        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        if not mapLayer.GetName():
-            wx.MessageBox(parent = self,
-                          message = _("Unable to display histogram of "
-                                    "raster map."),
-                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            return False
-
-        if not hasattr (self, "histogramFrame"):
-            self.histogramFrame = None
-
-        if hasattr (self.mapdisplay, "histogram") and self.mapdisplay.histogram:
-            self.histogramFrame = self.mapdisplay.histogram
-
-        if not self.histogramFrame:
-            self.histogramFrame = histogram.HistFrame(self,
-                                                      id = wx.ID_ANY,
-                                                      pos = wx.DefaultPosition, size = globalvar.HIST_WINDOW_SIZE,
-                                                      style = wx.DEFAULT_FRAME_STYLE)
-            self.histogramFrame.CentreOnScreen()
-            # show new display
-            self.histogramFrame.Show()
-
-        self.histogramFrame.SetHistLayer(mapLayer.GetName())
-        self.histogramFrame.HistWindow.UpdateHist()
-        self.histogramFrame.Refresh()
-        self.histogramFrame.Update()
-
-        return True
-
-    def OnUnivariateStats(self, event):
-        """!Univariate raster statistics"""
-        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
-        menuform.GUI(parent = self).ParseCommand(['r.univar',
-                                                  'map=%s' % name])
-
-    def OnStartEditing(self, event):
-        """!Start editing vector map layer requested by the user
-        """
-        try:
-            maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        except:
-            event.Skip()
-            return
-        
-        if not haveVDigit:
-            from vdigit import errorMsg
-            msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
-                    "TCL/TK digitizer (v.digit) instead?\n\n"
-                    "Details: %s" % errorMsg)
-            
-            self.mapdisplay.toolbars['map'].combo.SetValue (_("2D view"))
-            dlg = wx.MessageDialog(parent = self.mapdisplay,
-                                   message = msg,
-                                   caption=_("Vector digitizer failed"),
-                                   style = wx.YES_NO | wx.CENTRE)
-            if dlg.ShowModal() == wx.ID_YES:
-                self.lmgr.goutput.RunCmd(['v.digit', 'map=%s' % maplayer.GetName()],
-                                         switchPage = False)
-            
-            dlg.Destroy()
-            return
-        
-        if not self.mapdisplay.GetToolbar('vdigit'): # enable tool
-            self.mapdisplay.AddToolbar('vdigit')
-        else: # tool already enabled
-            pass
-        
-        # mark layer as 'edited'
-        self.mapdisplay.toolbars['vdigit'].StartEditing(maplayer)
-        
-        self._setGradient('vdigit')
-        self.RefreshLine(self.layer_selected)
-        
-    def OnStopEditing(self, event):
-        """!Stop editing the current vector map layer
-        """
-        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        
-        self.mapdisplay.toolbars['vdigit'].OnExit()
-        if self.lmgr:
-            self.lmgr.toolbars['tools'].Enable('vdigit', enable = True)
-        
-        self._setGradient()
-        self.RefreshLine(self.layer_selected)
-        
-    def OnSetBgMap(self, event):
-        """!Set background vector map for editing sesstion"""
-        digit = self.mapdisplay.GetWindow().digit
-        if event.IsChecked():
-            mapName = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
-            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
-                             value = str(mapName), internal = True)
-            digit.OpenBackgroundMap(mapName)
-            self._setGradient('bgmap')
-        else:
-            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
-                             value = '', internal = True)
-            digit.CloseBackgroundMap()
-            self._setGradient()
-        
-        self.RefreshLine(self.layer_selected)
-
-    def OnPopupProperties (self, event):
-        """!Popup properties dialog"""
-        self.PropertiesDialog(self.layer_selected)
-
-    def OnPopupOpacityLevel(self, event):
-        """!Popup opacity level indicator"""
-        if not self.GetPyData(self.layer_selected)[0]['ctrl']:
-            return
-        
-        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
-        current_opacity = maplayer.GetOpacity()
-        
-        dlg = gdialogs.SetOpacityDialog(self, opacity = current_opacity,
-                                        title = _("Set opacity <%s>") % maplayer.GetName())
-        dlg.CentreOnParent()
-
-        if dlg.ShowModal() == wx.ID_OK:
-            new_opacity = dlg.GetOpacity() # string
-            self.Map.ChangeOpacity(maplayer, new_opacity)
-            maplayer.SetOpacity(new_opacity)
-            self.SetItemText(self.layer_selected,
-                             self._getLayerName(self.layer_selected))
-            
-            # vector layer currently edited
-            if self.mapdisplay.GetToolbar('vdigit') and \
-                    self.mapdisplay.GetToolbar('vdigit').GetLayer() == maplayer:   
-                alpha = int(new_opacity * 255)
-                self.mapdisplay.GetWindow().digit.GetDisplay().UpdateSettings(alpha = alpha)
-                
-            # redraw map if auto-rendering is enabled
-            self.rerender = True
-            self.reorder = True
-
-    def OnNvizProperties(self, event):
-        """!Nviz-related properties (raster/vector/volume)
-
-        @todo vector/volume
-        """
-        self.lmgr.notebook.SetSelectionByName('nviz')
-        ltype = self.GetPyData(self.layer_selected)[0]['type']
-        if ltype == 'raster':
-            self.lmgr.nviz.SetPage('surface')
-        elif ltype == 'vector':
-            self.lmgr.nviz.SetPage('vector')
-        elif ltype == '3d-raster':
-            self.lmgr.nviz.SetPage('volume')
-        
-    def OnRenameLayer (self, event):
-        """!Rename layer"""
-        self.EditLabel(self.layer_selected)
-        self.GetEditControl().SetSelection(-1, -1)
-        
-    def OnRenamed(self, event):
-        """!Layer renamed"""
-        if not event.GetLabel():
-            event.Skip()
-            return
-        
-        item = self.layer_selected
-        self.GetPyData(item)[0]['label'] = event.GetLabel()
-        self.SetItemText(item, self._getLayerName(item))
-        
-        event.Skip()
-
-    def AddLayer(self, ltype, lname = None, lchecked = None,
-                 lopacity = 1.0, lcmd = None, lgroup = None, lvdigit = None, lnviz = None, multiple = True):
-        """!Add new item to the layer tree, create corresponding MapLayer instance.
-        Launch property dialog if needed (raster, vector, etc.)
-
-        @param ltype layer type (raster, vector, 3d-raster, ...)
-        @param lname layer name
-        @param lchecked if True layer is checked
-        @param lopacity layer opacity level
-        @param lcmd command (given as a list)
-        @param lgroup index of group item (-1 for root) or None
-        @param lvdigit vector digitizer settings (eg. geometry attributes)
-        @param lnviz layer Nviz properties
-        @param multiple True to allow multiple map layers in layer tree
-        """
-        if lname and not multiple:
-            # check for duplicates
-            item = self.GetFirstVisibleItem()
-            while item and item.IsOk():
-                if self.GetPyData(item)[0]['type'] == 'vector':
-                    name = self.GetPyData(item)[0]['maplayer'].GetName()
-                    if name == lname:
-                        return
-                item = self.GetNextVisible(item)
-        
-        self.first = True
-        params = {} # no initial options parameters
-        
-        # deselect active item
-        if self.layer_selected:
-            self.SelectItem(self.layer_selected, select = False)
-        
-        Debug.msg (3, "LayerTree().AddLayer(): ltype=%s" % (ltype))
-        
-        if ltype == 'command':
-            # generic command item
-            ctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
-                               pos = wx.DefaultPosition, size = (self.GetSize()[0]-100,25),
-                               # style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
-                               style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
-            ctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
-            # ctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
-        elif ltype == 'group':
-            # group item
-            ctrl = None
-            grouptext = _('Layer group:') + str(self.groupnode)
-            self.groupnode += 1
-        else:
-            btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
-            ctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24,24))
-            ctrl.SetToolTipString(_("Click to edit layer settings"))
-            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, ctrl)
-        # add layer to the layer tree
-        if self.layer_selected and self.layer_selected != self.GetRootItem():
-            if self.GetPyData(self.layer_selected)[0]['type'] == 'group' \
-                and self.IsExpanded(self.layer_selected):
-                # add to group (first child of self.layer_selected) if group expanded
-                layer = self.PrependItem(parent = self.layer_selected,
-                                         text = '', ct_type = 1, wnd = ctrl)
-            else:
-                # prepend to individual layer or non-expanded group
-                if lgroup == -1:
-                    # -> last child of root (loading from workspace)
-                    layer = self.AppendItem(parentId = self.root,
-                                            text = '', ct_type = 1, wnd = ctrl)
-                elif lgroup > -1:
-                    # -> last child of group (loading from workspace)
-                    parent = self.FindItemByIndex(index = lgroup)
-                    if not parent:
-                        parent = self.root
-                    layer = self.AppendItem(parentId = parent,
-                                            text = '', ct_type = 1, wnd = ctrl)
-                elif lgroup is None:
-                    # -> previous sibling of selected layer
-                    parent = self.GetItemParent(self.layer_selected)
-                    layer = self.InsertItem(parentId = parent,
-                                            input = self.GetPrevSibling(self.layer_selected),
-                                            text = '', ct_type = 1, wnd = ctrl)
-        else: # add first layer to the layer tree (first child of root)
-            layer = self.PrependItem(parent = self.root, text = '', ct_type = 1, wnd = ctrl)
-        
-        # layer is initially unchecked as inactive (beside 'command')
-        # use predefined value if given
-        if lchecked is not None:
-            checked = lchecked
-        else:
-            checked = True
-        
-        self.CheckItem(layer, checked = checked)
-        
-        # add text and icons for each layer ltype
-        label =  _('(double click to set properties)') + ' ' * 15
-        if ltype == 'raster':
-            self.SetItemImage(layer, self.rast_icon)
-            self.SetItemText(layer, '%s %s' % (_('raster'), label))
-        elif ltype == '3d-raster':
-            self.SetItemImage(layer, self.rast3d_icon)
-            self.SetItemText(layer, '%s %s' % (_('3D raster'), label))
-        elif ltype == 'rgb':
-            self.SetItemImage(layer, self.rgb_icon)
-            self.SetItemText(layer, '%s %s' % (_('RGB'), label))
-        elif ltype == 'his':
-            self.SetItemImage(layer, self.his_icon)
-            self.SetItemText(layer, '%s %s' % (_('HIS'), label))
-        elif ltype == 'shaded':
-            self.SetItemImage(layer, self.shaded_icon)
-            self.SetItemText(layer, '%s %s' % (_('shaded relief'), label))
-        elif ltype == 'rastnum':
-            self.SetItemImage(layer, self.rnum_icon)
-            self.SetItemText(layer, '%s %s' % (_('raster cell numbers'), label))
-        elif ltype == 'rastarrow':
-            self.SetItemImage(layer, self.rarrow_icon)
-            self.SetItemText(layer, '%s %s' % (_('raster flow arrows'), label))
-        elif ltype == 'vector':
-            self.SetItemImage(layer, self.vect_icon)
-            self.SetItemText(layer, '%s %s' % (_('vector'), label))
-        elif ltype == 'thememap':
-            self.SetItemImage(layer, self.theme_icon)
-            self.SetItemText(layer, '%s %s' % (_('thematic area (choropleth) map'), label))
-        elif ltype == 'themechart':
-            self.SetItemImage(layer, self.chart_icon)
-            self.SetItemText(layer, '%s %s' % (_('thematic charts'), label))
-        elif ltype == 'grid':
-            self.SetItemImage(layer, self.grid_icon)
-            self.SetItemText(layer, '%s %s' % (_('grid'), label))
-        elif ltype == 'geodesic':
-            self.SetItemImage(layer, self.geodesic_icon)
-            self.SetItemText(layer, '%s %s' % (_('geodesic line'), label))
-        elif ltype == 'rhumb':
-            self.SetItemImage(layer, self.rhumb_icon)
-            self.SetItemText(layer, '%s %s' % (_('rhumbline'), label))
-        elif ltype == 'labels':
-            self.SetItemImage(layer, self.labels_icon)
-            self.SetItemText(layer, '%s %s' % (_('vector labels'), label))
-        elif ltype == 'command':
-            self.SetItemImage(layer, self.cmd_icon)
-        elif ltype == 'group':
-            self.SetItemImage(layer, self.folder)
-            self.SetItemText(layer, grouptext)
-        
-        self.first = False
-        
-        if ltype != 'group':
-            if lcmd and len(lcmd) > 1:
-                cmd = lcmd
-                render = False
-                name, found = utils.GetLayerNameFromCmd(lcmd)
-            else:
-                cmd = []
-                if ltype == 'command' and lname:
-                    for c in lname.split(';'):
-                        cmd.append(c.split(' '))
-                
-                render = False
-                name = None
-            
-            if ctrl:
-                ctrlId = ctrl.GetId()
-            else:
-                ctrlId = None
-            
-            # add a data object to hold the layer's command (does not apply to generic command layers)
-            self.SetPyData(layer, ({'cmd'      : cmd,
-                                    'type'     : ltype,
-                                    'ctrl'     : ctrlId,
-                                    'label'    : None,
-                                    'maplayer' : None,
-                                    'vdigit'   : lvdigit,
-                                    'nviz'     : lnviz,
-                                    'propwin'  : None}, 
-                                   None))
-            
-            # find previous map layer instance 
-            prevItem = self.GetFirstChild(self.root)[0]
-            prevMapLayer = None 
-            pos = -1
-            while prevItem and prevItem.IsOk() and prevItem != layer: 
-                if self.GetPyData(prevItem)[0]['maplayer']: 
-                    prevMapLayer = self.GetPyData(prevItem)[0]['maplayer'] 
-                
-                prevItem = self.GetNextSibling(prevItem) 
-                
-                if prevMapLayer: 
-                    pos = self.Map.GetLayerIndex(prevMapLayer)
-                else: 
-                    pos = -1
-            
-            maplayer = self.Map.AddLayer(pos = pos,
-                                         type = ltype, command = self.GetPyData(layer)[0]['cmd'], name = name,
-                                         l_active = checked, l_hidden = False,
-                                         l_opacity = lopacity, l_render = render)
-            self.GetPyData(layer)[0]['maplayer'] = maplayer
-            
-            # run properties dialog if no properties given
-            if len(cmd) == 0:
-                self.PropertiesDialog(layer, show = True)
-        
-        else: # group
-            self.SetPyData(layer, ({'cmd'      : None,
-                                    'type'     : ltype,
-                                    'ctrl'     : None,
-                                    'label'    : None,
-                                    'maplayer' : None,
-                                    'propwin'  : None}, 
-                                   None))
-        
-        # select new item
-        self.SelectItem(layer, select = True)
-        self.layer_selected = layer
-        
-        # use predefined layer name if given
-        if lname:
-            if ltype == 'group':
-                self.SetItemText(layer, lname)
-            elif ltype == 'command':
-                ctrl.SetValue(lname)
-            else:
-                self.SetItemText(layer, self._getLayerName(layer, lname))
-        else:
-            if ltype == 'group':
-                self.OnRenameLayer(None)
-        
-        # updated progress bar range (mapwindow statusbar)
-        if checked:
-            self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
-        
-        return layer
-
-    def PropertiesDialog (self, layer, show = True):
-        """!Launch the properties dialog"""
-        if 'propwin' in self.GetPyData(layer)[0] and \
-                self.GetPyData(layer)[0]['propwin'] is not None:
-            # recycle GUI dialogs
-            win = self.GetPyData(layer)[0]['propwin']
-            # update properties (columns, layers)
-            win.notebookpanel.OnUpdateSelection(None)
-            if win.IsShown():
-                win.SetFocus()
-            else:
-                win.Show()
-            
-            return
-        
-        completed = ''
-        params = self.GetPyData(layer)[1]
-        ltype  = self.GetPyData(layer)[0]['type']
-                
-        Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
-                   ltype)
-        
-        if self.GetPyData(layer)[0]['cmd']:
-            module = menuform.GUI(parent = self, show = show, centreOnParent = False)
-            module.ParseCommand(self.GetPyData(layer)[0]['cmd'],
-                                completed = (self.GetOptData,layer,params))
-            
-            self.GetPyData(layer)[0]['cmd'] = module.GetCmd()
-        elif ltype == 'raster':
-            cmd = ['d.rast']
-            
-            if UserSettings.Get(group = 'cmd', key = 'rasterOpaque', subkey = 'enabled'):
-                cmd.append('-n')
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
-                                                                             completed = (self.GetOptData,layer,params))
-                         
-        elif ltype == '3d-raster':
-            cmd = ['d.rast3d']
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
-                                                                             completed = (self.GetOptData,layer,params))
-                                        
-        elif ltype == 'rgb':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rgb'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'his':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.his'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'shaded':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.shadedmap'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'rastarrow':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.arrow'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'rastnum':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.num'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'vector':
-            types = list()
-            for ftype in ['point', 'line', 'boundary', 'centroid', 'area', 'face']:
-                if UserSettings.Get(group = 'cmd', key = 'showType', subkey = [ftype, 'enabled']):
-                    types.append(ftype)
-            
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect', 'type=%s' % ','.join(types)],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'thememap':
-            # -s flag requested, otherwise only first thematic category is displayed
-            # should be fixed by C-based d.thematic.* modules
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.thematic.area'], 
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'themechart':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect.chart'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'grid':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.grid'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'geodesic':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.geodesic'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'rhumb':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.rhumbline'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'labels':
-            menuform.GUI(parent = self, centreOnParent = False).ParseCommand(['d.labels'],
-                                                                             completed = (self.GetOptData,layer,params))
-            
-        elif ltype == 'cmdlayer':
-            pass
-        elif ltype == 'group':
-            pass
-        
-    def OnActivateLayer(self, event):
-        """!Double click on the layer item.
-        Launch property dialog, or expand/collapse group of items, etc.
-        """
-        self.lmgr.WorkspaceChanged()
-        layer = event.GetItem()
-        self.layer_selected = layer
-        
-        self.PropertiesDialog(layer)
-        
-        if self.GetPyData(layer)[0]['type'] == 'group':
-            if self.IsExpanded(layer):
-                self.Collapse(layer)
-            else:
-                self.Expand(layer)
-        
-    def OnDeleteLayer(self, event):
-        """!Remove selected layer item from the layer tree"""
-        self.lmgr.WorkspaceChanged()
-        item = event.GetItem()
-        
-        try:
-            item.properties.Close(True)
-        except:
-            pass
-
-        if item != self.root:
-            Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \
-                           (self.GetItemText(item)))
-        else:
-            self.root = None
-
-        # unselect item
-        self.Unselect()
-        self.layer_selected = None
-
-        try:
-            if self.GetPyData(item)[0]['type'] != 'group':
-                self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer'])
-        except:
-            pass
-
-        # redraw map if auto-rendering is enabled
-        self.rerender = True
-        self.reorder = True
-        
-        if self.mapdisplay.GetToolbar('vdigit'):
-            self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers (updateTool = True)
-
-        # update progress bar range (mapwindow statusbar)
-        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
-
-        #
-        # nviz
-        #
-        if self.lmgr.IsPaneShown('toolbarNviz') and \
-                self.GetPyData(item) is not None and not self.rerender:
-            # nviz - load/unload data layer
-            mapLayer = self.GetPyData(item)[0]['maplayer']
-            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
-            if mapLayer.type == 'raster':
-                self.mapdisplay.MapWindow.UnloadRaster(item)
-            elif mapLayer.type == '3d-raster':
-                self.mapdisplay.MapWindow.UnloadRaster3d(item)
-            elif mapLayer.type == 'vector':
-                self.mapdisplay.MapWindow.UnloadVector(item)
-            self.mapdisplay.SetStatusText("", 0)
-            
-        event.Skip()
-
-    def OnLayerChecked(self, event):
-        """!Enable/disable data layer"""
-        self.lmgr.WorkspaceChanged()
-        
-        item    = event.GetItem()
-        checked = item.IsChecked()
-        
-        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
-        if not self.first:
-            # change active parameter for item in layers list in render.Map
-            if self.GetPyData(item)[0]['type'] == 'group':
-                child, cookie = self.GetFirstChild(item)
-                while child:
-                    self.CheckItem(child, checked)
-                    mapLayer = self.GetPyData(child)[0]['maplayer']
-                    if not digitToolbar or \
-                           (digitToolbar and digitToolbar.GetLayer() != mapLayer):
-                        # ignore when map layer is edited
-                        self.Map.ChangeLayerActive(mapLayer, checked)
-                    child = self.GetNextSibling(child)
-            else:
-                mapLayer = self.GetPyData(item)[0]['maplayer']
-                if not digitToolbar or \
-                       (digitToolbar and digitToolbar.GetLayer() != mapLayer):
-                    # ignore when map layer is edited
-                    self.Map.ChangeLayerActive(mapLayer, checked)
-        
-        self.Unselect()
-        
-        # update progress bar range (mapwindow statusbar)
-        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
-        
-        # nviz
-        if self.lmgr.IsPaneShown('toolbarNviz') and \
-                self.GetPyData(item) is not None:
-            # nviz - load/unload data layer
-            mapLayer = self.GetPyData(item)[0]['maplayer']
-
-            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
-
-            if checked: # enable
-                if mapLayer.type == 'raster':
-                    self.mapdisplay.MapWindow.LoadRaster(item)
-                elif mapLayer.type == '3d-raster':
-                    self.mapdisplay.MapWindow.LoadRaster3d(item)
-                elif mapLayer.type == 'vector':
-                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(mapLayer)
-                    if npoints > 0:
-                        self.mapdisplay.MapWindow.LoadVector(item, points = True)
-                    if nlines > 0:
-                        self.mapdisplay.MapWindow.LoadVector(item, points = False)
-
-            else: # disable
-                if mapLayer.type == 'raster':
-                    self.mapdisplay.MapWindow.UnloadRaster(item)
-                elif mapLayer.type == '3d-raster':
-                    self.mapdisplay.MapWindow.UnloadRaster3d(item)
-                elif mapLayer.type == 'vector':
-                    self.mapdisplay.MapWindow.UnloadVector(item)
-            
-            self.mapdisplay.SetStatusText("", 0)
-        
-        # redraw map if auto-rendering is enabled
-        self.rerender = True
-        self.reorder = True
-        
-    def OnCmdChanged(self, event):
-        """!Change command string"""
-        ctrl = event.GetEventObject().GetId()
-        cmd = event.GetString()
-        
-        layer = self.GetFirstVisibleItem()
-
-        while layer and layer.IsOk():
-            if self.GetPyData(layer)[0]['ctrl'] == ctrl:
-                break
-            
-            layer = self.GetNextVisible(layer)
-
-        # change parameters for item in layers list in render.Map
-        self.ChangeLayer(layer)
-        
-        event.Skip()
-
-    def OnChangeSel(self, event):
-        """!Selection changed"""
-        oldlayer = event.GetOldItem()
-        layer = event.GetItem()
-        if layer == oldlayer:
-            event.Veto()
-            return
-        
-        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
-        if digitToolbar:
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            bgmap = UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
-                                     internal = True)
-            
-            if digitToolbar.GetLayer() == mapLayer:
-                self._setGradient('vdigit')
-            elif bgmap == mapLayer.GetName():
-                self._setGradient('bgmap')
-            else:
-                self._setGradient()
-        else:
-            self._setGradient()
-        
-        self.layer_selected = layer
-        
-        try:
-            if self.IsSelected(oldlayer):
-                self.SetItemWindowEnabled(oldlayer, True)
-            else:
-                self.SetItemWindowEnabled(oldlayer, False)
-
-            if self.IsSelected(layer):
-                self.SetItemWindowEnabled(layer, True)
-            else:
-                self.SetItemWindowEnabled(layer, False)
-        except:
-            pass
-        
-        try:
-            self.RefreshLine(oldlayer)
-            self.RefreshLine(layer)
-        except:
-            pass
-        
-        # update statusbar -> show command string
-        if self.GetPyData(layer) and self.GetPyData(layer)[0]['maplayer']:
-            cmd = self.GetPyData(layer)[0]['maplayer'].GetCmd(string = True)
-            if len(cmd) > 0:
-                self.lmgr.SetStatusText(cmd)
-        
-        # set region if auto-zooming is enabled
-        if self.GetPyData(layer) and self.GetPyData(layer)[0]['cmd'] and \
-               UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            if mapLayer.GetType() in ('raster', 'vector'):
-                render = self.mapdisplay.IsAutoRendered()
-                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
-                                                    render = render)
-        
-        # update nviz tools
-        if self.lmgr.IsPaneShown('toolbarNviz') and \
-                self.GetPyData(self.layer_selected) is not None:
-            if self.layer_selected.IsChecked():
-                # update Nviz tool window
-                type = self.GetPyData(self.layer_selected)[0]['maplayer'].type
-                
-                if type == 'raster':
-                    self.lmgr.nviz.UpdatePage('surface')
-                    self.lmgr.nviz.SetPage('surface')
-                elif type == 'vector':
-                    self.lmgr.nviz.UpdatePage('vector')
-                    self.lmgr.nviz.SetPage('vector')
-                elif type == '3d-raster':
-                    self.lmgr.nviz.UpdatePage('volume')
-                    self.lmgr.nviz.SetPage('volume')
-        
-    def OnCollapseNode(self, event):
-        """!Collapse node
-        """
-        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
-            self.SetItemImage(self.layer_selected, self.folder)
-
-    def OnExpandNode(self, event):
-        """!Expand node
-        """
-        self.layer_selected = event.GetItem()
-        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
-            self.SetItemImage(self.layer_selected, self.folder_open)
-    
-    def OnEndDrag(self, event):
-        self.StopDragging()
-        dropTarget = event.GetItem()
-        self.flag = self.HitTest(event.GetPoint())[1]
-        if self.lmgr.IsPaneShown('toolbarNviz'):
-            self.mapdisplay.MapWindow.UnloadDataLayers(True)
-        if self.IsValidDropTarget(dropTarget):
-            self.UnselectAll()
-            if dropTarget != None:
-                self.SelectItem(dropTarget)
-            self.OnDrop(dropTarget, self._dragItem)
-        elif dropTarget == None:
-            self.OnDrop(dropTarget, self._dragItem)
-            
-    def OnDrop(self, dropTarget, dragItem):
-        # save everthing associated with item to drag
-        try:
-            old = dragItem  # make sure this member exists
-        except:
-            return
-
-        Debug.msg (4, "LayerTree.OnDrop(): layer=%s" % \
-                   (self.GetItemText(dragItem)))
-        
-        # recreate data layer, insert copy of layer in new position, and delete original at old position
-        newItem  = self.RecreateItem (dragItem, dropTarget)
-
-        # if recreated layer is a group, also recreate its children
-        if  self.GetPyData(newItem)[0]['type'] == 'group':
-            (child, cookie) = self.GetFirstChild(dragItem)
-            if child:
-                while child:
-                    self.RecreateItem(child, dropTarget, parent = newItem)
-                    self.Delete(child)
-                    child = self.GetNextChild(old, cookie)[0]
-        
-        # delete layer at original position
-        try:
-            self.Delete(old) # entry in render.Map layers list automatically deleted by OnDeleteLayer handler
-        except AttributeError:
-            pass
-
-        # redraw map if auto-rendering is enabled
-        self.rerender = True
-        self.reorder = True
-        
-        # select new item
-        self.SelectItem(newItem)
-        
-    def RecreateItem (self, dragItem, dropTarget, parent = None):
-        """!Recreate item (needed for OnEndDrag())
-        """
-        Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \
-                   self.GetItemText(dragItem))
-
-        # fetch data (dragItem)
-        checked = self.IsItemChecked(dragItem)
-        image   = self.GetItemImage(dragItem, 0)
-        text    = self.GetItemText(dragItem)
-        if self.GetPyData(dragItem)[0]['ctrl']:
-            # recreate data layer
-            btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
-            newctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24, 24))
-            newctrl.SetToolTipString(_("Click to edit layer settings"))
-            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, newctrl)
-            data    = self.GetPyData(dragItem)
-        
-        elif self.GetPyData(dragItem)[0]['type'] == 'command':
-            # recreate command layer
-            oldctrl = None
-            newctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
-                                  pos = wx.DefaultPosition, size = (250,25),
-                                  style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
-            try:
-                newctrl.SetValue(self.GetPyData(dragItem)[0]['maplayer'].GetCmd(string = True))
-            except:
-                pass
-            newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
-            newctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
-            data    = self.GetPyData(dragItem)
-
-        elif self.GetPyData(dragItem)[0]['type'] == 'group':
-            # recreate group
-            newctrl = None
-            data    = None
-            
-        # decide where to put recreated item
-        if dropTarget != None and dropTarget != self.GetRootItem():
-            if parent:
-                # new item is a group
-                afteritem = parent
-            else:
-                # new item is a single layer
-                afteritem = dropTarget
-
-            # dragItem dropped on group
-            if  self.GetPyData(afteritem)[0]['type'] == 'group':
-                newItem = self.PrependItem(afteritem, text = text, \
-                                      ct_type = 1, wnd = newctrl, image = image, \
-                                      data = data)
-                self.Expand(afteritem)
-            else:
-                #dragItem dropped on single layer
-                newparent = self.GetItemParent(afteritem)
-                newItem = self.InsertItem(newparent, self.GetPrevSibling(afteritem), \
-                                       text = text, ct_type = 1, wnd = newctrl, \
-                                       image = image, data = data)
-        else:
-            # if dragItem not dropped on a layer or group, append or prepend it to the layer tree
-            if self.flag & wx.TREE_HITTEST_ABOVE:
-                newItem = self.PrependItem(self.root, text = text, \
-                                      ct_type = 1, wnd = newctrl, image = image, \
-                                      data = data)
-            elif (self.flag &  wx.TREE_HITTEST_BELOW) or (self.flag & wx.TREE_HITTEST_NOWHERE) \
-                     or (self.flag & wx.TREE_HITTEST_TOLEFT) or (self.flag & wx.TREE_HITTEST_TORIGHT):
-                newItem = self.AppendItem(self.root, text = text, \
-                                      ct_type = 1, wnd = newctrl, image = image, \
-                                      data = data)
-
-        #update new layer 
-        self.SetPyData(newItem, self.GetPyData(dragItem))
-        if newctrl:
-            self.GetPyData(newItem)[0]['ctrl'] = newctrl.GetId()
-        else:
-            self.GetPyData(newItem)[0]['ctrl'] = None
-            
-        self.CheckItem(newItem, checked = checked) # causes a new render
-        
-        return newItem
-
-    def _getLayerName(self, item, lname = ''):
-        """!Get layer name string
-
-        @param lname optional layer name
-        """
-        mapLayer = self.GetPyData(item)[0]['maplayer']
-        if not mapLayer:
-            return lname
-        
-        if not lname:
-            lname  = self.GetPyData(item)[0]['label']
-        opacity  = int(mapLayer.GetOpacity(float = True) * 100)
-        if not lname:
-            dcmd    = self.GetPyData(item)[0]['cmd']
-            lname, found = utils.GetLayerNameFromCmd(dcmd, layerType = mapLayer.GetType(),
-                                                     fullyQualified = True)
-            if not found:
-                return None
-        
-        if opacity < 100:
-            return lname + ' (%s %d' % (_('opacity:'), opacity) + '%)'
-        
-        return lname
-                
-    def GetOptData(self, dcmd, layer, params, propwin):
-        """!Process layer data (when changes in properties dialog are applied)
-        """
-        # set layer text to map name
-        if dcmd:
-            self.GetPyData(layer)[0]['cmd'] = dcmd
-            mapText  = self._getLayerName(layer)
-            mapName, found = utils.GetLayerNameFromCmd(dcmd)
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            self.SetItemText(layer, mapName)
-            
-            if not mapText or not found:
-                propwin.Hide()
-                GWarning(parent = self,
-                         message = _("Map <%s> not found.") % mapName)
-                return
-        
-        # update layer data
-        if params:
-            self.SetPyData(layer, (self.GetPyData(layer)[0], params))
-        self.GetPyData(layer)[0]['propwin'] = propwin
-        
-        # change parameters for item in layers list in render.Map
-        self.ChangeLayer(layer)
-        
-        # set region if auto-zooming is enabled
-        if dcmd and UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            if mapLayer.GetType() in ('raster', 'vector'):
-                render = UserSettings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled')
-                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
-                                                    render = render)
-        
-        # update nviz session        
-        if self.lmgr.IsPaneShown('toolbarNviz') and dcmd:
-            mapLayer = self.GetPyData(layer)[0]['maplayer']
-            mapWin = self.mapdisplay.MapWindow
-            if len(mapLayer.GetCmd()) > 0:
-                id = -1
-                if mapLayer.type == 'raster':
-                    if mapWin.IsLoaded(layer):
-                        mapWin.UnloadRaster(layer)
-                    
-                    mapWin.LoadRaster(layer)
-                    
-                elif mapLayer.type == '3d-raster':
-                    if mapWin.IsLoaded(layer):
-                        mapWin.UnloadRaster3d(layer)
-                    
-                    mapWin.LoadRaster3d(layer)
-                    
-                elif mapLayer.type == 'vector':
-                    if mapWin.IsLoaded(layer):
-                        mapWin.UnloadVector(layer)
-                    
-                    mapWin.LoadVector(layer)
-
-                # reset view when first layer loaded
-                nlayers = len(mapWin.Map.GetListOfLayers(l_type = ('raster', 'vector'),
-                                                         l_active = True))
-                if nlayers < 2:
-                    mapWin.ResetView()
-        
-    def ReorderLayers(self):
-        """!Add commands from data associated with any valid layers
-        (checked or not) to layer list in order to match layers in
-        layer tree."""
-
-        # make a list of visible layers
-        treelayers = []
-        
-        vislayer = self.GetFirstVisibleItem()
-        
-        if not vislayer or self.GetPyData(vislayer) is None:
-            return
-        
-        itemList = ""
-        
-        for item in range(self.GetCount()):
-            itemList += self.GetItemText(vislayer) + ','
-            if self.GetPyData(vislayer)[0]['type'] != 'group':
-                treelayers.append(self.GetPyData(vislayer)[0]['maplayer'])
-
-            if not self.GetNextVisible(vislayer):
-                break
-            else:
-                vislayer = self.GetNextVisible(vislayer)
-        
-        Debug.msg (4, "LayerTree.ReorderLayers(): items=%s" % \
-                   (itemList))
-        
-        # reorder map layers
-        treelayers.reverse()
-        self.Map.ReorderLayers(treelayers)
-        self.reorder = False
-        
-    def ChangeLayer(self, item):
-        """!Change layer"""
-        type = self.GetPyData(item)[0]['type']
-        layerName = None
-        
-        if type == 'command':
-            win = self.FindWindowById(self.GetPyData(item)[0]['ctrl'])
-            if win.GetValue() != None:
-                cmd = win.GetValue().split(';')
-                cmdlist = []
-                for c in cmd:
-                    cmdlist.append(c.split(' '))
-                opac = 1.0
-                chk = self.IsItemChecked(item)
-                hidden = not self.IsVisible(item)
-        elif type != 'group':
-            if self.GetPyData(item)[0] is not None:
-                cmdlist = self.GetPyData(item)[0]['cmd']
-                opac = self.GetPyData(item)[0]['maplayer'].GetOpacity(float = True)
-                chk = self.IsItemChecked(item)
-                hidden = not self.IsVisible(item)
-                # determine layer name
-                layerName, found = utils.GetLayerNameFromCmd(cmdlist, fullyQualified = True)
-                if not found:
-                    layerName = self.GetItemText(item)
-        
-        maplayer = self.Map.ChangeLayer(layer = self.GetPyData(item)[0]['maplayer'], type = type,
-                                        command = cmdlist, name = layerName,
-                                        l_active = chk, l_hidden = hidden, l_opacity = opac, l_render = False)
-        
-        self.GetPyData(item)[0]['maplayer'] = maplayer
-        
-        # if digitization tool enabled -> update list of available vector map layers
-        if self.mapdisplay.GetToolbar('vdigit'):
-            self.mapdisplay.GetToolbar('vdigit').UpdateListOfLayers(updateTool = True)
-        
-        # redraw map if auto-rendering is enabled
-        self.rerender = True
-        self.reorder = True
-        
-    def OnCloseWindow(self, event):
-        pass
-        # self.Map.Clean()
-
-    def FindItemByData(self, key, value):
-        """!Find item based on key and value (see PyData[0]).
-        
-        If key is 'name', finds item(s) of given maplayer name.
-        
-        @return item instance
-        @return None not found
-        """
-        item = self.GetFirstChild(self.root)[0]
-        if key == 'name':
-            return self.__FindSubItemByName(item, value)
-        else:
-            return self.__FindSubItemByData(item, key, value)
-
-    def FindItemByIndex(self, index):
-        """!Find item by index (starting at 0)
-
-        @return item instance
-        @return None not found
-        """
-        item = self.GetFirstChild(self.root)[0]
-        i = 0
-        while item and item.IsOk():
-            if i == index:
-                return item
-            
-            item = self.GetNextVisible(item)
-            i += 1
-        
-        return None
-    
-    def EnableItemType(self, type, enable = True):
-        """!Enable/disable items in layer tree"""
-        item = self.GetFirstChild(self.root)[0]
-        while item and item.IsOk():
-            mapLayer = self.GetPyData(item)[0]['maplayer']
-            if mapLayer and type == mapLayer.type:
-                self.EnableItem(item, enable)
-            
-            item = self.GetNextSibling(item)
-        
-    def __FindSubItemByData(self, item, key, value):
-        """!Support method for FindItemByData"""
-        while item and item.IsOk():
-            try:
-                itemValue = self.GetPyData(item)[0][key]
-            except KeyError:
-                return None
-            
-            if value == itemValue:
-                return item
-            if self.GetPyData(item)[0]['type'] == 'group':
-                subItem = self.GetFirstChild(item)[0]
-                found = self.__FindSubItemByData(subItem, key, value)
-                if found:
-                    return found
-            item = self.GetNextSibling(item)
-
-        return None
-
-    def __FindSubItemByName(self, item, value):
-        """!Support method for FindItemByData for searching by name"""
-        items = []
-        while item and item.IsOk():
-            try:
-                itemLayer = self.GetPyData(item)[0]['maplayer']
-            except KeyError:
-                return None
-            
-            if value == itemLayer.GetName():
-                items.append(item)
-            if self.GetPyData(item)[0]['type'] == 'group':
-                subItem = self.GetFirstChild(item)[0]
-                found = self.__FindSubItemByName(subItem, name)
-                if found:
-                    items.extend(found)
-            item = self.GetNextSibling(item)
-        
-        if items:
-            return items
-        return None

Deleted: grass/trunk/gui/wxpython/gui_modules/location_wizard.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/location_wizard.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/location_wizard.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2670 +0,0 @@
-"""!
- at package location_wizard.py
-
- at brief Location wizard - creates a new GRASS Location. User can choose
-from multiple methods.
-
-Classes:
- - BaseClass
- - TitledPage
- - DatabasePage
- - CoordinateSystemPage
- - ProjectionsPage
- - ItemList
- - ProjParamsPage
- - DatumPage
- - EllipsePage
- - GeoreferencedFilePage
- - EPSGPage
- - CustomPage
- - SummaryPage
- - RegionDef
- - LocationWizard
- - SelectTransformDialog
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>   
-"""
-import os
-import shutil
-import string
-import sys
-import locale
-import platform
-
-import wx
-import wx.lib.mixins.listctrl as listmix
-import wx.wizard as wiz
-import wx.lib.scrolledpanel as scrolled
-import time
-
-import gcmd
-import globalvar
-import utils
-from grass.script import core as grass
-try:
-    import subprocess
-except:
-    CompatPath = os.path.join(globalvar.ETCWXDIR)
-    sys.path.append(CompatPath)
-    from compat import subprocess
-
-global coordsys
-global north
-global south
-global east
-global west
-global resolution
-global wizerror
-global translist
-
-class BaseClass(wx.Object):
-    """!Base class providing basic methods"""
-    def __init__(self):
-        pass
-
-    def MakeLabel(self, text = "", style = wx.ALIGN_LEFT, parent = None):
-        """!Make aligned label"""
-        if not parent:
-            parent = self
-        return wx.StaticText(parent = parent, id = wx.ID_ANY, label = text,
-                             style = style)
-
-    def MakeTextCtrl(self, text = '', size = (100,-1), style = 0, parent = None):
-        """!Generic text control"""
-        if not parent:
-            parent = self
-        return wx.TextCtrl(parent = parent, id = wx.ID_ANY, value = text,
-                           size = size, style = style)
-
-    def MakeButton(self, text, id = wx.ID_ANY, size = (-1,-1), parent = None):
-        """!Generic button"""
-        if not parent:
-            parent = self
-        return wx.Button(parent = parent, id = id, label = text,
-                         size = size)
-
-class TitledPage(BaseClass, wiz.WizardPageSimple):
-    """!Class to make wizard pages. Generic methods to make labels,
-    text entries, and buttons.
-    """
-    def __init__(self, parent, title):
-
-        self.page = wiz.WizardPageSimple.__init__(self, parent)
-
-        # page title
-        self.title = wx.StaticText(parent = self, id = wx.ID_ANY, label = title)
-        self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
-
-        # main sizers
-        self.pagesizer = wx.BoxSizer(wx.VERTICAL)
-        self.sizer = wx.GridBagSizer(vgap = 0, hgap = 0)
-        
-    def DoLayout(self):
-        """!Do page layout"""
-        self.pagesizer.Add(item = self.title, proportion = 0,
-                           flag = wx.ALIGN_CENTRE | wx.ALL,
-                           border = 5)
-        self.pagesizer.Add(item = wx.StaticLine(self, -1), proportion = 0,
-                           flag = wx.EXPAND | wx.ALL,
-                           border = 0)
-        self.pagesizer.Add(item = self.sizer, proportion = 1,
-                           flag = wx.EXPAND)
-        
-        self.SetAutoLayout(True)
-        self.SetSizer(self.pagesizer)
-        self.Layout()
-
-class DatabasePage(TitledPage):
-    """!Wizard page for setting GIS data directory and location name"""
-    def __init__(self, wizard, parent, grassdatabase):
-        TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
-
-        self.grassdatabase  = grassdatabase
-        self.location       = ''
-        self.locTitle       = ''
-        
-        # buttons
-        self.bbrowse = self.MakeButton(_("Browse"))
-
-        # text controls
-        self.tgisdbase = self.MakeTextCtrl(grassdatabase, size = (300, -1))
-        self.tlocation = self.MakeTextCtrl("newLocation", size = (300, -1))
-        self.tlocTitle = self.MakeTextCtrl(size = (400, -1))
-        
-        # layout
-        self.sizer.AddGrowableCol(3)
-        self.sizer.Add(item = self.MakeLabel(_("GIS Data Directory:")),
-                       flag = wx.ALIGN_RIGHT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (1, 1))
-        self.sizer.Add(item = self.tgisdbase,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (1, 2))
-        self.sizer.Add(item = self.bbrowse,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (1, 3))
-        
-        self.sizer.Add(item = self.MakeLabel("%s:" % _("Project Location")),
-                       flag = wx.ALIGN_RIGHT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (2, 1))
-        self.sizer.Add(item = self.tlocation,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (2, 2))
-
-        self.sizer.Add(item = self.MakeLabel("%s:" % _("Location Title")),
-                       flag = wx.ALIGN_RIGHT |
-                       wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (3, 1))
-        self.sizer.Add(item = self.tlocTitle,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5,
-                       pos = (3, 2), span  =  (1, 2))
-        
-        # bindings
-        self.Bind(wx.EVT_BUTTON,                self.OnBrowse, self.bbrowse)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.tgisdbase.Bind(wx.EVT_TEXT,        self.OnChangeName)
-        self.tlocation.Bind(wx.EVT_TEXT,        self.OnChangeName)
-        
-    def OnChangeName(self, event):
-        """!Name for new location was changed"""
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(event.GetString()) > 0:
-            if not nextButton.IsEnabled():
-                nextButton.Enable()
-        else:
-            nextButton.Disable()
-
-        event.Skip()
-
-    def OnBrowse(self, event):
-        """!Choose GRASS data directory"""
-        dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
-                           os.getcwd(), wx.DD_DEFAULT_STYLE)
-        if dlg.ShowModal() == wx.ID_OK:
-            self.grassdatabase = dlg.GetPath()
-            self.tgisdbase.SetValue(self.grassdatabase)
-            
-        dlg.Destroy()
-
-    def OnPageChanging(self, event = None):
-        error = None
-        if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
-            error = _("Location already exists in GRASS Database.")
-
-        if error:
-            gcmd.GError(parent = self,
-                        message="%s <%s>.%s%s" % (_("Unable to create location"),
-                                                  str(self.tlocation.GetValue()),
-                                                  os.linesep,
-                                                  error))
-            event.Veto()
-            return
-
-        self.location      = self.tlocation.GetValue()
-        self.grassdatabase = self.tgisdbase.GetValue()
-        self.locTitle      = self.tlocTitle.GetValue()
-        if os.linesep in self.locTitle or \
-                len(self.locTitle) > 255:
-            gcmd.GWarning(parent = self,
-                          message = _("Title of the location is limited only to one line and "
-                                      "256 characters. The rest of the text will be ignored."))
-            self.locTitle = self.locTitle.split(os.linesep)[0][:255]
-            
-class CoordinateSystemPage(TitledPage):
-    """!Wizard page for choosing method for location creation"""
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
-        
-        self.parent = parent
-        global coordsys
-        
-        # toggles
-        self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Select coordinate system parameters from a list"),
-                                     style  =  wx.RB_GROUP)
-        self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Select EPSG code of spatial reference system"))
-        self.radio3 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Read projection and datum terms from a "
-                                             "georeferenced data file"))
-        self.radio4 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Read projection and datum terms from a "
-                                             "WKT or PRJ file"))
-        self.radio5 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Specify projection and datum terms using custom "
-                                             "PROJ.4 parameters"))
-        self.radio6 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Create an arbitrary non-earth coordinate system (XY)"))
-        
-        # layout
-        self.sizer.AddGrowableCol(1)
-        self.sizer.SetVGap(10)
-        self.sizer.Add(item = self.radio1,
-                       flag = wx.ALIGN_LEFT, pos = (1, 1))
-        self.sizer.Add(item = self.radio2,
-                       flag = wx.ALIGN_LEFT, pos = (2, 1))
-        self.sizer.Add(item = self.radio3,
-                       flag = wx.ALIGN_LEFT, pos = (3, 1))
-        self.sizer.Add(item = self.radio4,
-                       flag = wx.ALIGN_LEFT, pos = (4, 1))
-        self.sizer.Add(item = self.radio5,
-                       flag = wx.ALIGN_LEFT, pos = (5, 1))
-        self.sizer.Add(item = self.radio6,
-                       flag = wx.ALIGN_LEFT, pos = (6, 1))
-
-        # bindings
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio3.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio4.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio5.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio6.GetId())
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
-        
-    def OnEnterPage(self, event):
-        global coordsys
-        
-        if not coordsys:
-            coordsys = "proj"
-            self.radio1.SetValue(True)
-        else:
-            if coordsys == 'proj':
-                self.radio1.SetValue(True)
-            if coordsys == "epsg":
-                self.radio2.SetValue(True)
-            if coordsys == "file":
-                self.radio3.SetValue(True)
-            if coordsys == "wkt":
-                self.radio4.SetValue(True)
-            if coordsys == "custom":
-                self.radio5.SetValue(True)
-            if coordsys == "xy":
-                self.radio6.SetValue(True)
-        
-        if event.GetDirection():
-            if coordsys == 'proj':
-                self.SetNext(self.parent.projpage)
-                self.parent.sumpage.SetPrev(self.parent.datumpage)
-            if coordsys == "epsg":
-                self.SetNext(self.parent.epsgpage)
-                self.parent.sumpage.SetPrev(self.parent.epsgpage)
-            if coordsys == "file":
-                self.SetNext(self.parent.filepage)
-                self.parent.sumpage.SetPrev(self.parent.filepage)
-            if coordsys == "wkt":
-                self.SetNext(self.parent.wktpage)
-                self.parent.sumpage.SetPrev(self.parent.wktpage)
-            if coordsys == "custom":
-                self.SetNext(self.parent.custompage)
-                self.parent.sumpage.SetPrev(self.parent.custompage)
-            if coordsys == "xy":
-                self.SetNext(self.parent.sumpage)
-                self.parent.sumpage.SetPrev(self.parent.csystemspage)
-        
-        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
-            wx.FindWindowById(wx.ID_FORWARD).Enable()
-    
-    def SetVal(self, event):
-        """!Choose method"""
-        global coordsys
-        if event.GetId() == self.radio1.GetId():
-            coordsys = "proj"
-            self.SetNext(self.parent.projpage)
-            self.parent.sumpage.SetPrev(self.parent.datumpage)
-        elif event.GetId() == self.radio2.GetId():
-            coordsys = "epsg"
-            self.SetNext(self.parent.epsgpage)
-            self.parent.sumpage.SetPrev(self.parent.epsgpage)
-        elif event.GetId() == self.radio3.GetId():
-            coordsys = "file"
-            self.SetNext(self.parent.filepage)
-            self.parent.sumpage.SetPrev(self.parent.filepage)
-        elif event.GetId() == self.radio4.GetId():
-            coordsys = "wkt"
-            self.SetNext(self.parent.wktpage)
-            self.parent.sumpage.SetPrev(self.parent.wktpage)
-        elif event.GetId() == self.radio5.GetId():
-            coordsys = "custom"
-            self.SetNext(self.parent.custompage)
-            self.parent.sumpage.SetPrev(self.parent.custompage)
-        elif event.GetId() == self.radio6.GetId():
-            coordsys = "xy"
-            self.SetNext(self.parent.sumpage)
-            self.parent.sumpage.SetPrev(self.parent.csystemspage)
-
-class ProjectionsPage(TitledPage):
-    """!Wizard page for selecting projection (select coordinate system option)"""
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Choose projection"))
-
-        self.parent = parent
-        self.proj = ''
-        self.projdesc = ''
-        self.p4proj = ''
-
-        # text input
-        self.tproj = self.MakeTextCtrl("", size = (200,-1))
-        
-        # search box
-        self.searchb = wx.SearchCtrl(self, size = (200,-1),
-                                     style = wx.TE_PROCESS_ENTER)
-
-        # projection list
-        self.projlist = ItemList(self, data = self.parent.projdesc.items(),
-                                 columns = [_('Code'), _('Description')])
-        self.projlist.resizeLastColumn(30) 
-
-        # layout
-        self.sizer.AddGrowableCol(3)
-        self.sizer.Add(item = self.MakeLabel(_("Projection code:")),
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.tproj,
-                       flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
-                       border = 5, pos = (1, 2))
-
-        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
-                       flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
-                       border = 5, pos = (2, 1))
-        self.sizer.Add(item = self.searchb,
-                       flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
-                       border = 5, pos = (2, 2))
-        
-        self.sizer.AddGrowableRow(3)
-        self.sizer.Add(item = self.projlist,
-                       flag = wx.EXPAND |
-                       wx.ALIGN_LEFT |
-                       wx.ALL, border = 5, pos = (3, 1), span = (1, 3))
-
-        # events
-        self.tproj.Bind(wx.EVT_TEXT, self.OnText)
-        self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
-        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
-        self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
-        
-    def OnPageChanging(self,event):
-        if event.GetDirection() and self.proj not in self.parent.projections.keys():
-            event.Veto()
-
-    def OnText(self, event):
-        """!Projection name changed"""
-        self.proj = event.GetString().lower()
-        self.p4proj = ''
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled():
-            nextButton.Enable(False)
-        
-        if self.proj in self.parent.projections.keys():
-            if self.proj == 'stp':
-                wx.MessageBox('Currently State Plane projections must be selected using the '
-                              'text-based setup (g.setproj), or entered by EPSG code or '
-                              'custom PROJ.4 terms.',
-                              'Warning', wx.ICON_WARNING)
-                self.proj = ''
-                self.tproj.SetValue(self.proj)
-                nextButton.Enable(False)
-                return
-            elif self.proj.lower() == 'll':
-                self.p4proj = '+proj=longlat'
-            else:
-                self.p4proj = '+proj=' + self.proj.lower()
-            self.projdesc = self.parent.projections[self.proj][0]
-            nextButton.Enable()
-
-    def OnEnterPage(self, event):
-        if len(self.proj) == 0:
-            # disable 'next' button by default
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        event.Skip()
-    
-    def OnSearch(self, event):
-        """!Search projection by desc"""
-        str = event.GetString()
-        try:
-            self.proj, self.projdesc = self.projlist.Search(index = [0,1], pattern = event.GetString())
-        except:
-            self.proj = self.projdesc = ''
-            
-        event.Skip()
-
-    def OnItemSelected(self, event):
-        """!Projection selected"""
-        index = event.m_itemIndex
-
-        # set values
-        self.proj = self.projlist.GetItem(index, 0).GetText().lower()
-        self.tproj.SetValue(self.proj)
-        
-        event.Skip()
-
-class ItemList(wx.ListCtrl,
-               listmix.ListCtrlAutoWidthMixin,
-               listmix.ColumnSorterMixin):
-    """!Generic list (for projections, ellipsoids, etc.)"""
-
-    def __init__(self, parent, columns, data = None):
-        wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
-                             style = wx.LC_REPORT |
-                             wx.LC_VIRTUAL | 
-                             wx.LC_HRULES |
-                             wx.LC_VRULES |
-                             wx.LC_SINGLE_SEL |
-                             wx.LC_SORT_ASCENDING, size = (550, 125))
-
-        # original data or None
-        self.sourceData = data
-        
-        #
-        # insert columns
-        #
-        i = 0
-        for column in columns:
-            self.InsertColumn(i, column)
-            i += 1
-
-        if self.sourceData:
-            self.Populate()
-        
-        for i in range(self.GetColumnCount()):
-            self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
-            if self.GetColumnWidth(i) < 80:
-                self.SetColumnWidth(i, 80)
-        
-        #
-        # listmix
-        #
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
-            
-        #
-        # add some attributes
-        #
-        self.attr1 = wx.ListItemAttr()
-        self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
-        self.attr2 = wx.ListItemAttr()
-        self.attr2.SetBackgroundColour("white")
-        self.il = wx.ImageList(16, 16)
-        self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
-                                                          (16,16)))
-        self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
-                                                          (16,16)))
-        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
-
-        #
-        # sort by first column
-        #
-        if self.sourceData:
-            self.SortListItems(col = 0, ascending = True)
-
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
-
-    def Populate(self, data = None, update = False):
-        """!Populate list"""
-        self.itemDataMap  = {}
-        self.itemIndexMap = []
-        
-        if data is None:
-            data = self.sourceData
-        elif update:
-            self.sourceData = data
-
-        try:
-            data.sort()
-            self.DeleteAllItems()
-            row = 0
-            for value in data:
-                self.itemDataMap[row] = [value[0]]
-                for i in range(1, len(value)):
-                     self.itemDataMap[row].append(value[i])
-                self.itemIndexMap.append(row)
-                row += 1
-
-            self.SetItemCount(row)
-            
-            # set column width
-            self.SetColumnWidth(0, 80)
-            self.SetColumnWidth(1, 300)
-            
-            self.SendSizeEvent()
-            
-        except StandardError, e:
-            wx.MessageBox(parent = self,
-                          message = _("Unable to read list: %s") % e,
-                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
-
-    def OnColumnClick(self, event):
-        """!Sort by column"""
-        self._col = event.GetColumn()
-
-        # remove duplicated arrow symbol from column header
-        # FIXME: should be done automatically
-        info = wx.ListItem()
-        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
-        info.m_image = -1
-        for column in range(self.GetColumnCount()):
-            info.m_text = self.GetColumn(column).GetText()
-            self.SetColumn(column, info)
-
-        event.Skip()
-
-    def GetSortImages(self):
-        """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
-        return (self.sm_dn, self.sm_up)
-
-    def OnGetItemText(self, item, col):
-        """!Get item text"""
-        index = self.itemIndexMap[item]
-        s = str(self.itemDataMap[index][col])
-        return s
-
-    def OnGetItemAttr(self, item):
-        """!Get item attributes"""
-        index = self.itemIndexMap[item]
-        if ( index % 2) == 0:
-            return self.attr2
-        else:
-            return self.attr1
-
-    def SortItems(self, sorter = cmp):
-        """!Sort items"""
-        items = list(self.itemDataMap.keys())
-        items.sort(self.Sorter)
-        self.itemIndexMap = items
-
-        # redraw the list
-        self.Refresh()
-        
-    def Sorter(self, key1, key2):
-        colName = self.GetColumn(self._col).GetText()
-        ascending = self._colSortFlag[self._col]
-        # convert always string
-        item1 = self.itemDataMap[key1][self._col]
-        item2 = self.itemDataMap[key2][self._col]
-
-        if type(item1) == type('') or type(item2) == type(''):
-            cmpVal = locale.strcoll(str(item1), str(item2))
-        else:
-            cmpVal = cmp(item1, item2)
-
-
-        # If the items are equal then pick something else to make the sort value unique
-        if cmpVal == 0:
-            cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
-
-        if ascending:
-            return cmpVal
-        else:
-            return -cmpVal
-
-    def GetListCtrl(self):
-        """!Used by listmix.ColumnSorterMixin"""
-        return self
-
-    def Search (self, index, pattern):
-        """!Search projection by description
-        Return first found item or None
-        """
-        if pattern == '':
-            self.Populate(self.sourceData)
-            return []
-
-        data = []
-        pattern = pattern.lower()
-        for i in range(len(self.sourceData)):
-            for idx in index:
-                try:
-                    value = str(self.sourceData[i][idx]).lower()
-                    if pattern in value:
-                        data.append(self.sourceData[i])
-                        break
-                except UnicodeDecodeError:
-                    # osgeo4w problem (should be fixed)
-                    pass
-
-        self.Populate(data)
-        if len(data) > 0:
-            return data[0]
-        else:
-            return []
-
-class ProjParamsPage(TitledPage):
-    """!Wizard page for selecting method of setting coordinate system
-    parameters (select coordinate system option)
-    """
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Choose projection parameters"))
-        global coordsys
-        
-        self.parent = parent
-        self.panel = None
-        self.prjParamSizer = None
-        
-        self.pparam = dict()
-        
-        self.p4projparams = ''
-        self.projdesc = ''
-
-        self.sizer.AddGrowableCol(1)
-        self.sizer.AddGrowableRow(1)
-
-        radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                 label = " %s " % _("Select datum or ellipsoid (next page)"))
-        radioSBSizer = wx.StaticBoxSizer(radioSBox)
-        self.sizer.Add(item = radioSBSizer, pos = (0, 1),
-                       flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
-        
-        self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY, 
-                                     label = _("Datum with associated ellipsoid"),
-                                     style  =  wx.RB_GROUP)
-        self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
-                                     label = _("Ellipsoid only"))   
-        
-        # default button setting
-        if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
-            self.radio1.SetValue(True)
-            self.SetNext(self.parent.datumpage)
-            #            self.parent.sumpage.SetPrev(self.parent.datumpage)  
-        
-        radioSBSizer.Add(item = self.radio1,
-                         flag = wx.ALIGN_LEFT | wx.RIGHT, border = 20)
-        radioSBSizer.Add(item = self.radio2,
-                         flag = wx.ALIGN_LEFT)
-        
-        # bindings
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
-        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-        
-    def OnParamEntry(self, event):
-        """!Parameter value changed"""
-        id  = event.GetId()
-        val = event.GetString()
-        
-        if id not in self.pparam:
-            event.Skip()
-            return
-
-        param = self.pparam[id]
-        win = self.FindWindowById(id)
-        if param['type'] == 'zone':
-            val = event.GetInt()
-            if val < 1:
-                win.SetValue(1)
-            elif val > 60:
-                    win.SetValue(60)
-        
-        if param['type'] == 'bool':
-            param['value'] = event.GetSelection()
-        else:
-            param['value'] = val
-        
-        event.Skip()
-        
-    def OnPageChange(self,event=None):
-        """!Go to next page"""
-        if event.GetDirection():
-            self.p4projparams = ''
-            for id, param in self.pparam.iteritems():
-                if param['type'] == 'bool':
-                    if param['value'] == False:
-                        continue
-                    else:
-                        self.p4projparams += (' +' + param['proj4'])
-                else:
-                    if param['value'] is None:
-                        wx.MessageBox(parent = self,
-                                      message = _('You must enter a value for %s') % param['desc'],
-                                      caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
-                        event.Veto()
-                    else:
-                        self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
-
-    def OnEnterPage(self,event):
-        """!Page entered"""
-        self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
-        if self.prjParamSizer is None:
-            # entering page for the first time
-            self.paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                                     label = _(" Enter parameters for %s projection ") % self.projdesc)
-            paramSBSizer = wx.StaticBoxSizer(self.paramSBox)
-            
-            self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
-            self.panel.SetupScrolling()
-            
-            self.prjParamSizer = wx.GridBagSizer(vgap = 0, hgap = 0) 
-            
-            self.sizer.Add(item = paramSBSizer, pos = (1, 1),
-                           flag = wx.EXPAND)
-            paramSBSizer.Add(item = self.panel, proportion = 1, 
-                             flag = wx.ALIGN_CENTER | wx.EXPAND)
-            
-            paramSBSizer.Fit(self.panel)
-            self.panel.SetSizer(self.prjParamSizer)
-                    
-        if event.GetDirection(): 
-            self.prjParamSizer.Clear(True)
-            self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
-            self.pparam = dict()
-            row = 0
-            for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
-                # get parameters
-                id = wx.NewId()
-                param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
-                                            'proj4': self.parent.paramdesc[paramgrp[0]][1],
-                                            'desc' : self.parent.paramdesc[paramgrp[0]][2] }
-                
-                # default values
-                if param['type'] == 'bool':
-                    param['value'] = 0
-                elif param['type'] == 'zone': 
-                    param['value'] = 30 
-                    param['desc'] += ' (1-60)'
-                else:
-                    param['value'] = paramgrp[2]
-                
-                label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'], 
-                                      style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
-                if param['type'] == 'bool':
-                    win = wx.Choice(parent = self.panel, id = id, size = (100,-1), 
-                                    choices = [_('No'), _('Yes')])  
-                    win.SetSelection(param['value'])
-                    win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
-                elif param['type'] == 'zone':
-                    win = wx.SpinCtrl(parent = self.panel, id = id,
-                                      size = (100, -1), 
-                                      style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
-                                      min = 1, max = 60)
-                    win.SetValue(param['value'])
-                    win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
-                    win.Bind(wx.EVT_TEXT, self.OnParamEntry)
-                else:
-                    win = wx.TextCtrl(parent = self.panel, id = id,
-                                      value = param['value'],
-                                      size=(100, -1))
-                    win.Bind(wx.EVT_TEXT, self.OnParamEntry)
-                    if paramgrp[1] == 'noask':
-                        win.Enable(False)
-                    
-                self.prjParamSizer.Add(item = label, pos = (row, 1),
-                                       flag = wx.ALIGN_RIGHT | 
-                                       wx.ALIGN_CENTER_VERTICAL |
-                                       wx.RIGHT, border = 5)
-                self.prjParamSizer.Add(item = win, pos = (row, 2),
-                                       flag = wx.ALIGN_LEFT | 
-                                       wx.ALIGN_CENTER_VERTICAL |
-                                       wx.LEFT, border = 5)           
-                row += 1
-        
-        self.panel.SetSize(self.panel.GetBestSize())
-        self.panel.Layout()
-        self.Layout()
-        self.Update()
-        
-        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
-            wx.FindWindowById(wx.ID_FORWARD).Enable()
-        
-        event.Skip()
-
-    def SetVal(self, event):
-        """!Set value"""
-        if event.GetId() == self.radio1.GetId():
-            self.SetNext(self.parent.datumpage)
-            self.parent.sumpage.SetPrev(self.parent.datumpage)
-        elif event.GetId() == self.radio2.GetId():
-            self.SetNext(self.parent.ellipsepage)
-            self.parent.sumpage.SetPrev(self.parent.ellipsepage)
-    
-class DatumPage(TitledPage):
-    """!Wizard page for selecting datum (with associated ellipsoid)
-    and datum transformation parameters (select coordinate system option)
-    """
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
-
-        self.parent = parent
-        self.datum = ''
-        self.datumdesc = ''
-        self.ellipse = ''
-        self.datumparams = ''
-        self.proj4params = ''
-
-        # text input
-        self.tdatum = self.MakeTextCtrl("", size = (200,-1))
-
-        # search box
-        self.searchb = wx.SearchCtrl(self, size = (200,-1),
-                                     style = wx.TE_PROCESS_ENTER)
-
-        # create list control for datum/elipsoid list
-        data = []
-        for key in self.parent.datums.keys():
-            data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
-        self.datumlist = ItemList(self,
-                                  data = data,
-                                  columns = [_('Code'), _('Ellipsoid'), _('Description')])
-        self.datumlist.resizeLastColumn(10) 
-        
-        # layout
-        self.sizer.AddGrowableCol(4)
-        self.sizer.Add(item = self.MakeLabel(_("Datum code:")),
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.tdatum,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 2))
-
-        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 1))
-        self.sizer.Add(item = self.searchb,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 2))
-
-        self.sizer.AddGrowableRow(3)
-        self.sizer.Add(item = self.datumlist,
-                       flag = wx.EXPAND |
-                       wx.ALIGN_LEFT |
-                       wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
-
-        # events
-        self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
-        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
-        self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
-        self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-
-        # do page layout
-        # self.DoLayout()
-
-    def OnPageChanging(self, event):
-        self.proj4params = ''
-        proj = self.parent.projpage.p4proj
-                
-        if event.GetDirection():
-            if self.datum not in self.parent.datums:
-                event.Veto()
-            else:
-                # check for datum tranforms            
-#                proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
-                ret = gcmd.RunCommand('g.proj',
-                                      read = True,
-                                      proj4 = '%s +datum=%s' % (proj, self.datum), 
-                                      datumtrans = '-1')
-                if ret != '':
-                    dtrans = ''
-                    # open a dialog to select datum transform number
-                    dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
-                    
-                    if dlg.ShowModal() == wx.ID_OK:
-                        dtrans = dlg.GetTransform()
-                        if dtrans == '':
-                            dlg.Destroy()
-                            event.Veto()
-                            return 'Datum transform is required.'
-                    else:
-                        dlg.Destroy()
-                        event.Veto()
-                        return 'Datum transform is required.'
-                    
-                    self.parent.datumtrans = dtrans
-                
-            self.GetNext().SetPrev(self)
-            self.parent.ellipsepage.ellipse = self.ellipse
-            self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
-
-    def OnEnterPage(self,event):
-        self.parent.datumtrans = None
-        if event.GetDirection():
-            if len(self.datum) == 0:
-                # disable 'next' button by default when entering from previous page
-                wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-            else:
-                wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        event.Skip()
-
-    def OnDText(self, event):
-        """!Datum code changed"""
-        self.datum = event.GetString()
-
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(self.datum) == 0 or self.datum not in self.parent.datums:
-            nextButton.Enable(False)
-        else:
-            self.ellipse = self.parent.datums[self.datum][0]
-            self.datumdesc = self.parent.datums[self.datum][1]
-            self.datumparams = self.parent.datums[self.datum][2]
-            try:
-                self.datumparams.remove('dx=0.0')
-            except:
-                pass
-            try:
-                self.datumparams.remove('dy=0.0')
-            except:
-                pass
-            try:
-                self.datumparams.remove('dz=0.0')
-            except:
-                pass
-            
-            nextButton.Enable(True)
-            
-        self.Update()    
-        event.Skip()
-
-    def OnDSearch(self, event):
-        """!Search geodetic datum by desc"""
-        str =  self.searchb.GetValue()
-        try:
-            self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index = [0,1,2], pattern = str)
-        except:
-            self.datum = self.datumdesc = self.ellipsoid = ''
-
-        event.Skip()
-
-    def OnDatumSelected(self, event):
-        """!Datum selected"""
-        index = event.m_itemIndex
-        item = event.GetItem()
-
-        self.datum = self.datumlist.GetItem(index, 0).GetText()
-        self.tdatum.SetValue(self.datum)
-        
-        event.Skip()
-
-class EllipsePage(TitledPage):
-    """!Wizard page for selecting ellipsoid (select coordinate system option)"""
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
-
-        self.parent = parent
-        
-        self.ellipse = ''
-        self.ellipsedesc = ''
-        self.ellipseparams = ''
-        self.proj4params = ''
-
-        # text input
-        self.tellipse = self.MakeTextCtrl("", size = (200,-1))
-
-        # search box
-        self.searchb = wx.SearchCtrl(self, size = (200,-1),
-                                     style = wx.TE_PROCESS_ENTER)
-
-        # create list control for ellipse list
-        data = []
-        # extract code, desc
-        for key in self.parent.ellipsoids.keys():
-            data.append([key, self.parent.ellipsoids[key][0]])
-
-        self.ellipselist = ItemList(self, data = data,
-                                    columns = [_('Code'), _('Description')])
-        self.ellipselist.resizeLastColumn(30)                             
-
-        # layout
-        self.sizer.AddGrowableCol(4)
-        self.sizer.Add(item = self.MakeLabel(_("Ellipsoid code:")),
-                       flag = wx.ALIGN_RIGHT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.tellipse,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 2))
-        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
-                       flag = wx.ALIGN_RIGHT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 1))
-        self.sizer.Add(item = self.searchb,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 2))
-
-        self.sizer.AddGrowableRow(3)
-        self.sizer.Add(item = self.ellipselist,
-                       flag = wx.EXPAND |
-                       wx.ALIGN_LEFT |
-                       wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
-
-        # events
-        self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED,    self.OnItemSelected)
-        self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
-        self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
-        self.searchb.Bind(wx.EVT_TEXT_ENTER,    self.OnSearch)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-
-    def OnEnterPage(self,event):
-        if len(self.ellipse) == 0:
-            # disable 'next' button by default
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        event.Skip()
-
-    def OnPageChanging(self, event):
-        if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
-            event.Veto()
-
-        self.proj4params = ''
-        self.GetNext().SetPrev(self)
-        self.parent.datumpage.datumparams = ''
-        # self.GetNext().SetPrev(self) (???)
-
-    def OnText(self, event):
-        """!Ellipspoid code changed"""
-        self.ellipse = event.GetString()
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
-            nextButton.Enable(False)
-            self.ellipsedesc = ''
-            self.ellipseparams = ''
-            self.proj4params = ''
-        elif self.ellipse in self.parent.ellipsoids:
-            self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
-            self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
-            nextButton.Enable(True)
-
-    def OnSearch(self, event):
-        """!Search ellipsoid by desc"""
-        try:
-            self.ellipse, self.ellipsedesc = \
-                self.ellipselist.Search(index=[0,1], pattern=event.GetString())
-            self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
-        except:
-            self.ellipse = self.ellipsedesc = self.ellipseparams = ''
-
-        event.Skip()
-
-    def OnItemSelected(self,event):
-        """!Ellipsoid selected"""
-        index = event.m_itemIndex
-        item = event.GetItem()
-
-        self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
-        self.tellipse.SetValue(self.ellipse)
-        
-        event.Skip()
-
-class GeoreferencedFilePage(TitledPage):
-    """!Wizard page for selecting georeferenced file to use
-    for setting coordinate system parameters"""
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Select georeferenced file"))
-
-        self.georeffile = ''
-
-        # create controls
-        self.lfile= self.MakeLabel(_("Georeferenced file:"))
-        self.tfile = self.MakeTextCtrl(size = (300,-1))
-        self.bbrowse = self.MakeButton(_("Browse"))
-
-        # do layout
-        self.sizer.AddGrowableCol(3)
-        self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTRE_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTRE_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 2))
-        self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
-                       wx.ALL, border = 5, pos = (1, 3))
-
-        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
-        self.tfile.Bind(wx.EVT_TEXT, self.OnText)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-
-        # do page layout
-        # self.DoLayout()
-
-    def OnEnterPage(self, event):
-        if len(self.georeffile) == 0:
-            # disable 'next' button by default
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        event.Skip()
-
-    def OnPageChanging(self, event):
-        if event.GetDirection() and not os.path.isfile(self.georeffile):
-            event.Veto()
-        self.GetNext().SetPrev(self)
-
-        event.Skip()
-
-    def OnText(self, event):
-        """!File changed"""
-        self.georeffile = event.GetString()
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
-            if not nextButton.IsEnabled():
-                nextButton.Enable(True)
-        else:
-            if nextButton.IsEnabled():
-                nextButton.Enable(False)
-
-        event.Skip()
-
-    def OnBrowse(self, event):
-        """!Choose file"""
-        dlg = wx.FileDialog(self,
-                            _("Select georeferenced file"),
-                            os.getcwd(), "", "*.*", wx.OPEN)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            self.tfile.SetValue(path)
-        dlg.Destroy()
-
-        event.Skip()
-
-class WKTPage(TitledPage):
-    """!Wizard page for selecting WKT file to use
-    for setting coordinate system parameters"""
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Select WKT file"))
-
-        self.wktfile = ''
-
-        # create controls
-        self.lfile= self.MakeLabel(_("WKT file:"))
-        self.tfile = self.MakeTextCtrl(size = (300,-1))
-        self.bbrowse = self.MakeButton(_("Browse"))
-
-        # do layout
-        self.sizer.AddGrowableCol(3)
-        self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTRE_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTRE_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 2))
-        self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
-                       wx.ALL, border = 5, pos = (1, 3))
-
-        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
-        self.tfile.Bind(wx.EVT_TEXT, self.OnText)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-
-    def OnEnterPage(self, event):
-        if len(self.wktfile) == 0:
-            # disable 'next' button by default
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        event.Skip()
-
-    def OnPageChanging(self, event):
-        if event.GetDirection() and not os.path.isfile(self.wktfile):
-            event.Veto()
-        self.GetNext().SetPrev(self)
-
-        event.Skip()
-
-    def OnText(self, event):
-        """!File changed"""
-        self.wktfile = event.GetString()
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
-            if not nextButton.IsEnabled():
-                nextButton.Enable(True)
-        else:
-            if nextButton.IsEnabled():
-                nextButton.Enable(False)
-
-        event.Skip()
-
-    def OnBrowse(self, event):
-        """!Choose file"""
-        dlg = wx.FileDialog(self,
-                            _("Select WKT file"),
-                            os.getcwd(), "", "*.*", wx.OPEN)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            self.tfile.SetValue(path)
-        dlg.Destroy()
-
-        event.Skip()
-
-class EPSGPage(TitledPage):
-    """!Wizard page for selecting EPSG code for
-    setting coordinate system parameters"""
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
-        self.parent = parent
-        self.epsgCodeDict = {}
-        self.epsgcode = None
-        self.epsgdesc = ''
-        self.epsgparams = ''
-
-        # labels
-        self.lfile = self.MakeLabel(_("Path to the EPSG-codes file:"),
-                                    style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
-        self.lcode = self.MakeLabel(_("EPSG code:"),
-                                    style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
-        # text input
-        epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
-        self.tfile = self.MakeTextCtrl(text = epsgdir, size = (200,-1),
-                                       style = wx.TE_PROCESS_ENTER)
-        self.tcode = self.MakeTextCtrl(size = (200,-1))
-
-        # buttons
-        self.bbrowse = self.MakeButton(_("Browse"))
-        
-        # search box
-        self.searchb = wx.SearchCtrl(self, size = (200,-1),
-                                     style = wx.TE_PROCESS_ENTER)
-
-        self.epsglist = ItemList(self, data = None,
-                                 columns = [_('Code'), _('Description'), _('Parameters')])
-
-        # layout
-        self.sizer.AddGrowableCol(3)
-        self.sizer.Add(item = self.lfile,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 1), span = (1, 2))
-        self.sizer.Add(item = self.tfile,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 3))
-        self.sizer.Add(item = self.bbrowse,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (1, 4))
-        self.sizer.Add(item = self.lcode,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 1), span = (1, 2))
-        self.sizer.Add(item = self.tcode,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (2, 3))
-        self.sizer.Add(item = self.searchb,
-                       flag = wx.ALIGN_LEFT |
-                       wx.ALIGN_CENTER_VERTICAL |
-                       wx.ALL, border = 5, pos = (3, 3))
-        
-        self.sizer.AddGrowableRow(4)
-        self.sizer.Add(item = self.epsglist,
-                       flag = wx.ALIGN_LEFT | wx.EXPAND, pos = (4, 1),
-                       span = (1, 4))
-
-        # events
-        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
-        self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
-        self.tcode.Bind(wx.EVT_TEXT, self.OnText)
-        self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
-        self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
-        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-
-    def OnEnterPage(self, event):
-        self.parent.datumtrans = None
-        if event.GetDirection():
-            if not self.epsgcode:
-                # disable 'next' button by default
-                wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-            else:
-                wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-        # load default epsg database file
-        self.OnBrowseCodes(None)
-        
-        event.Skip()
-
-    def OnPageChanging(self, event):
-        if event.GetDirection():
-            if not self.epsgcode:
-                event.Veto()
-                return
-            else:              
-                # check for datum transforms
-                ret = gcmd.RunCommand('g.proj',
-                                      read = True,
-                                      epsg = self.epsgcode,
-                                      datumtrans = '-1')
-                
-                if ret != '':
-                    dtrans = ''
-                    # open a dialog to select datum transform number
-                    dlg = SelectTransformDialog(self.parent.parent, transforms = ret)
-                    
-                    if dlg.ShowModal() == wx.ID_OK:
-                        dtrans = dlg.GetTransform()
-                        if dtrans == '':
-                            dlg.Destroy()
-                            event.Veto()
-                            return 'Datum transform is required.'
-                    else:
-                        dlg.Destroy()
-                        event.Veto()
-                        return 'Datum transform is required.'
-                    
-                    self.parent.datumtrans = dtrans
-            self.GetNext().SetPrev(self)
-
-    def OnText(self, event):
-        self.epsgcode = event.GetString()
-        try:
-            self.epsgcode = int(self.epsgcode)
-        except:
-            self.epsgcode = None
-            
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-
-        if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
-            self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
-            self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
-            if not nextButton.IsEnabled():
-                nextButton.Enable(True)
-        else:
-            self.epsgcode = None # not found
-            if nextButton.IsEnabled():
-                nextButton.Enable(False)
-            self.epsgdesc = self.epsgparams = ''
-        
-    def OnSearch(self, event):
-        value =  self.searchb.GetValue()
-        
-        if value == '':
-            self.epsgcode = None
-            self.epsgdesc = self.epsgparams = ''
-            self.tcode.SetValue('')
-            self.searchb.SetValue('')
-            self.OnBrowseCodes(None)
-        else:    
-            try:
-                self.epsgcode, self.epsgdesc, self.epsgparams = \
-                        self.epsglist.Search(index=[0,1,2], pattern=value)
-            except (IndexError, ValueError): # -> no item found
-                self.epsgcode = None
-                self.epsgdesc = self.epsgparams = ''
-                self.tcode.SetValue('')
-                self.searchb.SetValue('')
-
-        event.Skip()
-        
-    def OnBrowse(self, event):
-        """!Define path for EPSG code file"""
-        path = os.path.dirname(self.tfile.GetValue())
-        if not path:
-            path = os.getcwd()
-        
-        dlg = wx.FileDialog(parent = self, message = _("Choose EPSG codes file"),
-                            defaultDir = path, defaultFile = "", wildcard = "*", style = wx.OPEN)
-        
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            self.tfile.SetValue(path)
-            self.OnBrowseCodes(None)
-        
-        dlg.Destroy()
-
-        event.Skip()
-
-    def OnItemSelected(self, event):
-        """!EPSG code selected from the list"""
-        index = event.m_itemIndex
-        item = event.GetItem()
-
-        self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
-        self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
-        self.tcode.SetValue(str(self.epsgcode))
-
-        event.Skip()
-        
-    def OnBrowseCodes(self, event, search = None):
-        """!Browse EPSG codes"""
-        self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
-
-        if type(self.epsgCodeDict) != dict:
-            wx.MessageBox(parent = self,
-                          message = _("Unable to read EPGS codes: %s") % self.epsgCodeDict,
-                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            self.epsglist.Populate(list(), update = True)
-            return
-        
-        data = list()
-        for code, val in self.epsgCodeDict.iteritems():
-            if code is not None:
-                data.append((code, val[0], val[1]))
-        
-        self.epsglist.Populate(data, update = True)
-        
-class CustomPage(TitledPage):
-    """!Wizard page for entering custom PROJ.4 string
-    for setting coordinate system parameters"""
-
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard,
-                            _("Choose method of specifying georeferencing parameters"))
-        global coordsys
-        self.customstring = ''
-        self.parent = parent
-
-        # widgets
-        self.text_proj4string = self.MakeTextCtrl(size = (400, 200),
-                                                  style = wx.TE_MULTILINE)
-        self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
-
-        # layout
-        self.sizer.AddGrowableCol(2)
-        self.sizer.Add(self.label_proj4string,
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (1, 1))
-        self.sizer.AddGrowableRow(2)
-        self.sizer.Add(self.text_proj4string,
-                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 
-                       border = 5, pos = (2, 1), span = (1, 2))
-
-        self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-
-    def OnEnterPage(self, event):
-        if len(self.customstring) == 0:
-            # disable 'next' button by default
-            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
-        else:
-            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
-
-    def OnPageChanging(self, event):
-        if event.GetDirection():
-        # check for datum tranforms            
-            ret, out, err = gcmd.RunCommand('g.proj',
-                                            read = True, getErrorMsg = True,
-                                            proj4 = self.customstring, 
-                                            datumtrans = '-1')
-            if ret != 0:
-                wx.MessageBox(parent = self,
-                              message = err,
-                              caption = _("Error"),
-                              style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                event.Veto()
-                return
-            
-            if out:
-                dtrans = ''
-                # open a dialog to select datum transform number
-                dlg = SelectTransformDialog(self.parent.parent, transforms = out)
-                
-                if dlg.ShowModal() == wx.ID_OK:
-                    dtrans = dlg.GetTransform()
-                    if len(dtrans) == 0:
-                        dlg.Destroy()
-                        event.Veto()
-                        return _('Datum transform is required.')
-                else:
-                    dlg.Destroy()
-                    event.Veto()
-                    return _('Datum transform is required.')
-                
-                self.parent.datumtrans = dtrans
-        
-        self.GetNext().SetPrev(self)
-            
-    def GetProjstring(self, event):
-        """!Change proj string"""
-        # TODO: check PROJ.4 syntax
-        self.customstring = event.GetString()
-        nextButton = wx.FindWindowById(wx.ID_FORWARD)
-        if len(self.customstring) == 0:
-            if nextButton.IsEnabled():
-                nextButton.Enable(False)
-        else:
-            if not nextButton.IsEnabled():
-                nextButton.Enable()
-
-class SummaryPage(TitledPage):
-    """!Shows summary result of choosing coordinate system parameters
-    prior to creating location"""
-    def __init__(self, wizard, parent):
-        TitledPage.__init__(self, wizard, _("Summary"))
-        self.parent = parent
-
-        self.panelTitle = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
-        self.panelProj4string = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
-        self.panelProj = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
-
-        # labels
-        self.ldatabase    = self.MakeLabel()
-        self.llocation    = self.MakeLabel()
-        self.llocTitle    = self.MakeLabel(parent = self.panelTitle)
-        self.lprojection  = self.MakeLabel(parent = self.panelProj)
-        self.lproj4string = self.MakeLabel(parent = self.panelProj4string)
-        
-        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
-        
-        # do sub-page layout
-        self._doLayout()
-        
-    def _doLayout(self):
-        """!Do page layout"""
-        self.sizer.AddGrowableCol(1)
-        self.sizer.AddGrowableRow(3, 1)
-        self.sizer.AddGrowableRow(4, 1)
-        self.sizer.AddGrowableRow(5, 5)
-
-        titleSizer = wx.BoxSizer(wx.VERTICAL)
-        titleSizer.Add(item = self.llocTitle, proportion = 1,
-                       flag = wx.EXPAND | wx.ALL, border = 5)
-        self.panelTitle.SetSizer(titleSizer)        
-        
-        projSizer = wx.BoxSizer(wx.VERTICAL)
-        projSizer.Add(item = self.lprojection, proportion = 1,
-                       flag = wx.EXPAND | wx.ALL, border = 5)
-        self.panelProj.SetSizer(projSizer)        
-        
-        proj4stringSizer = wx.BoxSizer(wx.VERTICAL)
-        proj4stringSizer.Add(item = self.lproj4string, proportion = 1,
-                       flag = wx.EXPAND | wx.ALL, border = 5)
-        self.panelProj4string.SetSizer(proj4stringSizer)
-
-        self.panelProj4string.SetupScrolling()
-        self.panelProj.SetupScrolling(scroll_y = False)
-        self.panelTitle.SetupScrolling(scroll_y = False)
-
-        self.sizer.Add(item = self.MakeLabel(_("GRASS Database:")),
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (1, 0))
-        self.sizer.Add(item = self.ldatabase, 
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (1, 1))
-        self.sizer.Add(item = self.MakeLabel(_("Location Name:")),
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (2, 0))
-        self.sizer.Add(item = self.llocation,
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (2, 1))
-        self.sizer.Add(item = self.MakeLabel(_("Location Title:")),
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (3, 0))
-        self.sizer.Add(item = self.panelTitle,
-                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
-                       border = 0, pos = (3, 1))
-        self.sizer.Add(item = self.MakeLabel(_("Projection:")),
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (4, 0))
-        self.sizer.Add(item = self.panelProj,
-                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
-                       border = 0, pos = (4, 1))
-        self.sizer.Add(item = self.MakeLabel(_("PROJ.4 definition:")),
-                       flag = wx.ALIGN_LEFT | wx.ALL,
-                       border = 5, pos = (5, 0))
-        self.sizer.Add(item = self.panelProj4string,
-                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
-                       border = 0, pos = (5, 1))
-   
-    def OnEnterPage(self, event):
-        """!Insert values into text controls for summary of location
-        creation options
-        """
-        database = self.parent.startpage.grassdatabase
-        location = self.parent.startpage.location
-        proj4string = self.parent.CreateProj4String()
-        epsgcode = self.parent.epsgpage.epsgcode
-        dtrans = self.parent.datumtrans
-        
-        global coordsys
-        if coordsys in ('proj', 'epsg'):
-            if coordsys == 'proj':
-                ret, projlabel, err = gcmd.RunCommand('g.proj',
-                                                      flags = 'jf',
-                                                      proj4 = proj4string,
-                                                      datumtrans = dtrans,
-                                                      location = location,
-                                                      getErrorMsg = True,
-                                                      read = True)
-            elif coordsys == 'epsg':
-                ret, projlabel, err = gcmd.RunCommand('g.proj',
-                                                      flags = 'jf',
-                                                      epsg = epsgcode,
-                                                      datumtrans = dtrans,
-                                                      location = location,
-                                                      getErrorMsg = True,
-                                                      read = True)
-
-            finishButton = wx.FindWindowById(wx.ID_FORWARD)
-            if ret == 0:
-                self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
-                finishButton.Enable(True)
-            else:
-                gcmd.GError(err, parent = self)
-                self.lproj4string.SetLabel('')
-                finishButton.Enable(False)
-        
-        projdesc = self.parent.projpage.projdesc
-        ellipsedesc = self.parent.ellipsepage.ellipsedesc
-        datumdesc = self.parent.datumpage.datumdesc
-        self.ldatabase.SetLabel(database)
-        self.llocation.SetLabel(location)
-        self.llocTitle.SetLabel(self.parent.startpage.locTitle)
-        
-        label = ''
-        if coordsys == 'epsg':
-            label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
-        elif coordsys == 'file':
-            label = 'matches file %s' % self.parent.filepage.georeffile
-            self.lproj4string.SetLabel("")
-        elif coordsys == 'wkt':
-            label = 'matches file %s' % self.parent.wktpage.wktfile
-            self.lproj4string.SetLabel("")
-        elif coordsys == 'proj':
-            label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
-        elif coordsys == 'xy':
-            label = ('XY coordinate system (not projected).')
-            self.lproj4string.SetLabel("")
-        elif coordsys == 'custom':
-            label = _("custom")
-            self.lproj4string.SetLabel(('%s' % self.parent.custompage.customstring.replace(' ', os.linesep)))
-        self.lprojection.SetLabel(label)
-        
-    def OnFinish(self, event):
-        dlg = wx.MessageDialog(parent = self.wizard,
-                               message = _("Do you want to create GRASS location <%s>?") % location,
-                               caption = _("Create new location?"),
-                               style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-        
-        if dlg.ShowModal() == wx.ID_NO:
-            dlg.Destroy()
-            event.Veto()
-        else:
-            dlg.Destroy()
-            event.Skip()
-
-class LocationWizard(wx.Object):
-    """!Start wizard here and finish wizard here
-    """
-    def __init__(self, parent, grassdatabase):
-        self.__cleanUp()
-        
-        global coordsys
-        self.parent = parent
-        
-        #
-        # define wizard image
-        #
-        imagePath = os.path.join(globalvar.ETCIMGDIR, "loc_wizard_qgis.png")
-        wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
-        wizbmp = wizbmp.ConvertToBitmap()
-        
-        #
-        # get georeferencing information from tables in $GISBASE/etc
-        #
-        self.__readData()
-        
-        #
-        # datum transform number and list of datum transforms
-        #
-        self.datumtrans = None
-        self.proj4string = ''
-        
-        #
-        # define wizard pages
-        #
-        self.wizard = wiz.Wizard(parent, id = wx.ID_ANY, title = _("Define new GRASS Location"),
-                                 bitmap = wizbmp, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
-        self.startpage = DatabasePage(self.wizard, self, grassdatabase)
-        self.csystemspage = CoordinateSystemPage(self.wizard, self)
-        self.projpage = ProjectionsPage(self.wizard, self)
-        self.datumpage = DatumPage(self.wizard, self)
-        self.paramspage = ProjParamsPage(self.wizard,self)
-        self.epsgpage = EPSGPage(self.wizard, self)
-        self.filepage = GeoreferencedFilePage(self.wizard, self)
-        self.wktpage = WKTPage(self.wizard, self)
-        self.ellipsepage = EllipsePage(self.wizard, self)
-        self.custompage = CustomPage(self.wizard, self)
-        self.sumpage = SummaryPage(self.wizard, self)
-
-        #
-        # set the initial order of the pages
-        # (should follow the epsg line)
-        #
-        self.startpage.SetNext(self.csystemspage)
-
-        self.csystemspage.SetPrev(self.startpage)
-        self.csystemspage.SetNext(self.sumpage)
-
-        self.projpage.SetPrev(self.csystemspage)
-        self.projpage.SetNext(self.paramspage)
-
-        self.paramspage.SetPrev(self.projpage)
-        self.paramspage.SetNext(self.datumpage)
-
-        self.datumpage.SetPrev(self.paramspage)
-        self.datumpage.SetNext(self.sumpage)
-
-        self.ellipsepage.SetPrev(self.paramspage)
-        self.ellipsepage.SetNext(self.sumpage)
-
-        self.epsgpage.SetPrev(self.csystemspage)
-        self.epsgpage.SetNext(self.sumpage)
-
-        self.filepage.SetPrev(self.csystemspage)
-        self.filepage.SetNext(self.sumpage)
-
-        self.wktpage.SetPrev(self.csystemspage)
-        self.wktpage.SetNext(self.sumpage)
-
-        self.custompage.SetPrev(self.csystemspage)
-        self.custompage.SetNext(self.sumpage)
-
-        self.sumpage.SetPrev(self.csystemspage)
-        
-        #
-        # do pages layout
-        #
-        self.startpage.DoLayout()
-        self.csystemspage.DoLayout()
-        self.projpage.DoLayout()
-        self.datumpage.DoLayout()
-        self.paramspage.DoLayout()
-        self.epsgpage.DoLayout()
-        self.filepage.DoLayout()
-        self.wktpage.DoLayout()
-        self.ellipsepage.DoLayout()
-        self.custompage.DoLayout()
-        self.sumpage.DoLayout()
-        self.wizard.FitToPage(self.datumpage)
-        size = self.wizard.GetPageSize()
-        self.wizard.SetPageSize((size[0], size[1] + 75))
-        
-        # new location created?
-        self.location = None 
-        success = False
-        
-        # location created in different GIS database?
-        self.altdb = False
-
-        #
-        # run wizard...
-        #
-        if self.wizard.RunWizard(self.startpage):
-            msg = self.OnWizFinished()
-            if not msg:
-                self.wizard.Destroy()
-                self.location = self.startpage.location
-                
-                if self.altdb == False: 
-                    dlg = wx.MessageDialog(parent = self.parent,
-                                           message = _("Do you want to set the default "
-                                                     "region extents and resolution now?"),
-                                           caption = _("Location <%s> created") % self.location,
-                                           style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
-                    dlg.CenterOnScreen()
-                    if dlg.ShowModal() == wx.ID_YES:
-                        dlg.Destroy()
-                        defineRegion = RegionDef(self.parent, location = self.location)
-                        defineRegion.CenterOnScreen()
-                        defineRegion.Show()
-                    else:
-                        dlg.Destroy()
-            else: # -> error
-                self.wizard.Destroy()
-                gcmd.GError(parent = self.parent,
-                            message = "%s" % _("Unable to create new location. "
-                                               "Location <%(loc)s> not created.\n\n"
-                                               "Details: %(err)s") % \
-                                  { 'loc' : self.startpage.location,
-                                    'err' : msg })
-        else: # -> cancelled
-            self.wizard.Destroy()
-            gcmd.GMessage(parent = self.parent,
-                          message = _("Location wizard canceled. "
-                                    "Location not created."))
-            
-        self.__cleanUp()
-        
-    def __cleanUp(self):
-        global coordsys
-        global north
-        global south
-        global east
-        global west
-        global resolution
-        global wizerror
-        global translist
-        
-        coordsys = None
-        north = None
-        south = None
-        east = None
-        west = None
-        resolution = None
-        transformlist = list()
-
-    def __readData(self):
-        """!Get georeferencing information from tables in $GISBASE/etc"""
-
-        # read projection and parameters
-        f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
-        self.projections = {}
-        self.projdesc = {}
-        for line in f.readlines():
-            line = line.strip()
-            try:
-                proj, projdesc, params = line.split(':')
-                paramslist = params.split(';')
-                plist = []
-                for p in paramslist:
-                    if p == '': continue
-                    p1, pdefault = p.split(',')
-                    pterm, pask = p1.split('=')
-                    p = [pterm.strip(), pask.strip(), pdefault.strip()]
-                    plist.append(p)
-                self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
-                self.projdesc[proj.lower().strip()] = projdesc.strip()
-            except:
-                continue
-        f.close()
-
-        # read datum definitions
-        f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
-        self.datums = {}
-        paramslist = []
-        for line in f.readlines():
-            line = line.expandtabs(1)
-            line = line.strip()
-            if line == '' or line[0] == "#":
-                continue
-            datum, info = line.split(" ", 1)
-            info = info.strip()
-            datumdesc, params = info.split(" ", 1)
-            datumdesc = datumdesc.strip('"')
-            paramlist = params.split()
-            ellipsoid = paramlist.pop(0)
-            self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
-        f.close()
-
-        # read ellipsiod definitions
-        f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
-        self.ellipsoids = {}
-        for line in f.readlines():
-            line = line.expandtabs(1)
-            line = line.strip()
-            if line == '' or line[0] == "#":
-                continue
-            ellipse, rest = line.split(" ", 1)
-            rest = rest.strip('" ')
-            desc, params = rest.split('"', 1)
-            desc = desc.strip('" ')
-            paramslist = params.split()
-            self.ellipsoids[ellipse] = (desc, paramslist)
-        f.close()
-        
-        # read projection parameter description and parsing table
-        f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
-        self.paramdesc = {}
-        for line in f.readlines():
-            line = line.strip()
-            try:
-                pparam, datatype, proj4term, desc = line.split(':')
-                self.paramdesc[pparam] = (datatype, proj4term, desc)
-            except:
-                continue
-        f.close()
-
-    def OnWizFinished(self):
-        """!Wizard finished, create new location
-
-        @return error message on error
-        @return None on success
-        """
-        database = self.startpage.grassdatabase
-        location = self.startpage.location
-        
-        # location already exists?
-        if os.path.isdir(os.path.join(database,location)):
-            gcmd.GError(parent = self.wizard,
-                        message = "%s <%s>: %s" % \
-                            (_("Unable to create new location"),
-                             os.path.join(database, location),
-                             _("Location already exists in GRASS Database.")))
-            return None
-        
-        # current GISDbase or a new one?
-        current_gdb = grass.gisenv()['GISDBASE']
-        if current_gdb != database:
-            # change to new GISDbase or create new one
-            if os.path.isdir(database) != True:
-                # create new directory
-                os.mkdir(database)
-            
-            # change to new GISDbase directory
-            gcmd.RunCommand('g.gisenv',
-                            parent = self.wizard,
-                            set = 'GISDBASE=%s' % database)
-            
-            wx.MessageBox(parent = self.wizard,
-                          message = _("Location <%(loc)s> will be created "
-                                    "in GIS data directory <%(dir)s>. "
-                                    "You will need to change the default GIS "
-                                    "data directory in the GRASS startup screen.") % \
-                              { 'loc' : location, 'dir' : database},
-                          caption = _("New GIS data directory"), 
-                          style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-            
-            # location created in alternate GISDbase
-            self.altdb = True
-        
-        global coordsys
-        try:
-            if coordsys == "xy":
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      desc = self.startpage.locTitle)
-            elif coordsys == "proj":
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      proj4 = self.CreateProj4String(),
-                                      datum = self.datumtrans,
-                                      desc = self.startpage.locTitle)
-            elif coordsys == 'custom':
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      proj4 = self.custompage.customstring,
-                                      desc = self.startpage.locTitle)
-            elif coordsys == "epsg":
-                if not self.epsgpage.epsgcode:
-                    return _('EPSG code missing.')
-                
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      epsg = self.epsgpage.epsgcode,
-                                      datum = self.datumtrans,
-                                      desc = self.startpage.locTitle)
-            elif coordsys == "file":
-                if not self.filepage.georeffile or \
-                        not os.path.isfile(self.filepage.georeffile):
-                    return _("File <%s> not found." % self.filepage.georeffile)
-                
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      filename = self.filepage.georeffile,
-                                      desc = self.startpage.locTitle)
-            elif coordsys == "wkt":
-                if not self.wktpage.wktfile or \
-                        not os.path.isfile(self.wktpage.wktfile):
-                    return _("File <%s> not found." % self.wktpage.wktfile)
-                
-                grass.create_location(dbase = self.startpage.grassdatabase,
-                                      location = self.startpage.location,
-                                      wkt = self.wktpage.wktfile,
-                                      desc = self.startpage.locTitle)
-        
-        except grass.ScriptError, e:
-            return e.value
-        
-        return None
-    
-    def CreateProj4String(self):
-        """!Constract PROJ.4 string"""
-        location = self.startpage.location
-        proj = self.projpage.p4proj
-        projdesc = self.projpage.projdesc
-        proj4params = self.paramspage.p4projparams
-                
-        datum = self.datumpage.datum
-        if self.datumpage.datumdesc:
-            datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
-        else:
-            datumdesc = ''
-        datumparams = self.datumpage.datumparams        
-        ellipse = self.ellipsepage.ellipse
-        ellipsedesc = self.ellipsepage.ellipsedesc
-        ellipseparams = self.ellipsepage.ellipseparams
-                
-        #
-        # creating PROJ.4 string
-        #
-        proj4string = '%s %s' % (proj, proj4params)
-                            
-        # set ellipsoid parameters
-        if ellipse != '':
-            proj4string = '%s +ellps=%s' % (proj4string, ellipse)
-        for item in ellipseparams:
-            if item[:4] == 'f=1/':
-                item = ' +rf=' + item[4:]
-            else:
-                item = ' +' + item
-            proj4string = '%s %s' % (proj4string, item)
-            
-        # set datum and transform parameters if relevant
-        if datum != '':
-            proj4string = '%s +datum=%s' % (proj4string, datum)
-        if datumparams:
-            for item in datumparams:
-                proj4string = '%s +%s' % (proj4string,item)
-
-        proj4string = '%s +no_defs' % proj4string
-        
-        return proj4string
-
-class RegionDef(BaseClass, wx.Frame):
-    """!Page for setting default region extents and resolution
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _("Set default region extent and resolution"), location = None):
-        wx.Frame.__init__(self, parent, id, title, size = (650,300))
-        panel = wx.Panel(self, id = wx.ID_ANY)
-        
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.parent = parent
-        self.location = location
-        
-        #
-        # default values
-        #
-        # 2D
-        self.north = 1.0
-        self.south = 0.0
-        self.east = 1.0
-        self.west = 0.0
-        self.nsres = 1.0
-        self.ewres = 1.0
-        # 3D
-        self.top = 1.0
-        self.bottom = 0.0
-        #         self.nsres3 = 1.0
-        #         self.ewres3 = 1.0
-        self.tbres  = 1.0
-        
-        #
-        # inputs
-        #
-        # 2D
-        self.tnorth = self.MakeTextCtrl(text = str(self.north), size = (150, -1), parent = panel)
-        self.tsouth = self.MakeTextCtrl(str(self.south), size = (150, -1), parent = panel)
-        self.twest = self.MakeTextCtrl(str(self.west), size = (150, -1), parent = panel)
-        self.teast = self.MakeTextCtrl(str(self.east), size = (150, -1), parent = panel)
-        self.tnsres = self.MakeTextCtrl(str(self.nsres), size = (150, -1), parent = panel)
-        self.tewres = self.MakeTextCtrl(str(self.ewres), size = (150, -1), parent = panel)
-        
-        #
-        # labels
-        #
-        self.lrows  = self.MakeLabel(parent = panel)
-        self.lcols  = self.MakeLabel(parent = panel)
-        self.lcells = self.MakeLabel(parent = panel)
-        
-        #
-        # buttons
-        #
-        self.bset = self.MakeButton(text = _("&Set region"), id = wx.ID_OK, parent = panel)
-        self.bcancel = wx.Button(panel, id = wx.ID_CANCEL)
-        self.bset.SetDefault()
-        
-        #
-        # image
-        #
-        self.img = wx.Image(os.path.join(globalvar.ETCIMGDIR, "qgis_world.png"),
-                            wx.BITMAP_TYPE_PNG).ConvertToBitmap()
-        
-        #
-        # set current working environment to PERMANENT mapset
-        # in selected location in order to set default region (WIND)
-        #
-        envval = {}
-        ret = gcmd.RunCommand('g.gisenv',
-                              read = True)
-        if ret:
-            for line in ret.splitlines():
-                key, val = line.split('=')
-                envval[key] = val
-            self.currlocation = envval['LOCATION_NAME'].strip("';")
-            self.currmapset = envval['MAPSET'].strip("';")
-            if self.currlocation != self.location or self.currmapset != 'PERMANENT':
-                gcmd.RunCommand('g.gisenv',
-                                set = 'LOCATION_NAME=%s' % self.location)
-                gcmd.RunCommand('g.gisenv',
-                                set = 'MAPSET=PERMANENT')
-        else:
-            dlg = wx.MessageBox(parent = self,
-                                message = _('Invalid location selected.'),
-                                caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
-            return
-        
-        #
-        # get current region settings
-        #
-        region = {}
-        ret = gcmd.RunCommand('g.region',
-                              read = True,
-                              flags = 'gp3')
-        if ret:
-            for line in ret.splitlines():
-                key, val = line.split('=')
-                region[key] = float(val)
-        else:
-            dlg = wx.MessageBox(parent = self,
-                                message = _("Invalid region"),
-                                caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
-            dlg.ShowModal()
-            dlg.Destroy()
-            return
-        
-        #
-        # update values
-        # 2D
-        self.north = float(region['n'])
-        self.south = float(region['s'])
-        self.east = float(region['e'])
-        self.west = float(region['w'])
-        self.nsres = float(region['nsres'])
-        self.ewres = float(region['ewres'])
-        self.rows = int(region['rows'])
-        self.cols = int(region['cols'])
-        self.cells = int(region['cells'])
-        # 3D
-        self.top = float(region['t'])
-        self.bottom = float(region['b'])
-        #         self.nsres3 = float(region['nsres3'])
-        #         self.ewres3 = float(region['ewres3'])
-        self.tbres = float(region['tbres'])
-        self.depth = int(region['depths'])
-        self.cells3 = int(region['cells3'])
-        
-        #
-        # 3D box collapsable
-        #
-        self.infoCollapseLabelExp = _("Click here to show 3D settings")
-        self.infoCollapseLabelCol = _("Click here to hide 3D settings")
-        self.settings3D = wx.CollapsiblePane(parent = panel,
-                                             label = self.infoCollapseLabelExp,
-                                             style = wx.CP_DEFAULT_STYLE |
-                                             wx.CP_NO_TLW_RESIZE | wx.EXPAND)
-        self.MakeSettings3DPaneContent(self.settings3D.GetPane())
-        self.settings3D.Collapse(False) # FIXME
-        self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSettings3DPaneChanged, self.settings3D)
-        
-        #
-        # set current region settings
-        #
-        self.tnorth.SetValue(str(self.north))
-        self.tsouth.SetValue(str(self.south))
-        self.twest.SetValue(str(self.west))
-        self.teast.SetValue(str(self.east))
-        self.tnsres.SetValue(str(self.nsres))
-        self.tewres.SetValue(str(self.ewres))
-        self.ttop.SetValue(str(self.top))
-        self.tbottom.SetValue(str(self.bottom))
-        #         self.tnsres3.SetValue(str(self.nsres3))
-        #         self.tewres3.SetValue(str(self.ewres3))
-        self.ttbres.SetValue(str(self.tbres))
-        self.lrows.SetLabel(_("Rows: %d") % self.rows)
-        self.lcols.SetLabel(_("Cols: %d") % self.cols)
-        self.lcells.SetLabel(_("Cells: %d") % self.cells)
-        
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
-        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
-        self.tnorth.Bind(wx.EVT_TEXT,   self.OnValue)
-        self.tsouth.Bind(wx.EVT_TEXT,   self.OnValue)
-        self.teast.Bind(wx.EVT_TEXT,    self.OnValue)
-        self.twest.Bind(wx.EVT_TEXT,    self.OnValue)
-        self.tnsres.Bind(wx.EVT_TEXT,   self.OnValue)
-        self.tewres.Bind(wx.EVT_TEXT,   self.OnValue)
-        self.ttop.Bind(wx.EVT_TEXT,     self.OnValue)
-        self.tbottom.Bind(wx.EVT_TEXT,  self.OnValue)
-        #         self.tnsres3.Bind(wx.EVT_TEXT,  self.OnValue)
-        #         self.tewres3.Bind(wx.EVT_TEXT,  self.OnValue)
-        self.ttbres.Bind(wx.EVT_TEXT,   self.OnValue)
-        
-        self.__DoLayout(panel)
-        self.SetMinSize(self.GetBestSize())
-        self.minWindowSize = self.GetMinSize()
-    
-    def MakeSettings3DPaneContent(self, pane):
-        """!Create 3D region settings pane"""
-        border = wx.BoxSizer(wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
-
-        # inputs
-        self.ttop = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.top),
-                                size = (150, -1))
-        self.tbottom = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.bottom),
-                                size = (150, -1))
-        self.ttbres = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.tbres),
-                                size = (150, -1))
-        #         self.tnsres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.nsres3),
-        #                                    size = (150, -1))
-        #         self.tewres3  =  wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.ewres3),
-        #                                    size = (150, -1))
-
-        #labels
-        self.ldepth = wx.StaticText(parent = pane, label = _("Depth: %d") % self.depth)
-        self.lcells3  =  wx.StaticText(parent = pane, label = _("3D Cells: %d") % self.cells3)
-
-        # top
-        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Top")),
-                      flag = wx.ALIGN_CENTER |
-                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
-                      pos = (0, 1))
-        gridSizer.Add(item = self.ttop,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALL, border = 5, pos = (1, 1))
-        # bottom
-        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Bottom")),
-                      flag = wx.ALIGN_CENTER |
-                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
-                      pos = (0, 2))
-        gridSizer.Add(item = self.tbottom,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALL, border = 5, pos = (1, 2))
-        # tbres
-        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("T-B resolution")),
-                      flag = wx.ALIGN_CENTER | 
-                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
-                      pos = (0, 3))
-        gridSizer.Add(item = self.ttbres,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALL, border = 5, pos = (1, 3))
-
-        # res
-        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D N-S resolution")),
-        #                       flag = wx.ALIGN_CENTER |
-        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
-        #                       pos = (2, 1))
-        #         gridSizer.Add(item = self.tnsres3,
-        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
-        #                       wx.ALL, border = 5, pos = (3, 1))
-        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D E-W resolution")),
-        #                       flag = wx.ALIGN_CENTER |
-        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
-        #                       pos = (2, 3))
-        #         gridSizer.Add(item = self.tewres3,
-        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
-        #                       wx.ALL, border = 5, pos = (3, 3))
-
-        # rows/cols/cells
-        gridSizer.Add(item = self.ldepth,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.ALL, border = 5, pos = (2, 1))
-
-        gridSizer.Add(item = self.lcells3,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.ALL, border = 5, pos = (2, 2))
-
-        border.Add(item = gridSizer, proportion = 1,
-                   flag = wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border = 5)
-
-        pane.SetSizer(border)
-        border.Fit(pane)
-
-    def OnSettings3DPaneChanged(self, event):
-        """!Collapse 3D settings box"""
-
-        if self.settings3D.IsExpanded():
-            self.settings3D.SetLabel(self.infoCollapseLabelCol)
-            self.Layout()
-            self.SetSize(self.GetBestSize())
-            self.SetMinSize(self.GetSize())
-        else:
-            self.settings3D.SetLabel(self.infoCollapseLabelExp)
-            self.Layout()
-            self.SetSize(self.minWindowSize)
-            self.SetMinSize(self.minWindowSize)
-
-        self.SendSizeEvent()
-
-    def __DoLayout(self, panel):
-        """!Window layout"""
-        frameSizer = wx.BoxSizer(wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
-        settings3DSizer = wx.BoxSizer(wx.VERTICAL)
-        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        # north
-        gridSizer.Add(item = self.MakeLabel(text = _("North"), parent = panel),
-                      flag = wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (0, 2))
-        gridSizer.Add(item = self.tnorth,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5, pos = (1, 2))
-        # west
-        gridSizer.Add(item = self.MakeLabel(text = _("West"), parent = panel),
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.LEFT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 0))
-        gridSizer.Add(item = self.twest,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5,  pos = (2, 1))
-
-        gridSizer.Add(item = wx.StaticBitmap(panel, wx.ID_ANY, self.img, (-1, -1),
-                                           (self.img.GetWidth(), self.img.GetHeight())),
-                      flag = wx.ALIGN_CENTER |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5, pos = (2, 2))
-
-        # east
-        gridSizer.Add(item = self.teast,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5,  pos = (2, 3))
-        gridSizer.Add(item = self.MakeLabel(text = _("East"), parent = panel),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.RIGHT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 4))
-        # south
-        gridSizer.Add(item = self.tsouth,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5, pos = (3, 2))
-        gridSizer.Add(item = self.MakeLabel(text = _("South"), parent = panel),
-                      flag = wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
-                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5, pos = (4, 2))
-        # ns-res
-        gridSizer.Add(item = self.MakeLabel(text = _("N-S resolution"), parent = panel),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 1))
-        gridSizer.Add(item = self.tnsres,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5,  pos = (6, 1))
-        # ew-res
-        gridSizer.Add(item = self.MakeLabel(text = _("E-W resolution"), parent = panel),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 3))
-        gridSizer.Add(item = self.tewres,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALL, border = 5,  pos = (6, 3))
-        # rows/cols/cells
-        gridSizer.Add(item = self.lrows,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.ALL, border = 5, pos = (7, 1))
-
-        gridSizer.Add(item = self.lcells,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.ALL, border = 5, pos = (7, 2))
-
-        gridSizer.Add(item = self.lcols,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
-                      wx.ALL, border = 5, pos = (7, 3))
-
-        # 3D
-        settings3DSizer.Add(item = self.settings3D,
-                            flag = wx.ALL,
-                            border = 5)
-
-        # buttons
-        buttonSizer.Add(item = self.bcancel, proportion = 1,
-                        flag = wx.ALIGN_RIGHT |
-                        wx.ALIGN_CENTER_VERTICAL |
-                        wx.ALL, border = 10)
-        buttonSizer.Add(item = self.bset, proportion = 1,
-                        flag = wx.ALIGN_CENTER |
-                        wx.ALIGN_CENTER_VERTICAL |
-                        wx.ALL, border = 10)
-
-        frameSizer.Add(item = gridSizer, proportion = 1,
-                       flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
-        frameSizer.Add(item = settings3DSizer, proportion = 0,
-                       flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
-        frameSizer.Add(item = buttonSizer, proportion = 0,
-                       flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
-
-        self.SetAutoLayout(True)
-        panel.SetSizer(frameSizer)
-        frameSizer.Fit(panel)
-        self.Layout()
-
-    def OnValue(self, event):
-        """!Set given value"""
-        try:
-            if event.GetId() == self.tnorth.GetId():
-                self.north = float(event.GetString())
-            elif event.GetId() == self.tsouth.GetId():
-                self.south = float(event.GetString())
-            elif event.GetId() == self.teast.GetId():
-                self.east = float(event.GetString())
-            elif event.GetId() == self.twest.GetId():
-                self.west = float(event.GetString())
-            elif event.GetId() == self.tnsres.GetId():
-                self.nsres = float(event.GetString())
-            elif event.GetId() == self.tewres.GetId():
-                self.ewres = float(event.GetString())
-            elif event.GetId() == self.ttop.GetId():
-                self.top = float(event.GetString())
-            elif event.GetId() == self.tbottom.GetId():
-                self.bottom = float(event.GetString())
-            #             elif event.GetId() == self.tnsres3.GetId():
-            #                 self.nsres3 = float(event.GetString())
-            #             elif event.GetId() == self.tewres3.GetId():
-            #                 self.ewres3 = float(event.GetString())
-            elif event.GetId() == self.ttbres.GetId():
-                self.tbres = float(event.GetString())
-
-            self.__UpdateInfo()
-
-        except ValueError, e:
-            if len(event.GetString()) > 0 and event.GetString() != '-':
-                dlg = wx.MessageBox(parent = self,
-                                    message = _("Invalid value: %s") % e,
-                                    caption = _("Error"),
-                                    style = wx.OK | wx.ICON_ERROR)
-                # reset values
-                self.tnorth.SetValue(str(self.north))
-                self.tsouth.SetValue(str(self.south))
-                self.teast.SetValue(str(self.east))
-                self.twest.SetValue(str(self.west))
-                self.tnsres.SetValue(str(self.nsres))
-                self.tewres.SetValue(str(self.ewres))
-                self.ttop.SetValue(str(self.top))
-                self.tbottom.SetValue(str(self.bottom))
-                self.ttbres.SetValue(str(self.tbres))
-                # self.tnsres3.SetValue(str(self.nsres3))
-                # self.tewres3.SetValue(str(self.ewres3))
-
-        event.Skip()
-
-    def __UpdateInfo(self):
-        """!Update number of rows/cols/cells"""
-        self.rows = int((self.north - self.south) / self.nsres)
-        self.cols = int((self.east - self.west) / self.ewres)
-        self.cells = self.rows * self.cols
-
-        self.depth = int((self.top - self.bottom) / self.tbres)
-        self.cells3 = self.rows * self.cols * self.depth
-
-        # 2D
-        self.lrows.SetLabel(_("Rows: %d") % self.rows)
-        self.lcols.SetLabel(_("Cols: %d") % self.cols)
-        self.lcells.SetLabel(_("Cells: %d") % self.cells)
-        # 3D
-        self.ldepth.SetLabel(_("Depth: %d" % self.depth))
-        self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))
-
-    def OnSetButton(self, event = None):
-        """!Set default region"""
-        ret = gcmd.RunCommand('g.region',
-                              flags = 'sgpa',
-                              n = self.north,
-                              s = self.south,
-                              e = self.east,
-                              w = self.west,
-                              nsres = self.nsres,
-                              ewres = self.ewres,
-                              t = self.top,
-                              b = self.bottom,
-                              tbres = self.tbres)
-        if ret == 0:
-            self.Destroy()
-
-    def OnCancel(self, event):
-        self.Destroy()
-        
-class TransList(wx.VListBox):
-    """!Creates a multiline listbox for selecting datum transforms"""
-        
-    def OnDrawItem(self, dc, rect, n):
-        if self.GetSelection() == n:
-            c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
-        else:
-            c = self.GetForegroundColour()
-        dc.SetFont(self.GetFont())
-        dc.SetTextForeground(c)
-        dc.DrawLabel(self._getItemText(n), rect,
-                     wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
-
-    def OnMeasureItem(self, n):
-        height = 0
-        if self._getItemText(n) == None:
-            return
-        for line in self._getItemText(n).splitlines():
-            w, h = self.GetTextExtent(line)
-            height += h
-        return height + 5
-
-    def _getItemText(self, item):
-        global transformlist
-        transitem = transformlist[item]
-        if transitem.strip() !='':
-            return transitem
-
-
-class SelectTransformDialog(wx.Dialog):
-    """!Dialog for selecting datum transformations"""
-    def __init__(self, parent, transforms, title = _("Select datum transformation"),
-                 pos = wx.DefaultPosition, size = wx.DefaultSize, 
-                 style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
-
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
-
-        global transformlist
-        self.CentreOnParent()
-        
-        # default transform number
-        self.transnum = 0
-        
-        panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        #
-        # set panel sizer
-        #
-        panel.SetSizer(sizer)
-        panel.SetupScrolling()
-
-        #
-        # dialog body
-        #
-        bodyBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                               label = " %s " % _("Select from list of datum transformations"))
-        bodySizer = wx.StaticBoxSizer(bodyBox)       
-        
-        # add no transform option
-        transforms = '---\n\n0\nDo not apply any datum transformations\n\n' + transforms
-        
-        transformlist = transforms.split('---')
-        tlistlen = len(transformlist)
-        
-        # calculate size for transform list
-        height = 0
-        width = 0
-        for line in transforms.splitlines():
-            w, h = self.GetTextExtent(line)
-            height += h
-            width = max(width, w)
-            
-        height = height + 5
-        if height > 400: height = 400
-        width = width + 5
-        if width > 400: width = 400
-
-        #
-        # VListBox for displaying and selecting transformations
-        #
-        self.translist = TransList(panel, id = -1, size = (width, height), style = wx.SUNKEN_BORDER)
-        self.translist.SetItemCount(tlistlen)
-        self.translist.SetSelection(2)
-        self.translist.SetFocus()
-        
-        self.Bind(wx.EVT_LISTBOX, self.ClickTrans, self.translist)
-
-        bodySizer.Add(item = self.translist, proportion = 1, flag = wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
-
-        #
-        # buttons
-        #
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(parent = panel, id = wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(parent = panel, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        sizer.Add(item = bodySizer, proportion = 1,
-                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag =  wx.ALL | wx.ALIGN_RIGHT, border = 5)
-
-        sizer.Fit(panel)
-
-        self.SetSize(self.GetBestSize())
-        self.Layout()
-        
-    def ClickTrans(self, event):
-        """!Get the number of the datum transform to use in g.proj"""
-        self.transnum = event.GetSelection()
-        self.transnum = self.transnum - 1
-    
-    def GetTransform(self):
-        """!Get the number of the datum transform to use in g.proj"""
-        self.transnum = self.translist.GetSelection()
-        self.transnum = self.transnum - 1
-        return self.transnum

Deleted: grass/trunk/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1819 +0,0 @@
-"""!
- at package mapdisp.py
-
- at brief Map display with toolbar for various display management
-functions, and additional toolbars (vector digitizer, 3d view).
-
-Can be used either from Layer Manager or as d.mon backend.
-
-Classes:
- - MapFrameBase
- - MapFrame
- - MapApp
-
-Usage:
-python mapdisp.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
-
-(C) 2006-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
- at author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
-"""
-
-import os
-import sys
-import glob
-import math
-import tempfile
-import copy
-
-import globalvar
-import wx
-import wx.aui
-
-sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
-sys.path.append(os.path.join(globalvar.ETCDIR,   "python"))
-
-import render
-import toolbars
-import menuform
-import gselect
-import disp_print
-import gcmd
-import dbm
-import dbm_dialogs
-import globalvar
-import utils
-import gdialogs
-import mapdisp_statusbar as sb
-from debug       import Debug
-from icon        import Icons
-from preferences import globalSettings as UserSettings
-
-from mapdisp_window  import BufferedWindow
-from histogram       import HistFrame
-from wxplot          import HistFrame as HistFramePyPlot, ProfileFrame, ScatterFrame
-
-from grass.script import core as grass
-
-# for standalone app
-monFile = { 'cmd' : None,
-            'map' : None,
-            'env' : None,
-            }
-monName = None
-monSize = list(globalvar.MAP_WINDOW_SIZE)
-
-haveCtypes = False
-
-class MapFrameBase(wx.Frame):
-    """!Base class for map display window
-    
-    Derived class must use statusbarManager or override
-    GetProperty, SetProperty and HasProperty methods.
-    If derived class enables and disables auto-rendering,
-    it should override IsAutoRendered method.
-    """
-    def __init__(self, parent = None, id = wx.ID_ANY, title = None,
-                 style = wx.DEFAULT_FRAME_STYLE, toolbars = None,
-                 Map = None, auimgr = None, name = None, **kwargs):
-        """!
-        @param toolbars array of activated toolbars, e.g. ['map', 'digit']
-        @param Map instance of render.Map
-        @param auimgs AUI manager
-        @param name frame name
-        @param kwargs wx.Frame attributes
-        """
-        
-
-        self.Map        = Map       # instance of render.Map
-        self.parent     = parent
-        
-        wx.Frame.__init__(self, parent, id, title, style = style, name = name, **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))
-        
-        # toolbars
-        self.toolbars = {}
-        
-        #
-        # Fancy gui
-        #
-        self._mgr = wx.aui.AuiManager(self)
-        
-    def _initMap(self, map):
-        """!Initialize map display, set dimensions and map region
-        """
-        if not grass.find_program('g.region', ['--help']):
-            sys.exit(_("GRASS module '%s' not found. Unable to start map "
-                       "display window.") % 'g.region')
-        
-        self.width, self.height = self.GetClientSize()
-        
-        Debug.msg(2, "MapFrame._initMap():")
-        map.ChangeMapSize(self.GetClientSize())
-        map.region = map.GetRegion() # g.region -upgc
-        # self.Map.SetRegion() # adjust region to match display window
-        
-    def SetProperty(self, name, value):
-        """!Sets property"""
-        self.statusbarManager.SetProperty(name, value)
-        
-    def GetProperty(self, name):
-        """!Returns property"""
-        return self.statusbarManager.GetProperty(name)
-        
-    def HasProperty(self, name):
-        """!Checks whether object has property"""
-        return self.statusbarManager.HasProperty(name)
-    
-    def GetPPM(self):
-        """! Get pixel per meter
-        
-        @todo now computed every time, is it necessary?
-        @todo enable user to specify ppm (and store it in UserSettings)
-        """
-        # 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
-        ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
-                    (ppi[1] / 2.54) * 100)
-        
-        Debug.msg(4, "MapFrameBase.GetPPM(): 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],
-                   ppm[0], ppm[1]))
-        
-        return ppm
-    
-    def SetMapScale(self, value, map = None):
-        """! Set current map scale
-        
-        @param value scale value (n if scale is 1:n)
-        @param map Map instance (if none self.Map is used)
-        """
-        if not map:
-            map = self.Map
-        
-        region = self.Map.region
-        dEW = value * (region['cols'] / self.GetPPM()[0])
-        dNS = value * (region['rows'] / self.GetPPM()[1])
-        region['n'] = region['center_northing'] + dNS / 2.
-        region['s'] = region['center_northing'] - dNS / 2.
-        region['w'] = region['center_easting']  - dEW / 2.
-        region['e'] = region['center_easting']  + dEW / 2.
-        
-        # add to zoom history
-        self.GetWindow().ZoomHistory(region['n'], region['s'],
-                                   region['e'], region['w'])
-    
-    def GetMapScale(self, map = None):
-        """! Get current map scale
-        
-        @param map Map instance (if none self.Map is used)
-        """
-        if not map:
-            map = self.Map
-        
-        region = map.region
-        ppm = self.GetPPM()
-
-        heightCm = region['rows'] / ppm[1] * 100
-        widthCm  = region['cols'] / ppm[0] * 100
-
-        Debug.msg(4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" %
-                  (widthCm, heightCm))
-
-        xscale = (region['e'] - region['w']) / (region['cols'] / ppm[0])
-        yscale = (region['n'] - region['s']) / (region['rows'] / ppm[1])
-        scale = (xscale + yscale) / 2.
-        
-        Debug.msg(3, "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" % \
-                      (xscale, yscale, scale))
-        
-        return scale
-        
-    def GetProgressBar(self):
-        """!Returns progress bar
-        
-        Progress bar can be used by other classes.
-        """
-        return self.statusbarManager.GetProgressBar()
-        
-    def GetMap(self):
-        """!Returns current Map instance
-        """
-        return self.Map
-
-    def GetWindow(self):
-        """!Get map window"""
-        return self.MapWindow
-        
-    def GetMapToolbar(self):
-       """!Returns toolbar with zooming tools"""
-       raise NotImplementedError()
-       
-    def GetToolbar(self, name):
-        """!Returns toolbar if exists else None.
-        
-        Toolbars dictionary contains currently used toolbars only.
-        """
-        if name in self.toolbars:
-            return self.toolbars[name]
-        
-        return None
-       
-    def StatusbarUpdate(self):
-        """!Update statusbar content"""
-        self.statusbarManager.Update()
-        
-    def IsAutoRendered(self):
-        """!Check if auto-rendering is enabled"""
-        return self.GetProperty('render')
-        
-    def CoordinatesChanged(self):
-        """!Shows current coordinates on statusbar.
-        
-        Used in BufferedWindow to report change of map coordinates (under mouse cursor).
-        """
-        self.statusbarManager.ShowItem('coordinates')
-        
-    def StatusbarReposition(self):
-        """!Reposition items in statusbar"""
-        self.statusbarManager.Reposition()
-        
-    def StatusbarEnableLongHelp(self, enable = True):
-        """!Enable/disable toolbars long help"""
-        for toolbar in self.toolbars.itervalues():
-            toolbar.EnableLongHelp(enable)
-        
-    def IsStandalone(self):
-        """!Check if Map display is standalone"""
-        raise NotImplementedError("IsStandalone")
-   
-    def OnRender(self, event):
-        """!Re-render map composition (each map layer)
-        """
-        raise NotImplementedError("OnRender")
-        
-    def OnDraw(self, event):
-        """!Re-display current map composition
-        """
-        self.MapWindow.UpdateMap(render = False)
-        
-    def OnErase(self, event):
-        """!Erase the canvas
-        """
-        self.MapWindow.EraseMap()
-        
-    def OnZoomIn(self, event):
-        """!Zoom in the map.
-        Set mouse cursor, zoombox attributes, and zoom direction
-        """
-        toolbar = self.GetMapToolbar()
-        self._switchTool(toolbar, event)
-        
-        win = self.GetWindow()
-        self._prepareZoom(mapWindow = win, zoomType = 1)
-        
-    def OnZoomOut(self, event):
-        """!Zoom out the map.
-        Set mouse cursor, zoombox attributes, and zoom direction
-        """
-        toolbar = self.GetMapToolbar()
-        self._switchTool(toolbar, event)
-        
-        win = self.GetWindow()
-        self._prepareZoom(mapWindow = win, zoomType = -1)
-        
-    def _prepareZoom(self, mapWindow, zoomType):
-        """!Prepares MapWindow for zoom, toggles toolbar
-        
-        @param mapWindow MapWindow to prepare
-        @param zoomType 1 for zoom in, -1 for zoom out
-        """
-        mapWindow.mouse['use'] = "zoom"
-        mapWindow.mouse['box'] = "box"
-        mapWindow.zoomtype = zoomType
-        mapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
-        
-        # change the cursor
-        mapWindow.SetCursor(self.cursors["cross"])
-    
-    def _switchTool(self, toolbar, event):
-        """!Helper function to switch tools"""
-        if toolbar:
-            toolbar.OnTool(event)
-            toolbar.action['desc'] = ''
-            
-    def OnPan(self, event):
-        """!Panning, set mouse to drag
-        """
-        toolbar = self.GetMapToolbar()
-        self._switchTool(toolbar, event)
-        
-        win = self.GetWindow()
-        self._preparePan(mapWindow = win)
-    
-    def _preparePan(self, mapWindow):
-        """!Prepares MapWindow for pan, toggles toolbar
-        
-        @param mapWindow MapWindow to prepare
-        """
-        mapWindow.mouse['use'] = "pan"
-        mapWindow.mouse['box'] = "pan"
-        mapWindow.zoomtype = 0
-        
-        # change the cursor
-        mapWindow.SetCursor(self.cursors["hand"])
-        
-    def OnZoomBack(self, event):
-        """!Zoom last (previously stored position)
-        """
-        self.MapWindow.ZoomBack()
-        
-    def OnZoomToMap(self, event):
-        """!
-        Set display extents to match selected raster (including NULLs)
-        or vector map.
-        """
-        self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
-    
-    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()
-        
-class MapFrame(MapFrameBase):
-    """!Main frame for map display window. Drawing takes place in
-    child double buffered drawing window.
-    """
-    def __init__(self, parent = None, title = _("GRASS GIS - Map display"),
-                 toolbars = ["map"], tree = None, notebook = None, lmgr = None,
-                 page = None, Map = None, auimgr = None, name = 'MapWindow', **kwargs):
-        """!Main map display window with toolbars, statusbar and
-        BufferedWindow (map canvas)
-        
-        @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 name frame name
-        @param kwargs wx.Frame attributes
-        """
-        MapFrameBase.__init__(self, parent = parent, title = title, toolbars = toolbars,
-                              Map = Map, auimgr = auimgr, name = name, **kwargs)
-        
-        self._layerManager = lmgr   # Layer Manager object
-        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
-        #
-        # Add toolbars
-        #
-        for toolb in toolbars:
-            self.AddToolbar(toolb)
-        
-        #
-        # Add statusbar
-        #
-        
-        # items for choice
-        self.statusbarItems = [sb.SbCoordinates,
-                               sb.SbRegionExtent,
-                               sb.SbCompRegionExtent,
-                               sb.SbShowRegion,
-                               sb.SbAlignExtent,
-                               sb.SbResolution,
-                               sb.SbDisplayGeometry,
-                               sb.SbMapScale,
-                               sb.SbGoTo,
-                               sb.SbProjection]
-                            
-        self.statusbarItemsHiddenInNviz = (sb.SbAlignExtent,
-                                           sb.SbDisplayGeometry,
-                                           sb.SbShowRegion,
-                                           sb.SbResolution,
-                                           sb.SbMapScale)
-        
-        # create statusbar and its manager
-        statusbar = self.CreateStatusBar(number = 4, style = 0)
-        statusbar.SetStatusWidths([-5, -2, -1, -1])
-        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
-        
-        # fill statusbar manager
-        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
-        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
-        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
-        
-        self.statusbarManager.Update()
-
-        #
-        # Init map display (buffered DC & set default cursor)
-        #
-        self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
-                                          Map = self.Map, tree = self.tree, lmgr = self._layerManager)
-        # default is 2D display mode
-        self.MapWindow = self.MapWindow2D
-        self.MapWindow.SetCursor(self.cursors["default"])
-        # used by vector digitizer
-        self.MapWindowVDigit = None
-        # used by Nviz (3D display mode)
-        self.MapWindow3D = None 
-
-        #
-        # initialize region values
-        #
-        self._initMap(map = self.Map) 
-
-        #
-        # Bind various events
-        #
-        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
-        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
-        self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
-        
-        #
-        # Update fancy gui style
-        #
-        self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
-                          Dockable(False).BestSize((-1,-1)).Name('2d').
-                          CloseButton(False).DestroyOnClose(True).
-                          Layer(0))
-        self._mgr.Update()
-
-        #
-        # Init print module and classes
-        #
-        self.printopt = disp_print.PrintOptions(self, self.MapWindow)
-        
-        #
-        # 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 _addToolbarVDigit(self):
-        """!Add vector digitizer toolbar
-        """
-        from vdigit import haveVDigit
-        
-        if not haveVDigit:
-            from vdigit import errorMsg
-            msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
-                    "TCL/TK digitizer (v.digit) instead?\n\n"
-                    "Details: %s" % errorMsg)
-            
-            self.toolbars['map'].combo.SetValue(_("2D view"))
-            dlg = wx.MessageDialog(parent = self,
-                                   message = msg,
-                                   caption=_("Vector digitizer failed"),
-                                   style = wx.YES_NO | wx.CENTRE)
-            if dlg.ShowModal() == wx.ID_YES:
-                mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetName()
-                self._layerManager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
-                                                  switchPage = False)
-            dlg.Destroy()
-            
-            self.toolbars['map'].combo.SetValue(_("2D view"))
-            return
-        
-        if self._layerManager:
-            log = self._layerManager.goutput
-        else:
-            log = None
-        
-        if not self.MapWindowVDigit:
-            from mapdisp_vdigit import VDigitWindow
-            self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
-                                                Map = self.Map, tree = self.tree,
-                                                lmgr = self._layerManager)
-            self.MapWindowVDigit.Show()
-            self._mgr.AddPane(self.MapWindowVDigit, wx.aui.AuiPaneInfo().CentrePane().
-                          Dockable(False).BestSize((-1,-1)).Name('vdigit').
-                          CloseButton(False).DestroyOnClose(True).
-                          Layer(0))
-        
-        self.MapWindow = self.MapWindowVDigit
-        
-        if self._mgr.GetPane('2d').IsShown():
-            self._mgr.GetPane('2d').Hide()
-        elif self._mgr.GetPane('3d').IsShown():
-            self._mgr.GetPane('3d').Hide()
-        self._mgr.GetPane('vdigit').Show()
-        self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent = self, MapWindow = self.MapWindow,
-                                                         layerTree = self.tree,
-                                                         log = log)
-        self.MapWindowVDigit.SetToolbar(self.toolbars['vdigit'])
-        
-        self._mgr.AddPane(self.toolbars['vdigit'],
-                          wx.aui.AuiPaneInfo().
-                          Name("vdigittoolbar").Caption(_("Vector Digitizer Toolbar")).
-                          ToolbarPane().Top().Row(1).
-                          LeftDockable(False).RightDockable(False).
-                          BottomDockable(False).TopDockable(True).
-                          CloseButton(False).Layer(2).
-                          BestSize((self.toolbars['vdigit'].GetBestSize())))
-        # change mouse to draw digitized line
-        self.MapWindow.mouse['box'] = "point"
-        self.MapWindow.zoomtype     = 0
-        self.MapWindow.pen          = wx.Pen(colour = 'red',   width = 2, style = wx.SOLID)
-        self.MapWindow.polypen      = wx.Pen(colour = 'green', width = 2, style = wx.SOLID)
-
-    def AddNviz(self):
-        """!Add 3D view mode window
-        """
-        import nviz
-        
-        # check for GLCanvas and OpenGL
-        if not nviz.haveNviz:
-            self.toolbars['map'].combo.SetValue(_("2D view"))
-            gcmd.GError(parent = self,
-                        message = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
-                                    "was not found or loaded properly.\n"
-                                    "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg))
-            return
-        
-        # disable 3D mode for other displays
-        for page in range(0, self._layerManager.gm_cb.GetPageCount()):
-            if self._layerManager.gm_cb.GetPage(page) != self._layerManager.curr_page:
-                if '3D' in self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.GetString(1):
-                    self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.Delete(1)
-        self.toolbars['map'].Enable2D(False)
-        # add rotate tool to map toolbar
-        self.toolbars['map'].InsertTool((('rotate', Icons['nviz']['rotate'],
-                                          self.OnRotate, wx.ITEM_CHECK, 7),)) # 7 is position
-        self.toolbars['map'].InsertTool((('flyThrough', Icons['nviz']['flyThrough'],
-                                          self.OnFlyThrough, wx.ITEM_CHECK, 8),)) 
-        self.toolbars['map'].ChangeToolsDesc(mode2d = False)
-        # update status bar
-        
-        self.statusbarManager.HideStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
-        self.statusbarManager.SetMode(0)
-        
-        # erase map window
-        self.MapWindow.EraseMap()
-        
-        self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."),
-                                               switchPage = False)
-        self.SetStatusText(_("Please wait, loading data..."), 0)
-        
-        # create GL window
-        if not self.MapWindow3D:
-            self.MapWindow3D = nviz.GLWindow(self, id = wx.ID_ANY,
-                                             Map = self.Map, tree = self.tree, lmgr = self._layerManager)
-            self.MapWindow = self.MapWindow3D
-            self.MapWindow.SetCursor(self.cursors["default"])
-            
-            # add Nviz notebookpage
-            self._layerManager.AddNvizTools()
-            
-            # switch from MapWindow to MapWindowGL
-            self._mgr.GetPane('2d').Hide()
-            self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
-                              Dockable(False).BestSize((-1,-1)).Name('3d').
-                              CloseButton(False).DestroyOnClose(True).
-                              Layer(0))
-            
-            self.MapWindow3D.OnPaint(None) # -> LoadData
-            self.MapWindow3D.Show()
-            self.MapWindow3D.ResetViewHistory()            
-            self.MapWindow3D.UpdateView(None)
-        else:
-            self.MapWindow = self.MapWindow3D
-            os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
-            self.MapWindow3D.GetDisplay().Init()
-            del os.environ['GRASS_REGION']
-            
-            # switch from MapWindow to MapWindowGL
-            self._mgr.GetPane('2d').Hide()
-            self._mgr.GetPane('3d').Show()
-            
-            # add Nviz notebookpage
-            self._layerManager.AddNvizTools()
-            self.MapWindow3D.ResetViewHistory()
-            for page in ('view', 'light', 'fringe', 'constant', 'cplane', 'animation'):
-                self._layerManager.nviz.UpdatePage(page)
-                
-        self.MapWindow3D.overlays = self.MapWindow2D.overlays
-        self.MapWindow3D.textdict = self.MapWindow2D.textdict
-        # update overlays needs to be called after because getClientSize
-        # is called during update and it must give reasonable values
-        wx.CallAfter(self.MapWindow3D.UpdateOverlays)
-        
-        self.SetStatusText("", 0)
-        self._mgr.Update()
-    
-    def RemoveNviz(self):
-        """!Restore 2D view"""
-        self.toolbars['map'].RemoveTool(self.toolbars['map'].rotate)
-        self.toolbars['map'].RemoveTool(self.toolbars['map'].flyThrough)
-        # update status bar
-        self.statusbarManager.ShowStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
-        self.statusbarManager.SetMode(UserSettings.Get(group = 'display',
-                                                       key = 'statusbarMode',
-                                                       subkey = 'selection'))
-        self.SetStatusText(_("Please wait, unloading data..."), 0)
-        self._layerManager.goutput.WriteCmdLog(_("Switching back to 2D view mode..."),
-                                               switchPage = False)
-        self.MapWindow3D.OnClose(event = None)
-        # switch from MapWindowGL to MapWindow
-        self._mgr.GetPane('2d').Show()
-        self._mgr.GetPane('3d').Hide()
-
-        self.MapWindow = self.MapWindow2D
-        # remove nviz notebook page
-        self._layerManager.RemoveNvizTools()
-        
-        self.MapWindow2D.overlays = self.MapWindow3D.overlays
-        self.MapWindow2D.textdict = self.MapWindow3D.textdict
-        self.MapWindow.UpdateMap()
-        self._mgr.Update()
-        
-    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
-        """
-        # 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().Name('mapToolbar').
-                              LeftDockable(False).RightDockable(False).
-                              BottomDockable(False).TopDockable(True).
-                              CloseButton(False).Layer(2).
-                              BestSize((self.toolbars['map'].GetBestSize())))
-            
-        # vector digitizer
-        elif name == "vdigit":
-            self._addToolbarVDigit()
-        
-        self._mgr.Update()
-        
-    def RemoveToolbar (self, name):
-        """!Removes defined toolbar from the window
-
-        @todo Only hide, activate by calling AddToolbar()
-        """
-        # cannot hide main toolbar
-        if name == "map":
-            return
-        
-        self._mgr.DetachPane(self.toolbars[name])
-        self.toolbars[name].Destroy()
-        self.toolbars.pop(name)
-        
-        if name == 'vdigit':
-            self._mgr.GetPane('vdigit').Hide()
-            self._mgr.GetPane('2d').Show()
-            self.MapWindow = self.MapWindow2D
-            
-        self.toolbars['map'].combo.SetValue(_("2D view"))
-        self.toolbars['map'].Enable2D(True)
-        
-        self._mgr.Update()
-    
-    def IsPaneShown(self, name):
-        """!Check if pane (toolbar, mapWindow ...) of given name is currently shown"""
-        if self._mgr.GetPane(name).IsOk():
-            return self._mgr.GetPane(name).IsShown()
-        return False
-        
-    def OnUpdateProgress(self, event):
-        """!Update progress bar info
-        """
-        self.GetProgressBar().SetValue(event.value)
-        
-        event.Skip()
-        
-    def OnFocus(self, event):
-        """!Change choicebook page to match display.
-        """
-        # change bookcontrol page to page associated with display
-        if self.page:
-            pgnum = self.layerbook.GetPageIndex(self.page)
-            if pgnum > -1:
-                self.layerbook.SetSelection(pgnum)
-                self._layerManager.curr_page = self.layerbook.GetCurrentPage()
-        
-        event.Skip()
-        
-    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)
-        
-        # delete tmp lines
-        if self.MapWindow.mouse["use"] in ("measure",
-                                           "profile"):
-            self.MapWindow.polycoords = []
-            self.MapWindow.ClearLines()
-        
-        # deselect features in vdigit
-        if self.GetToolbar('vdigit'):
-            self.MapWindow.digit.GetDisplay().SetSelected([])
-            self.MapWindow.UpdateMap(render = True, renderVector = True)
-        else:
-            self.MapWindow.UpdateMap(render = True)
-        
-        # update statusbar
-        self.StatusbarUpdate()
-
-    def OnPointer(self, event):
-        """!Pointer button clicked
-        """
-        if self.GetMapToolbar():
-            if event:
-                self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "pointer"
-        self.MapWindow.mouse['box'] = "point"
-
-        # change the cursor
-        if self.GetToolbar('vdigit'):
-            # digitization tool activated
-            self.MapWindow.SetCursor(self.cursors["cross"])
-
-            # reset mouse['box'] if needed
-            if self.toolbars['vdigit'].GetAction() in ['addLine']:
-                if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
-                    self.MapWindow.mouse['box'] = 'point'
-                else: # line, boundary
-                    self.MapWindow.mouse['box'] = 'line'
-            elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
-                                                         'editLine', 'displayCats', 'queryMap',
-                                                         'copyCats']:
-                self.MapWindow.mouse['box'] = 'point'
-            else: # moveLine, deleteLine
-                self.MapWindow.mouse['box'] = 'box'
-        
-        else:
-            self.MapWindow.SetCursor(self.cursors["default"])
-
-    def OnRotate(self, event):
-        """!Rotate 3D view
-        """
-        if self.GetMapToolbar():
-            self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "rotate"
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["hand"])
-
-    def OnFlyThrough(self, event):
-        """!Fly-through mode
-        """
-        if self.GetMapToolbar():
-            self.toolbars['map'].OnTool(event)
-            self.toolbars['map'].action['desc'] = ''
-        
-        self.MapWindow.mouse['use'] = "fly"
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["hand"])
-        self.MapWindow.SetFocus()
-        
-    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 SaveToFile(self, event):
-        """!Save map to image
-        """
-        if self.IsPaneShown('3d'):
-            filetype = "PPM file (*.ppm)|*.ppm|TIF file (*.tif)|*.tif"
-            ltype = [{ 'ext' : 'ppm', 'type' : 'ppm' },
-                     { 'ext' : 'tif', 'type' : 'tif' }]
-        else:
-            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 OnCloseWindow(self, event):
-        """!Window closed.
-        Also close associated layer tree page
-        """
-        pgnum = None
-        self.Map.Clean()
-        
-        # close edited map and 3D tools properly
-        if self.GetToolbar('vdigit'):
-            maplayer = self.toolbars['vdigit'].GetLayer()
-            if maplayer:
-                self.toolbars['vdigit'].OnExit()
-        if self.IsPaneShown('3d'):
-            self.RemoveNviz()
-        
-        if not self._layerManager:
-            self.Destroy()
-        elif self.page:
-            pgnum = self.layerbook.GetPageIndex(self.page)
-            if pgnum > -1:
-                self.layerbook.DeletePage(pgnum)
-    
-    
-    def QueryMap(self, x, y):
-        """!Query raster or vector map layers by r/v.what
-        
-        @param x,y coordinates
-        """
-        # set query snap distance for v.what at map unit equivalent of 10 pixels
-        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
-        east, north = self.MapWindow.Pixel2Cell((x, y))
-        
-        if not self.IsStandalone():
-            num = 0
-            for layer in self.tree.GetSelections():
-                ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
-                if ltype in ('raster', 'rgb', 'his',
-                             'vector', 'thememap', 'themechart'):
-                    num += 1
-            
-            if num < 1:
-                gcmd.GMessage(parent = self,
-                              message = _('No raster or vector map layer selected for querying.'))
-                return
-        
-        rast = list()
-        vect = list()
-        rcmd = ['r.what', '--v']
-        vcmd = ['v.what', '--v']
-        
-        if self.IsStandalone():
-            pass
-        else:
-            for layer in self.tree.GetSelections():
-                ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
-                dcmd = self.tree.GetPyData(layer)[0]['cmd']
-                name, found = utils.GetLayerNameFromCmd(dcmd)
-                
-                if not found:
-                    continue
-                if ltype == 'raster':
-                    rast.append(name)
-                elif ltype in ('rgb', 'his'):
-                    for iname in name.split('\n'):
-                        rast.append(iname)
-                elif ltype in ('vector', 'thememap', 'themechart'):
-                    vect.append(name)
-        # rasters are not queried this way in 3D, we don't want them now
-        if self.IsPaneShown('3d'):
-            rast = list()
-        # use display region settings instead of computation region settings
-        self.tmpreg = os.getenv("GRASS_REGION")
-        os.environ["GRASS_REGION"] = self.Map.SetRegion(windres = False)
-        
-        # build query commands for any selected rasters and vectors
-        if rast:
-            rcmd.append('-f')
-            rcmd.append('-n')
-            rcmd.append('input=%s' % ','.join(rast))
-            rcmd.append('east_north=%f,%f' % (float(east), float(north)))
-        
-        if vect:
-            # check for vector maps open to be edited
-            digitToolbar = self.toolbars['vdigit']
-            if digitToolbar:
-                lmap = digitToolbar.GetLayer().GetName()
-                for name in vect:
-                    if lmap == name:
-                        self._layerManager.goutput.WriteWarning(_("Vector map <%s> "
-                                                                  "opened for editing - skipped.") % map)
-                        vect.remove(name)
-            
-            if len(vect) < 1:
-                self._layerManager.goutput.WriteCmdLog(_("Nothing to query."))
-                return
-            
-            vcmd.append('-a')
-            vcmd.append('map=%s' % ','.join(vect))
-            vcmd.append('layer=%s' % ','.join(['-1'] * len(vect)))
-            vcmd.append('east_north=%f,%f' % (float(east), float(north)))
-            vcmd.append('distance=%f' % float(qdist))
-        
-        Debug.msg(1, "QueryMap(): raster=%s vector=%s" % (','.join(rast),
-                                                          ','.join(vect)))
-        # parse query command(s)
-        if not self.IsStandalone():
-            if rast:
-                self._layerManager.goutput.RunCmd(rcmd,
-                                                  compReg = False,
-                                                  onDone  =  self._QueryMapDone)
-            if vect:
-                self._layerManager.goutput.RunCmd(vcmd,
-                                                  onDone = self._QueryMapDone)
-        else:
-            if rast:
-                gcmd.RunCommand(rcmd)
-            if vect:
-                gcmd.RunCommand(vcmd)
-        
-    def _QueryMapDone(self, cmd, returncode):
-        """!Restore settings after querying (restore GRASS_REGION)
-        
-        @param returncode command return code
-        """
-        if hasattr(self, "tmpreg"):
-            if self.tmpreg:
-                os.environ["GRASS_REGION"] = self.tmpreg
-            elif 'GRASS_REGION' in os.environ:
-                del os.environ["GRASS_REGION"]
-        elif 'GRASS_REGION' in os.environ:
-            del os.environ["GRASS_REGION"]
-        
-        if hasattr(self, "tmpreg"):
-            del self.tmpreg
-        
-    def QueryVector(self, x, y):
-        """!Query vector map layer features
-
-        Attribute data of selected vector object are displayed in GUI dialog.
-        Data can be modified (On Submit)
-        """
-        if not self.tree.layer_selected or \
-                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
-            gcmd.GMessage(parent = self,
-                          message = _("No map layer selected for querying."))
-            return
-        
-        posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
-                                         y + self.MapWindow.dialogOffset))
-        
-        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) /
-                        self.Map.width)
-        
-        east, north = self.MapWindow.Pixel2Cell((x, y))
-        
-        mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
-        
-        if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
-                grass.gisenv()['MAPSET']:
-            mode = 'display'
-        else:
-            mode = 'update'
-        
-        if self.dialogs['attributes'] is None:
-            dlg = dbm_dialogs.DisplayAttributesDialog(parent = self.MapWindow,
-                                                      map = mapName,
-                                                      query = ((east, north), qdist),
-                                                      pos = posWindow,
-                                                      action = mode)
-            self.dialogs['attributes'] = dlg
-        
-        else:
-            # selection changed?
-            if not self.dialogs['attributes'].mapDBInfo or \
-                    self.dialogs['attributes'].mapDBInfo.map != mapName:
-                self.dialogs['attributes'].UpdateDialog(map = mapName, query = ((east, north), qdist),
-                                                        action = mode)
-            else:
-                self.dialogs['attributes'].UpdateDialog(query = ((east, north), qdist),
-                                                        action = mode)
-        if not self.dialogs['attributes'].IsFound():
-            self._layerManager.goutput.WriteLog(_('Nothing found.'))
-        
-        cats = self.dialogs['attributes'].GetCats()
-        
-        qlayer = None
-        if not self.IsPaneShown('3d'):
-            try:
-                qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)[0]
-            except IndexError:
-                pass
-        
-        if self.dialogs['attributes'].mapDBInfo and cats:
-            if not self.IsPaneShown('3d'):
-                # highlight feature & re-draw map
-                if qlayer:
-                    qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
-                                                            useId = False,
-                                                            addLayer = False))
-                else:
-                    qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId = False)
-                
-                # set opacity based on queried layer
-                opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float = True)
-                qlayer.SetOpacity(opacity)
-                
-                self.MapWindow.UpdateMap(render = False, renderVector = False)
-            if not self.dialogs['attributes'].IsShown():
-                self.dialogs['attributes'].Show()
-        else:
-            if qlayer:
-                self.Map.DeleteLayer(qlayer)
-                self.MapWindow.UpdateMap(render = False, renderVector = False)
-            if self.dialogs['attributes'].IsShown():
-                self.dialogs['attributes'].Hide()
-        
-    def OnQuery(self, event):
-        """!Query tools menu"""
-        if self.GetMapToolbar():
-            self.toolbars['map'].OnTool(event)
-            action = self.toolbars['map'].GetAction()
-            
-        self.toolbars['map'].action['desc'] = 'queryMap'
-        self.MapWindow.mouse['use'] = "query"
-        
-        if not self.IsStandalone():
-            # switch to output console to show query results
-            self._layerManager.notebook.SetSelectionByName('output')
-        
-        self.MapWindow.mouse['box'] = "point"
-        self.MapWindow.zoomtype = 0
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["cross"])
-        
-    def AddTmpVectorMapLayer(self, name, cats, useId = False, addLayer = True):
-        """!Add temporal vector map layer to map composition
-
-        @param name name of map layer
-        @param useId use feature id instead of category 
-        """
-        # color settings from ATM
-        color = UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'color')
-        colorStr = str(color[0]) + ":" + \
-            str(color[1]) + ":" + \
-            str(color[2])
-
-        # icon used in vector display and its size
-        icon = ''
-        size = 0
-        vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
-        for p in vparam:
-            if '=' in p:
-                parg,pval = p.split('=')
-                if parg == 'icon': icon = pval
-                elif parg == 'size': size = int(pval)
-
-        pattern = ["d.vect",
-                   "map=%s" % name,
-                   "color=%s" % colorStr,
-                   "fcolor=%s" % colorStr,
-                   "width=%d"  % UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'width')]
-        if icon != '':
-            pattern.append('icon=%s' % icon)
-        if size > 0:
-            pattern.append('size=%i' % size)
-        
-        if useId:
-            cmd = pattern
-            cmd.append('-i')
-            cmd.append('cats=%s' % str(cats))
-        else:
-            cmd = []
-            for layer in cats.keys():
-                cmd.append(copy.copy(pattern))
-                lcats = cats[layer]
-                cmd[-1].append("layer=%d" % layer)
-                cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
-        
-        if addLayer:
-            if useId:
-                return self.Map.AddLayer(type = 'vector', name = globalvar.QUERYLAYER, command = cmd,
-                                         l_active = True, l_hidden = True, l_opacity = 1.0)
-            else:
-                return self.Map.AddLayer(type = 'command', name = globalvar.QUERYLAYER, command = cmd,
-                                         l_active = True, l_hidden = True, l_opacity = 1.0)
-        else:
-            return cmd
-
-    def OnAnalyze(self, event):
-        """!Analysis tools menu
-        """
-        point = wx.GetMousePosition()
-        toolsmenu = wx.Menu()
-        icons = Icons['displayWindow']
-        
-        # Add items to the menu
-        measure = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["measure"].GetLabel())
-        measure.SetBitmap(icons["measure"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(measure)
-        self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
-        
-        profile = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["profile"].GetLabel())
-        profile.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(profile)
-        self.Bind(wx.EVT_MENU, self.OnProfile, profile)
-
-        scatterplot = wx.MenuItem(toolsmenu, wx.ID_ANY, _("Create bivariate scatterplot of raster maps"))
-        scatterplot.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(scatterplot)
-        self.Bind(wx.EVT_MENU, self.OnScatterplot, scatterplot)
-
-        histogram2 = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
-        histogram2.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(histogram2)
-        self.Bind(wx.EVT_MENU, self.OnHistogramPyPlot, histogram2)
-
-        histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, _("Create histogram with d.histogram"))
-        histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
-        toolsmenu.AppendItem(histogram)
-        self.Bind(wx.EVT_MENU, self.OnHistogram, histogram)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(toolsmenu)
-        toolsmenu.Destroy()
-
-    def OnMeasure(self, event):
-        """!Init measurement routine that calculates map distance
-        along transect drawn on map display
-        """
-        self.totaldist = 0.0 # total measured distance
-        
-        # switch Layer Manager to output console to show measure results
-        self._layerManager.notebook.SetSelectionByName('output')
-        
-        # change mouse to draw line for measurement
-        self.MapWindow.mouse['use'] = "measure"
-        self.MapWindow.mouse['box'] = "line"
-        self.MapWindow.zoomtype = 0
-        self.MapWindow.pen     = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
-        self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
-        
-        # change the cursor
-        self.MapWindow.SetCursor(self.cursors["pencil"])
-        
-        # initiating output
-        style = self._layerManager.goutput.cmd_output.StyleWarning
-        self._layerManager.goutput.WriteLog(_('Click and drag with left mouse button '
-                                              'to measure.%s'
-                                              'Double click with left button to clear.') % \
-                                                (os.linesep), style)
-        if self.Map.projinfo['proj'] != 'xy':
-            units = self.Map.projinfo['units']
-            self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
-                                                   + units + '):')
-        else:
-            self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
-        
-        if self.Map.projinfo['proj'] == 'll':
-            try:
-                import grass.lib.gis as gislib
-                global haveCtypes
-                haveCtypes = True
-
-                gislib.G_begin_distance_calculations()
-            except ImportError, e:
-                self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
-                                                          'supported by this tool.\n'
-                                                          'Reason: %s' % e))
-        
-    def MeasureDist(self, beginpt, endpt):
-        """!Calculate map distance from screen distance
-        and print to output window
-        """
-        self._layerManager.notebook.SetSelectionByName('output')
-        
-        dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
-        
-        dist = round(dist, 3)
-        d, dunits = self.FormatDist(dist)
-        
-        self.totaldist += dist
-        td, tdunits = self.FormatDist(self.totaldist)
-        
-        strdist = str(d)
-        strtotdist = str(td)
-        
-        if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
-            angle = int(math.degrees(math.atan2(north,east)) + 0.5)
-            angle = 180 - angle
-            if angle < 0:
-                angle = 360 + angle
-            
-            mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
-                % (_('segment'), strdist, dunits,
-                   _('total distance'), strtotdist, tdunits,
-                   _('bearing'), angle, _('deg'),
-                   '-' * 60)
-        else:
-            mstring = '%s = %s %s\n%s = %s %s\n%s' \
-                % (_('segment'), strdist, dunits,
-                   _('total distance'), strtotdist, tdunits,
-                   '-' * 60)
-        
-        self._layerManager.goutput.WriteLog(mstring)
-        
-        return dist
-
-    def OnProfile(self, event):
-        """!Init profile canvas and tools
-        """
-        raster = []
-        if self.tree.layer_selected and \
-                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
-            raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-
-        self.profile = ProfileFrame(self,
-                                            id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
-                                            style = wx.DEFAULT_FRAME_STYLE, 
-                                            rasterList = raster)
-        self.profile.Show()
-        # Open raster select dialog to make sure that a raster (and the desired raster)
-        # is selected to be profiled
-        self.profile.OnSelectRaster(None)
-
-    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 and \
-                not haveCtypes:
-            if dist < 1:
-                outunits = 'min'
-                divisor = (1/60.0)
-            else:
-                outunits = 'deg'
-        else:
-            outunits = 'meters'
-        
-        # 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 OnHistogramPyPlot(self, event):
-        """!Init PyPlot histogram display canvas and tools
-        """
-        raster = []
-
-        for layer in self.tree.GetSelections():
-            if self.tree.GetPyData(layer)[0]['maplayer'].GetType() != 'raster':
-                continue
-            raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
-
-        self.histogramPyPlot = HistFramePyPlot(self, id = wx.ID_ANY, 
-                                                pos = wx.DefaultPosition, size = (700,300),
-                                                style = wx.DEFAULT_FRAME_STYLE, 
-                                                rasterList = raster)
-        self.histogramPyPlot.Show()
-        # Open raster select dialog to make sure that a raster (and the desired raster)
-        # is selected to be histogrammed
-        self.histogramPyPlot.OnSelectRaster(None)
-        
-    def OnScatterplot(self, event):
-        """!Init PyPlot scatterplot display canvas and tools
-        """
-        raster = []
-
-        for layer in self.tree.GetSelections():
-            if self.tree.GetPyData(layer)[0]['maplayer'].GetType() != 'raster':
-                continue
-            raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
-
-        self.scatterplot = ScatterFrame(self, id = wx.ID_ANY, 
-                                                pos = wx.DefaultPosition, size = (700,300),
-                                                style = wx.DEFAULT_FRAME_STYLE, 
-                                                rasterList = raster)
-        self.scatterplot.Show()
-        # Open raster select dialog to make sure that at least 2 rasters (and the desired rasters)
-        # are selected to be plotted
-        self.scatterplot.OnSelectRaster(None)
-
-    def OnHistogram(self, event):
-        """!Init histogram display canvas and tools
-        """
-        self.histogram = HistFrame(parent = self, id = wx.ID_ANY, size = globalvar.HIST_WINDOW_SIZE,
-                                   style = wx.DEFAULT_FRAME_STYLE)
-        
-        # show new display
-        self.histogram.Show()
-        self.histogram.Refresh()
-        self.histogram.Update()
-       
-    def OnDecoration(self, event):
-        """!Decorations overlay menu
-        """
-        point = wx.GetMousePosition()
-        decmenu = wx.Menu()
-        icons = Icons['displayWindow']
-        
-        # Add items to the menu
-        AddScale = wx.MenuItem(decmenu, wx.ID_ANY, icons["addBarscale"].GetLabel())
-        AddScale.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddScale)
-        self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
-        # temporary
-        if self.IsPaneShown('3d'):
-            AddScale.Enable(False)
-            AddArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("Add north arrow"))
-            AddArrow.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
-            decmenu.AppendItem(AddArrow)
-            self.Bind(wx.EVT_MENU, self.OnAddArrow, AddArrow)
-        
-        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, icons["addLegend"].GetLabel())
-        AddLegend.SetBitmap(icons["addLegend"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddLegend)
-        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
-        
-        AddText = wx.MenuItem(decmenu, wx.ID_ANY, icons["addText"].GetLabel())
-        AddText.SetBitmap(icons["addText"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddText)
-        self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
-        
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(decmenu)
-        decmenu.Destroy()
-        
-    def OnAddBarscale(self, event):
-        """!Handler for scale/arrow map decoration menu selection.
-        """
-        if self.dialogs['barscale']:
-            return
-        
-        id = 0 # unique index for overlay layer
-
-        # If location is latlon, only display north arrow (scale won't work)
-        #        proj = self.Map.projinfo['proj']
-        #        if proj == 'll':
-        #            barcmd = 'd.barscale -n'
-        #        else:
-        #            barcmd = 'd.barscale'
-
-        # decoration overlay control dialog
-        self.dialogs['barscale'] = \
-            gdialogs.DecorationDialog(parent = self, title = _('Scale and North arrow'),
-                                      size = (350, 200),
-                                      style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                                      cmd = ['d.barscale', 'at=0,95'],
-                                      ovlId = id,
-                                      name = 'barscale',
-                                      checktxt = _("Show/hide scale and North arrow"),
-                                      ctrltxt = _("scale object"))
-
-        self.dialogs['barscale'].CentreOnParent()
-        ### dialog cannot be show as modal - in the result d.barscale is not selectable
-        ### self.dialogs['barscale'].ShowModal()
-        self.dialogs['barscale'].Show()
-        self.MapWindow.mouse['use'] = 'pointer'
-
-    def OnAddLegend(self, event):
-        """!Handler for legend map decoration menu selection.
-        """
-        if self.dialogs['legend']:
-            return
-        
-        id = 1 # index for overlay layer in render
-        
-        cmd = ['d.legend', 'at=5,50,2,5']
-        
-        if self.tree and self.tree.layer_selected and \
-                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
-            cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-        
-        # Decoration overlay control dialog
-        self.dialogs['legend'] = \
-            gdialogs.DecorationDialog(parent = self, title = ('Legend'),
-                                      size = (350, 200),
-                                      style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
-                                      cmd = cmd,
-                                      ovlId = id,
-                                      name = 'legend',
-                                      checktxt = _("Show/hide legend"),
-                                      ctrltxt = _("legend object")) 
-    
-        self.dialogs['legend'].CentreOnParent() 
-        ### dialog cannot be show as modal - in the result d.legend is not selectable
-        ### self.dialogs['legend'].ShowModal()
-        self.dialogs['legend'].Show()
-        self.MapWindow.mouse['use'] = 'pointer'
-        
-    def OnAddText(self, event):
-        """!Handler for text decoration menu selection.
-        """
-        if self.MapWindow.dragid > -1:
-            id = self.MapWindow.dragid
-            self.MapWindow.dragid = -1
-        else:
-            # index for overlay layer in render
-            if len(self.MapWindow.textdict.keys()) > 0:
-                id = max(self.MapWindow.textdict.keys()) + 1
-            else:
-                id = 101
-        
-        self.dialogs['text'] = gdialogs.TextLayerDialog(parent = self, ovlId = id, 
-                                                        title = _('Add text layer'),
-                                                        size = (400, 200))
-        self.dialogs['text'].CenterOnParent()
-
-        # If OK button pressed in decoration control dialog
-        if self.dialogs['text'].ShowModal() == wx.ID_OK:
-            text = self.dialogs['text'].GetValues()['text']
-            active = self.dialogs['text'].GetValues()['active']
-        
-            # delete object if it has no text or is not active
-            if text == '' or active == False:
-                try:
-                    self.MapWindow2D.pdc.ClearId(id)
-                    self.MapWindow2D.pdc.RemoveId(id)
-                    del self.MapWindow.textdict[id]
-                    if self.IsPaneShown('3d'):
-                        self.MapWindow3D.UpdateOverlays()
-                        self.MapWindow.UpdateMap()
-                    else:
-                        self.MapWindow2D.UpdateMap(render = False, renderVector = False)
-                except:
-                    pass
-                return
-
-            
-            self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
-            
-            if self.IsPaneShown('3d'):
-                self.MapWindow3D.UpdateOverlays()
-                self.MapWindow3D.UpdateMap()
-            else:
-                self.MapWindow2D.pdc.ClearId(id)
-                self.MapWindow2D.pdc.SetId(id)
-                self.MapWindow2D.UpdateMap(render = False, renderVector = False)
-            
-        self.MapWindow.mouse['use'] = 'pointer'
-    
-    def OnAddArrow(self, event):
-        """!Handler for north arrow menu selection.
-            Opens Appearance page of nviz notebook.
-        """
-        
-        self._layerManager.nviz.SetPage('decoration')
-        self.MapWindow3D.SetDrawArrow((70, 70))
-        
-    def GetOptData(self, dcmd, type, params, propwin):
-        """!Callback method for decoration overlay command generated by
-        dialog created in menuform.py
-        """
-        # Reset comand and rendering options in render.Map. Always render decoration.
-        # Showing/hiding handled by PseudoDC
-        self.Map.ChangeOverlay(ovltype = type, type = 'overlay', name = '', command = dcmd,
-                               l_active = True, l_render = False)
-        self.params[type] = params
-        self.propwin[type] = propwin
-
-    def OnZoomToMap(self, event):
-        """!Set display extents to match selected raster (including
-        NULLs) or vector map.
-        """
-        layers = None
-        if self.IsStandalone():
-            layers = self.MapWindow.GetMap().GetListOfLayers(l_active = False)
-        
-        self.MapWindow.ZoomToMap(layers = layers)
-
-    def OnZoomToRaster(self, event):
-        """!Set display extents to match selected raster map (ignore NULLs)
-        """
-        self.MapWindow.ZoomToMap(ignoreNulls = True)
-        
-    def OnZoomToSaved(self, event):
-        """!Set display geometry to match extents in
-        saved region file
-        """
-        self.MapWindow.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'))
-        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 extent'))
-        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, alignExtent = True):
-        """!Set properies of map display window"""
-        self.SetProperty('render', render)
-        self.statusbarManager.SetMode(mode)
-        self.StatusbarUpdate()
-        self.SetProperty('region', showCompExtent)
-        self.SetProperty('alignExtent', alignExtent)
-        self.SetProperty('resolution', constrainRes)
-        self.SetProperty('projection', projection)
-        
-    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
-    
-    def GetMapToolbar(self):
-        """!Returns toolbar with zooming tools"""
-        return self.toolbars['map']
-    
-class MapApp(wx.App):
-    def OnInit(self):
-        wx.InitAllImageHandlers()
-        if __name__ == "__main__":
-            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
-            Map = render.Map(cmdfile = monFile['cmd'], mapfile = monFile['map'],
-                             envfile = monFile['env'], monitor = monName)
-        else:
-            Map = None
-        
-        self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
-                               size = monSize)
-        # self.SetTopWindow(Map)
-        self.mapFrm.Show()
-        
-        if __name__ == "__main__":
-            self.timer = wx.PyTimer(self.watcher)
-            #check each 0.5s
-            global mtime
-            mtime = 500
-            self.timer.Start(mtime)
-            
-        return True
-    
-    def OnExit(self):
-        if __name__ == "__main__":
-            # stop the timer
-            # self.timer.Stop()
-            # terminate thread
-            for f in monFile.itervalues():
-                grass.try_remove(f)
-            
-    def watcher(self):
-        """!Redraw, if new layer appears (check's timestamp of
-        cmdfile)
-        """
-        # todo: events
-        if os.path.getmtime(monFile['cmd']) > self.cmdTimeStamp:
-            self.timer.Stop()
-            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
-            self.mapFrm.OnDraw(None)
-            self.mapFrm.GetMap().GetLayersFromCmdFile()
-            self.timer.Start(mtime)
-        
-if __name__ == "__main__":
-    # set command variable
-    if len(sys.argv) < 5:
-        print __doc__
-        sys.exit(1)
-    
-    monName = sys.argv[1]
-    monFile = { 'map' : sys.argv[2],
-                'cmd' : sys.argv[3],
-                'env' : sys.argv[4],
-                }
-    if len(sys.argv) >= 6:
-        try:
-            monSize[0] = int(sys.argv[5])
-        except ValueError:
-            pass
-    
-    if len(sys.argv) == 7:
-        try:
-            monSize[1] = int(sys.argv[6])
-        except ValueError:
-            pass
-    
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    grass.verbose(_("Starting map display <%s>...") % (monName))
-
-    gcmd.RunCommand('g.gisenv',
-                    set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
-    
-    gm_map = MapApp(0)
-    # set title
-    gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
-                             monName + 
-                             " - Location: " + grass.gisenv()["LOCATION_NAME"]))
-    
-    gm_map.MainLoop()
-    
-    grass.verbose(_("Stopping map display <%s>...") % (monName))
-
-    # clean up GRASS env variables
-    env = grass.gisenv()
-    env_name = 'MONITOR_%s' % monName
-    for key in env.keys():
-        if key.find(env_name) == 0:
-            gcmd.RunCommand('g.gisenv',
-                              set = '%s=' % key)
-        if key == 'MONITOR' and env[key] == monName:
-            gcmd.RunCommand('g.gisenv',
-                            set = '%s=' % key)
-    
-    sys.exit(0)

Deleted: grass/trunk/gui/wxpython/gui_modules/mapdisp_statusbar.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp_statusbar.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp_statusbar.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1059 +0,0 @@
-"""!
- at package mapdisp_statusbar.py
-
- at brief Classes for statusbar management
-
-Classes:
- - SbException
- - SbManager
- - SbItem
- - SbRender
- - SbShowRegion
- - SbAlignExtent
- - SbResolution
- - SbMapScale
- - SbGoTo
- - SbProjection
- - SbMask
- - SbTextItem
- - SbDisplayGeometry
- - SbCoordinates
- - SbRegionExtent
- - SbCompRegionExtent
- - SbProgress
-
-
-(C) 2006-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Vaclav Petras <wenzeslaus gmail.com>
- at author Anna Kratochvilova <kratochanna gmail.com>
-"""
-
-import wx
-
-import utils
-import gcmd
-from grass.script import core as grass
-from preferences import globalSettings as UserSettings
-
-class SbException:
-    """! Exception class used in SbManager and SbItems"""
-    def __init__(self, message):
-        self.message = message
-    def __str__(self):
-        return self.message
-
-
-class SbManager:
-    """!Statusbar manager for wx.Statusbar and SbItems.
-    
-    Statusbar manager manages items added by AddStatusbarItem method.
-    Provides progress bar (SbProgress) and choice (wx.Choice).
-    Items with position 0 are shown according to choice selection.
-    Only one item of the same class is supposed to be in statusbar.
-    Manager user have to create statusbar on his own, add items to manager
-    and call Update method to show particular widgets.
-    User settings (group = 'display', key = 'statusbarMode', subkey = 'selection')
-    are taken into account.
-    
-    @todo generalize access to UserSettings (specify group, etc.) 
-    @todo add GetMode method using name instead of index
-    """
-    def __init__(self, mapframe, statusbar):
-        """!Connects manager to statusbar
-        
-        Creates choice and progress bar.
-        """
-        self.mapFrame = mapframe
-        self.statusbar = statusbar
-        
-        self.choice = wx.Choice(self.statusbar, wx.ID_ANY)
-        
-        self.choice.Bind(wx.EVT_CHOICE, self.OnToggleStatus)
-        
-        self.statusbarItems = dict()
-        
-        self._postInitialized = False
-        
-        self.progressbar = SbProgress(self.mapFrame, self.statusbar)
-        
-        self._hiddenItems = {}
-    
-    def SetProperty(self, name, value):
-        """!Sets property represented by one of contained SbItems
-            
-        @param name name of SbItem (from name attribute)
-        @param value value to be set
-        """
-        self.statusbarItems[name].SetValue(value)
-        
-    def GetProperty(self, name):
-        """!Returns property represented by one of contained SbItems
-        
-        @param name name of SbItem (from name attribute)
-        """
-        return self.statusbarItems[name].GetValue()
-        
-    def HasProperty(self, name):
-        """!Checks whether property is represented by one of contained SbItems
-        
-        @param name name of SbItem (from name attribute)
-        
-        @returns True if particular SbItem is contained, False otherwise
-        """
-        if name in self.statusbarItems:
-            return True
-        return False
-    
-    def AddStatusbarItem(self, item):
-        """!Adds item to statusbar
-        
-        If item position is 0, item is managed by choice.
-        
-        @see AddStatusbarItemsByClass
-        """
-        self.statusbarItems[item.name] = item
-        if item.GetPosition() == 0:
-            self.choice.Append(item.label, clientData = item) #attrError?
-            
-    def AddStatusbarItemsByClass(self, itemClasses, **kwargs):
-        """!Adds items to statusbar
-
-        @param itemClasses list of classes of items to be add
-        @param kwargs SbItem constructor parameters
-        
-        @see AddStatusbarItem
-        """
-        for Item in itemClasses:
-            item = Item(**kwargs)
-            self.AddStatusbarItem(item)
-                      
-    def HideStatusbarChoiceItemsByClass(self, itemClasses):
-        """!Hides items showed in choice
-        
-        Hides items with position 0 (items showed in choice) by removing
-        them from choice.
-        
-        @param itemClasses list of classes of items to be hided
-        
-        @see ShowStatusbarChoiceItemsByClass
-        @todo consider adding similar function which would take item names
-        """
-        index = []
-        for itemClass in itemClasses:
-            for i in range(0, self.choice.GetCount() - 1):
-                item = self.choice.GetClientData(i)
-                if item.__class__ == itemClass:
-                    index.append(i)
-                    self._hiddenItems[i] = item
-        # must be sorted in reverse order to be removed correctly
-        for i in sorted(index, reverse = True):
-            self.choice.Delete(i)
-        
-    def ShowStatusbarChoiceItemsByClass(self, itemClasses):
-        """!Shows items showed in choice
-        
-        Shows items with position 0 (items showed in choice) by adding
-        them to choice.
-        Items are restored in their old positions.
-        
-        @param itemClasses list of classes of items to be showed
-        
-        @see HideStatusbarChoiceItemsByClass
-        """
-        # must be sorted to be inserted correctly
-        for pos in sorted(self._hiddenItems.keys()):
-            item = self._hiddenItems[pos]
-            if item.__class__ in itemClasses:
-                self.choice.Insert(item.label, pos, item)
-        
-    def ShowItem(self, itemName):
-        """!Invokes showing of particular item
-        
-        @see Update
-        """
-        self.statusbarItems[itemName].Show()
-        
-    def _postInit(self):
-        """!Post-initialization method
-        
-        It sets internal user settings,
-        set choice's selection (from user settings) and does reposition.
-        It needs choice filled by items.
-        it is called automatically.
-        """
-        UserSettings.Set(group = 'display',
-                         key = 'statusbarMode',
-                         subkey = 'choices',
-                         value = self.choice.GetItems(),
-                         internal = True)
-        
-        self.choice.SetSelection(UserSettings.Get(group = 'display',
-                                                  key = 'statusbarMode',
-                                                  subkey = 'selection')) 
-        self.Reposition()
-        
-        self._postInitialized = True
-        
-    def Update(self):
-        """!Updates statusbar
-
-        It always updates mask.
-        """
-        if not self._postInitialized:
-            self._postInit()
-        
-        for item in self.statusbarItems.values():
-            if item.GetPosition() == 0:
-                item.Hide()
-            else:
-                item.Update() # mask, render
-        
-        if self.choice.GetCount() > 0:
-            item = self.choice.GetClientData(self.choice.GetSelection())
-            item.Update()
-        
-    def Reposition(self):
-        """!Reposition items in statusbar
-        
-        Set positions to all items managed by statusbar manager.
-        It should not be necessary to call it manually.
-        """
-        
-        widgets = []
-        for item in self.statusbarItems.values():
-            widgets.append((item.GetPosition(), item.GetWidget()))
-            
-        widgets.append((1, self.choice))
-        widgets.append((0, self.progressbar.GetWidget()))
-                
-        for idx, win in widgets:
-            if not win:
-                continue
-            rect = self.statusbar.GetFieldRect(idx)
-            if idx == 0: # show region / mapscale / process bar
-                # -> size
-                wWin, hWin = win.GetBestSize()
-                if win == self.progressbar.GetWidget():
-                    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 == 2: # mask
-                    x += 5
-                    y += 4
-                elif idx == 3: # render
-                    x += 5
-            win.SetPosition((x, y))
-            win.SetSize((w, h))
-        
-    def GetProgressBar(self):
-        """!Returns progress bar"""
-        return self.progressbar
-    
-    def OnToggleStatus(self, event):
-        """!Toggle status text
-        """
-        self.Update()
-        
-    def SetMode(self, modeIndex):
-        """!Sets current mode
-        
-        Mode is usually driven by user through choice.
-        """
-        self.choice.SetSelection(modeIndex)
-    
-    def GetMode(self):
-        """!Returns current mode"""
-        return self.choice.GetSelection()
-
-class SbItem:
-    """!Base class for statusbar items.
-    
-    Each item represents functionality (or action) controlled by statusbar
-    and related to MapFrame.
-    One item is usually connected with one widget but it is not necessary.
-    Item can represent property (depends on manager).
-    Items are not widgets but can provide interface to them.
-    Items usually has requirements to MapFrame instance
-    (specified as MapFrame.methodname or MapWindow.methodname).
-    
-    @todo consider externalizing position (see SbProgress use in SbManager)
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        """!
-        
-        @param mapframe instance of class with MapFrame interface
-        @param statusbar statusbar instance (wx.Statusbar)
-        @param position item position in statusbar
-        
-        @todo rewrite Update also in derived classes to take in account item position
-        """
-        self.mapFrame = mapframe
-        self.statusbar = statusbar
-        self.position = position
-    
-    def Show(self):
-        """!Invokes showing of underlying widget.
-        
-        In derived classes it can do what is appropriate for it,
-        e.g. showing text on statusbar (only).
-        """
-        self.widget.Show()
-        
-    def Hide(self):
-        self.widget.Hide()
-        
-    def SetValue(self, value):
-        self.widget.SetValue(value)
-    
-    def GetValue(self):
-        return self.widget.GetValue()
-        
-    def GetPosition(self):
-        return self.position
-    
-    def GetWidget(self):
-        """!Returns underlaying winget.
-        
-        @return widget or None if doesn't exist
-        """
-        return self.widget
-    
-    def _update(self, longHelp):
-        """!Default implementation for Update method.
-        
-        @param longHelp True to enable long help (help from toolbars)
-        """
-        self.statusbar.SetStatusText("", 0)
-        self.Show()
-        self.mapFrame.StatusbarEnableLongHelp(longHelp)
-        
-    def Update(self):
-        """!Called when statusbar action is activated (e.g. through wx.Choice).
-        """
-        self._update(longHelp = False)
-
-class SbRender(SbItem):
-    """!Checkbox to enable and disable auto-rendering.
-    
-    Requires MapFrame.OnRender method.
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'render'
-        
-        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
-                                  label = _("Render"))
-        
-        self.widget.SetValue(UserSettings.Get(group = 'display',
-                                              key = 'autoRendering',
-                                              subkey = 'enabled'))
-        self.widget.Hide()
-        self.widget.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
-                                            
-        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleRender)
-        
-    def OnToggleRender(self, event):
-        # (other items should call self.mapFrame.IsAutoRendered())
-        if self.GetValue():
-            self.mapFrame.OnRender(None)
-
-    def Update(self):
-        self.Show()
-        
-class SbShowRegion(SbItem):
-    """!Checkbox to enable and disable showing of computational region.
-    
-    Requires MapFrame.OnRender, MapFrame.IsAutoRendered, MapFrame.GetWindow.
-    Expects that instance returned by MapFrame.GetWindow will handle
-    regionCoords attribute. 
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'region'
-        self.label = _("Show comp. extent")
-        
-        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
-                                  label = _("Show computational extent"))
-        
-        self.widget.SetValue(False)
-        self.widget.Hide()
-        self.widget.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).")))
-                                            
-        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion)
-    
-    def OnToggleShowRegion(self, event):
-        """!Shows/Hides extent (comp. region) in map canvas.
-        
-        Shows or hides according to checkbox value.
-        """
-        if self.widget.GetValue():
-            # show extent
-            self.mapFrame.GetWindow().regionCoords = []
-        elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
-            del self.mapFrame.GetWindow().regionCoords
-
-        # redraw map if auto-rendering is enabled
-        if self.mapFrame.IsAutoRendered():
-            self.mapFrame.OnRender(None)
-
-    def SetValue(self, value):
-        SbItem.SetValue(self, value)
-        if value:
-            self.mapFrame.GetWindow().regionCoords = []
-        elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
-            del self.mapFrame.GetWindow().regionCoords
-            
-class SbAlignExtent(SbItem):
-    """!Checkbox to select zoom behavior.
-    
-    Used by BufferedWindow (through MapFrame property).
-    See tooltip for explanation.
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'alignExtent'
-        self.label = _("Display mode")
-        
-        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
-                                  label = _("Align region extent based on display size"))
-        
-        self.widget.SetValue(UserSettings.Get(group = 'display', key = 'alignExtent', subkey = 'enabled'))
-        self.widget.Hide()
-        self.widget.SetToolTip(wx.ToolTip (_("Align region extent based on display "
-                                             "size from center point. "
-                                             "Default value for new map displays can "
-                                             "be set up in 'User GUI settings' dialog.")))      
-        
-class SbResolution(SbItem):
-    """!Checkbox to select used display resolution.
-    
-    Requires MapFrame.OnRender method. 
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'resolution'
-        self.label = _("Display resolution")
-        
-        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
-                                  label = _("Constrain display resolution to computational settings"))
-        
-        self.widget.SetValue(UserSettings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
-        self.widget.Hide()
-        self.widget.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.")))
-                                            
-        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleUpdateMap)
-        
-    def OnToggleUpdateMap(self, event):
-        """!Update display when toggle display mode
-        """
-        # redraw map if auto-rendering is enabled
-        if self.mapFrame.IsAutoRendered():
-            self.mapFrame.OnRender(None)
-
-
-class SbMapScale(SbItem):
-    """!Editable combobox to get/set current map scale.
-    
-    Requires MapFrame.GetMapScale, MapFrame.SetMapScale
-    and MapFrame.GetWindow (and GetWindow().UpdateMap()).
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'mapscale'
-        self.label = _("Map scale")
-        
-        self.widget = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
-                                                    style = wx.TE_PROCESS_ENTER,
-                                                    size = (150, -1))
-        
-        self.widget.SetItems(['1:1000',
-                              '1:5000',
-                              '1:10000',
-                              '1:25000',
-                              '1:50000',
-                              '1:100000',
-                              '1:1000000'])
-        self.widget.Hide()
-        self.widget.SetToolTip(wx.ToolTip (_("As everyone's monitors and resolutions "
-                                            "are set differently these values are not "
-                                            "true map scales, but should get you into "
-                                            "the right neighborhood.")))
-                                            
-        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale)
-        self.widget.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale)
-        
-        self.lastMapScale = None
-
-    def Update(self):
-        scale = self.mapFrame.GetMapScale()
-        self.statusbar.SetStatusText("")
-        try:
-            self.SetValue("1:%ld" % (scale + 0.5))
-        except TypeError:
-            pass # FIXME, why this should happen?
-        
-        self.lastMapScale = scale
-        self.Show()
-
-        # disable long help
-        self.mapFrame.StatusbarEnableLongHelp(False)
-
-    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.SetValue('1:%ld' % int(self.lastMapScale))
-            return
-        
-        self.mapFrame.SetMapScale(value)
-        
-        # redraw a map
-        self.mapFrame.GetWindow().UpdateMap()
-        self.GetWidget().SetFocus()
-        
-        
-class SbGoTo(SbItem):
-    """!Textctrl to set coordinates which to focus on.
-    
-    Requires MapFrame.GetWindow, MapWindow.GoTo method.
-    """
-    
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'goto'
-        self.label = _("Go to")
-        
-        self.widget = wx.TextCtrl(parent = self.statusbar, id = wx.ID_ANY,
-                                                value = "", style = wx.TE_PROCESS_ENTER,
-                                                size = (300, -1))
-        
-        self.widget.Hide()
-        
-        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo)
-    
-    def ReprojectENToMap(self, e, n, useDefinedProjection):
-        """!Reproject east, north from user defined projection
-        
-        @param e,n coordinate (for DMS string, else float or string)
-        @param useDefinedProjection projection defined by user in settings dialog
-        
-        @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
-        """
-        if useDefinedProjection:
-            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
-            if not settings:
-                raise SbException(_("Projection not defined (check the settings)"))
-            else:
-                # reproject values
-                projIn = settings
-                projOut = gcmd.RunCommand('g.proj',
-                                          flags = 'jf',
-                                          read = True)
-                proj = projIn.split(' ')[0].split('=')[1]
-                if proj in ('ll', 'latlong', 'longlat'):
-                    e, n = utils.DMS2Deg(e, n)
-                    proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
-                                                              projIn = projIn,
-                                                              projOut = projOut, flags = 'd')
-                    e, n = coord1
-                else:
-                    e, n = float(e), float(n)
-                    proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
-                                                              projIn = projIn,
-                                                              projOut = projOut, flags = 'd')
-                    e, n = coord1
-        elif self.mapFrame.GetMap().projinfo['proj'] == 'll':
-            e, n = utils.DMS2Deg(e, n)
-        else: 
-            e, n = float(e), float(n)
-        return e, n
-
-    def OnGoTo(self, event):
-        """!Go to position
-        """
-        try:
-            e, n = self.GetValue().split(';')
-            e, n = self.ReprojectENToMap(e, n, self.mapFrame.GetProperty('projection'))
-            self.mapFrame.GetWindow().GoTo(e, n)
-            self.widget.SetFocus()
-        except ValueError:
-            # FIXME: move this code to MapWindow/BufferedWindow/MapFrame
-            region = self.mapFrame.GetMap().GetCurrentRegion()
-            precision = int(UserSettings.Get(group = 'projection', key = 'format',
-                                             subkey = 'precision'))
-            format = UserSettings.Get(group = 'projection', key = 'format',
-                                      subkey = 'll')
-            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
-                    self.SetValue("%s" % utils.Deg2DMS(region['center_easting'], 
-                                                                            region['center_northing'],
-                                                                            precision = precision))
-            else:
-                self.SetValue("%.*f; %.*f" % \
-                               (precision, region['center_easting'],
-                                precision, region['center_northing']))
-        except SbException, e:
-            # FIXME: this may be useless since statusbar update checks user defined projection and this exception raises when user def proj does not exists
-            self.statusbar.SetStatusText(str(e), 0)
-
-    def GetCenterString(self, map):
-        """!Get current map center in appropriate format"""
-        region = map.GetCurrentRegion()
-        precision = int(UserSettings.Get(group = 'projection', key = 'format',
-                                         subkey = 'precision'))
-        format = UserSettings.Get(group = 'projection', key = 'format',
-                                  subkey = 'll')
-        projection = UserSettings.Get(group='projection', key='statusbar', subkey='proj4')
-        
-        if self.mapFrame.GetProperty('projection'):
-            if not projection:
-                raise SbException(_("Projection not defined (check the settings)"))
-            else:
-                proj, coord  = utils.ReprojectCoordinates(coord = (region['center_easting'],
-                                                                   region['center_northing']),
-                                                          projOut = projection,
-                                                          flags = 'd')
-                if coord:
-                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
-                        return "%s" % utils.Deg2DMS(coord[0],
-                                                                                coord[1],
-                                                                                precision = precision)
-                    else:
-                        return "%.*f; %.*f" % (precision, coord[0], precision, coord[1])
-                else:
-                    raise SbException(_("Error in projection (check the settings)"))
-        else:
-            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
-                return "%s" % utils.Deg2DMS(region['center_easting'], region['center_northing'],
-                                                                      precision = precision)
-            else:
-                return "%.*f; %.*f" % (precision, region['center_easting'], precision, region['center_northing'])
-
-
-    def SetCenter(self):
-        """!Set current map center as item value"""
-        center = self.GetCenterString(self.mapFrame.GetMap())
-        self.SetValue(center)
-        
-    def Update(self):
-        self.statusbar.SetStatusText("")
-        
-        try:
-            self.SetCenter()
-            self.Show()
-        except SbException, e:
-            self.statusbar.SetStatusText(str(e), 0)
-                        
-        # disable long help
-        self.mapFrame.StatusbarEnableLongHelp(False)
-        
-
-class SbProjection(SbItem):
-    """!Checkbox to enable user defined projection (can be set in settings)"""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'projection'
-        self.label = _("Projection")
-        
-        self.defaultLabel = _("Use defined projection")
-        
-        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
-                                  label = self.defaultLabel)
-        
-        self.widget.SetValue(False)
-        
-        # necessary?
-        size = self.widget.GetSize()
-        self.widget.SetMinSize((size[0] + 150, size[1]))
-        
-        self.widget.Hide()
-        self.widget.SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
-                                             "in the statusbar. Projection can be "
-                                             "defined in GUI preferences dialog "
-                                             "(tab 'Projection')")))
-                                            
-    def Update(self):
-        self.statusbar.SetStatusText("")
-        epsg = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')
-        if epsg:
-            label = '%s (EPSG: %s)' % (self.defaultLabel, epsg)
-            self.widget.SetLabel(label)
-        else:
-            self.widget.SetLabel(self.defaultLabel)
-        self.Show()
-        
-        # disable long help
-        self.mapFrame.StatusbarEnableLongHelp(False)
-        
-
-class SbMask(SbItem):
-    """!StaticText to show whether mask is activated."""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'mask'
-        
-        self.widget = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY, label = _('MASK'))
-        self.widget.SetForegroundColour(wx.Colour(255, 0, 0))
-        self.widget.Hide()
-        
-    def Update(self):
-        if grass.find_file(name = 'MASK', element = 'cell')['name']:
-            self.Show()
-        else:
-            self.Hide()
-        
-class SbTextItem(SbItem):
-    """!Base class for items without widgets.
-    
-    Only sets statusbar text.
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        
-        self.text = None
-        
-    def Show(self):
-        self.statusbar.SetStatusText(self.GetValue(), self.position)
-        
-    def Hide(self):
-        self.statusbar.SetStatusText("", self.position)
-        
-    def SetValue(self, value):
-        self.text = value
-    
-    def GetValue(self):
-        return self.text
-            
-    def GetWidget(self):
-        return None
-    
-    def Update(self):
-        self._update(longHelp = True)
-
-class SbDisplayGeometry(SbTextItem):
-    """!Show current display resolution."""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbTextItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'displayGeometry'
-        self.label = _("Display geometry")
-        
-    def Show(self):
-        region = self.mapFrame.GetMap().GetCurrentRegion()
-        self.SetValue("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
-                     (region["rows"], region["cols"],
-                      region["nsres"], region["ewres"]))
-        SbTextItem.Show(self)
-
-class SbCoordinates(SbTextItem):
-    """!Show map coordinates when mouse moves.
-    
-    Requires MapWindow.GetLastEN method."""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbTextItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'coordinates'
-        self.label = _("Coordinates")
-        
-    def Show(self):
-        precision = int(UserSettings.Get(group = 'projection', key = 'format',
-                             subkey = 'precision'))
-        format = UserSettings.Get(group = 'projection', key = 'format',
-                                       subkey = 'll')
-        projection = self.mapFrame.GetProperty('projection')
-        try:
-            e, n = self.mapFrame.GetWindow().GetLastEN()
-            self.SetValue(self.ReprojectENFromMap(e, n, projection, precision, format))
-        except SbException, e:
-            self.SetValue(e)
-        except TypeError, e:
-            self.SetValue("")
-        except AttributeError:
-            self.SetValue("") # during initialization MapFrame has no MapWindow
-        SbTextItem.Show(self)
-        
-    def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format):
-        """!Reproject east, north to user defined projection.
-        
-        @param e,n coordinate
-        
-        @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
-        """
-        if useDefinedProjection:
-            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
-            if not settings:
-                raise SbException(_("Projection not defined (check the settings)"))
-            else:
-                # reproject values
-                proj, coord  = utils.ReprojectCoordinates(coord = (e, n),
-                                                          projOut = settings,
-                                                          flags = 'd')
-                if coord:
-                    e, n = coord
-                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
-                        return utils.Deg2DMS(e, n, precision = precision)
-                    else:
-                        return "%.*f; %.*f" % (precision, e, precision, n)
-                else:
-                    raise SbException(_("Error in projection (check the settings)"))
-        else:
-            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
-                return utils.Deg2DMS(e, n, precision = precision)
-            else:
-                return "%.*f; %.*f" % (precision, e, precision, n)
-        
-class SbRegionExtent(SbTextItem):
-    """!Shows current display region"""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbTextItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'displayRegion'
-        self.label = _("Extent")
-        
-    def Show(self):
-        precision = int(UserSettings.Get(group = 'projection', key = 'format',
-                             subkey = 'precision'))
-        format = UserSettings.Get(group = 'projection', key = 'format',
-                                       subkey = 'll')
-        projection = self.mapFrame.GetProperty('projection')        
-        region = self._getRegion()
-        try:
-            regionReprojected = self.ReprojectRegionFromMap(region, projection, precision, format)
-            self.SetValue(regionReprojected)
-        except SbException, e:
-            self.SetValue(e)
-        SbTextItem.Show(self)
-    
-    def _getRegion(self):
-        """!Get current display region"""
-        return self.mapFrame.GetMap().GetCurrentRegion() # display region
-        
-    def _formatRegion(self, w, e, s, n, nsres, ewres, precision = None):
-        """!Format display region string for statusbar
-
-        @param nsres,ewres unused
-        """
-        if precision is not None:
-            return "%.*f - %.*f, %.*f - %.*f" % (precision, w, precision, e,
-                                                 precision, s, precision, n)
-        else:
-            return "%s - %s, %s - %s" % (w, e, s, n)
-         
-           
-    def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format):
-        """!Reproject region values
-        
-        @todo reorganize this method to remove code useful only for derived class SbCompRegionExtent
-        """
-        if useDefinedProjection:
-            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
-            
-            if not settings:
-                raise SbException(_("Projection not defined (check the settings)"))
-            else:
-                projOut = settings
-                proj, coord1 = utils.ReprojectCoordinates(coord = (region["w"], region["s"]),
-                                                          projOut = projOut, flags = 'd')
-                proj, coord2 = utils.ReprojectCoordinates(coord = (region["e"], region["n"]),
-                                                          projOut = projOut, flags = 'd')
-                # useless, used in derived class
-                proj, coord3 = utils.ReprojectCoordinates(coord = (0.0, 0.0),
-                                                          projOut = projOut, flags = 'd')
-                proj, coord4 = utils.ReprojectCoordinates(coord = (region["ewres"], region["nsres"]),
-                                                          projOut = projOut, flags = 'd')
-                if coord1 and coord2:
-                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
-                        w, s = utils.Deg2DMS(coord1[0], coord1[1], string = False,
-                                             precision = precision)
-                        e, n = utils.Deg2DMS(coord2[0], coord2[1], string = False,
-                                             precision = precision)
-                        ewres, nsres = utils.Deg2DMS(abs(coord3[0]) - abs(coord4[0]),
-                                                         abs(coord3[1]) - abs(coord4[1]),
-                                                         string = False, hemisphere = False,
-                                                         precision = precision)
-                        return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
-                    else:
-                        w, s = coord1
-                        e, n = coord2
-                        ewres, nsres = coord3
-                        return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
-                                                  nsres = nsres, precision = precision)
-                else:
-                    raise SbException(_("Error in projection (check the settings)"))
-                
-        else:
-            if self.mapFrame.GetMap().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)
-                ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
-                                             string = False, precision = precision)
-                return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
-            else:
-                w, s = region["w"], region["s"]
-                e, n = region["e"], region["n"]
-                ewres, nsres = region['ewres'], region['nsres']
-                return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
-                                          nsres = nsres, precision = precision)
-                                
-                                
-class SbCompRegionExtent(SbRegionExtent):
-    """!Shows computational region."""
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbRegionExtent.__init__(self, mapframe, statusbar, position)
-        self.name = 'computationalRegion'
-        self.label = _("Comp. region")
-        
-    def _formatRegion(self, w, e, s, n, ewres, nsres, precision = None):
-        """!Format computational region string for statusbar"""
-        if precision is not None:
-            return "%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" % (precision, w, precision, e,
-                                                              precision, s, precision, n,
-                                                              precision, ewres, precision, nsres)
-        else:
-            return "%s - %s, %s - %s (%s, %s)" % (w, e, s, n, ewres, nsres)
-        
-    def _getRegion(self):
-        """!Returns computational region."""
-        return self.mapFrame.GetMap().GetRegion() # computational region
-        
-        
-class SbProgress(SbItem):
-    """!General progress bar to show progress.
-    
-    Underlaying widget is wx.Gauge.
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'progress'
-
-        # on-render gauge
-        self.widget = wx.Gauge(parent = self.statusbar, id = wx.ID_ANY,
-                                      range = 0, style = wx.GA_HORIZONTAL)
-        self.widget.Hide()
-        
-    def GetRange(self):
-        """!Returns progress range."""
-        return self.widget.GetRange()
-    
-    def SetRange(self, range):
-        """!Sets progress range."""
-        self.widget.SetRange(range)
-    
-
-class SbGoToGCP(SbItem):
-    """!SpinCtrl to select GCP to focus on
-    
-    Requires MapFrame.GetSrcWindow, MapFrame.GetTgtWindow, MapFrame.GetListCtrl,
-    MapFrame.GetMapCoordList.
-    """
-    
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'gotoGCP'
-        self.label = _("Go to GCP No.")
-
-        self.widget = wx.SpinCtrl(parent = self.statusbar, id = wx.ID_ANY,
-                                                value = "", min = 0)
-        self.widget.Hide()
-        
-        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoToGCP)
-        self.widget.Bind(wx.EVT_SPINCTRL, self.OnGoToGCP)
-    
-    def OnGoToGCP(self, event):
-        """!Zooms to given GCP."""
-        GCPNo = self.GetValue()
-        mapCoords = self.mapFrame.GetMapCoordList()
-        
-        if GCPNo < 0 or GCPNo > len(mapCoords): # always false, spin checks it
-            gcmd.GMessage(parent=self,
-                          message="%s 1 - %s." % (_("Valid Range:"),
-                          len(mapCoords)))
-            return
-
-        if GCPNo == 0:
-            return
-            
-        listCtrl = self.mapFrame.GetListCtrl()
-        
-        listCtrl.selectedkey = GCPNo
-        listCtrl.selected = listCtrl.FindItemData(-1, GCPNo)
-        listCtrl.render = False
-        listCtrl.SetItemState(listCtrl.selected,
-                          wx.LIST_STATE_SELECTED,
-                          wx.LIST_STATE_SELECTED)
-        listCtrl.render = True
-        
-        srcWin = self.mapFrame.GetSrcWindow()
-        tgtWin = self.mapFrame.GetTgtWindow()
-        
-        # Source MapWindow:
-        begin = (mapCoords[GCPNo][1], mapCoords[GCPNo][2])
-        begin = srcWin.Cell2Pixel(begin)
-        end = begin
-        srcWin.Zoom(begin, end, 0)
-
-        # redraw map
-        srcWin.UpdateMap()
-
-        if self.mapFrame.GetShowTarget():
-            # Target MapWindow:
-            begin = (mapCoords[GCPNo][3], mapCoords[GCPNo][4])
-            begin = tgtWin.Cell2Pixel(begin)
-            end = begin
-            tgtWin.Zoom(begin, end, 0)
-
-            # redraw map
-            tgtWin.UpdateMap()
-
-        self.GetWidget().SetFocus()
-    
-    def Update(self):
-        self.statusbar.SetStatusText("")
-        max = self.mapFrame.GetListCtrl().GetItemCount()
-        if max < 1:
-            max = 1
-        self.widget.SetRange(0, max)
-        self.Show()
-                        
-        # disable long help
-        self.mapFrame.StatusbarEnableLongHelp(False)
-        
-class SbRMSError(SbTextItem):
-    """!Shows RMS error.
-    
-    Requires MapFrame.GetFwdError, MapFrame.GetBkwError.
-    """
-    def __init__(self, mapframe, statusbar, position = 0):
-        SbTextItem.__init__(self, mapframe, statusbar, position)
-        self.name = 'RMSError'
-        self.label = _("RMS error")
-        
-    def Show(self):
-        self.SetValue(_("Forward: %(forw)s, Backward: %(back)s") %
-                                   { 'forw' : self.mapFrame.GetFwdError(),
-                                     'back' : self.mapFrame.GetBkwError() })
-        SbTextItem.Show(self)

Deleted: grass/trunk/gui/wxpython/gui_modules/mapdisp_vdigit.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp_vdigit.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp_vdigit.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1081 +0,0 @@
-"""!
- at package mapdisp_vdigit.py
-
- at brief Map display canvas extended for vector digitizer
-
-See also vdigit.py, wxvdriver.py and wxvdigit.py
-
-Classes:
- - VDigitWindow
-
-(C) 2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import wx
-
-import dbm_dialogs
-
-import gcmd
-from debug          import Debug
-from mapdisp_window import BufferedWindow
-from preferences    import globalSettings as UserSettings
-from utils          import ListOfCatsToRange
-from globalvar      import QUERYLAYER
-from vdigit import VDigitCategoryDialog
-from vdigit import VDigitZBulkDialog
-from vdigit import VDigitDuplicatesDialog
-
-class VDigitWindow(BufferedWindow):
-    """!A Buffered window extended for vector digitizer.
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        BufferedWindow.__init__(self, parent, id, Map, tree, lmgr,
-                                style, **kwargs)
-        
-        self.pdcVector = wx.PseudoDC()
-        self.toolbar   = self.parent.GetToolbar('vdigit')
-        self.digit     = None # wxvdigit.IVDigit
-        
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-        
-    def SetToolbar(self, toolbar):
-        """!Set up related toolbar
-        """
-        self.toolbar = toolbar
-        
-    def _onMotion(self, coord, precision):
-        """!Track mouse motion and update statusbar (see self.Motion)
-
-        @parem coord easting, northing
-        @param precision formatting precision
-        """
-        e, n = coord
-        
-        if self.toolbar.GetAction() != 'addLine' or \
-                self.toolbar.GetAction('type') not in ('line', 'boundary') or \
-                len(self.polycoords) == 0:
-            return False
-        
-        # for linear feature show segment and total length
-        distance_seg = self.Distance(self.polycoords[-1],
-                                     (e, n), screen = False)[0]
-        distance_tot = distance_seg
-        for idx in range(1, len(self.polycoords)):
-            distance_tot += self.Distance(self.polycoords[idx-1],
-                                          self.polycoords[idx],
-                                          screen = False)[0]
-        self.parent.SetStatusText("%.*f, %.*f (seg: %.*f; tot: %.*f)" % \
-                                                (precision, e, precision, n,
-                                                 precision, distance_seg,
-                                                 precision, distance_tot), 0)
-        
-        return True
-    
-    def OnKeyDown(self, event):
-        """!Key pressed"""
-        shift = event.ShiftDown()
-        kc = event.GetKeyCode()
-        
-        event = None
-        if not shift:
-            if kc == ord('P'):
-                event = wx.CommandEvent(winid = self.toolbar.addPoint)
-                tool = self.toolbar.OnAddPoint
-            elif kc == ord('L'):
-                event = wx.CommandEvent(winid = self.toolbar.addLine)
-                tool = self.toolbar.OnAddLine
-        if event:
-            self.toolbar.OnTool(event)
-            tool(event)
-        
-    def _updateMap(self):
-        if not self.toolbar or \
-                not self.toolbar.GetLayer():
-            return
-        
-        # set region
-        self.digit.GetDisplay().UpdateRegion()
-        # re-calculate threshold for digitization tool
-        # self.parent.digit.GetDisplay().GetThreshold()
-        # draw map
-        # self.pdcVector.Clear()
-        self.pdcVector.RemoveAll()
-        
-        item = None
-        if self.tree:
-            try:
-                item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer())
-            except TypeError:
-                pass
-        
-        if not self.tree or \
-                (self.tree and item and \
-                     self.tree.IsItemChecked(item)):
-            self.redrawAll = True
-            self.digit.GetDisplay().DrawMap()
-        
-        # translate tmp objects (pointer position)
-        if self.toolbar.GetAction() == 'moveLine' and \
-                hasattr(self, "moveInfo"):
-            if 'beginDiff' in self.moveInfo:
-                # move line
-                for id in self.moveInfo['id']:
-                    self.pdcTmp.TranslateId(id,
-                                            self.moveInfo['beginDiff'][0],
-                                            self.moveInfo['beginDiff'][1])
-                del self.moveInfo['beginDiff']
-        
-    def OnLeftDownAddLine(self, event):
-        """!Left mouse button pressed - add new feature
-        """
-        try:
-            mapLayer = self.toolbar.GetLayer().GetName()
-        except:
-            return
-        
-        if self.toolbar.GetAction('type') in ['point', 'centroid']:
-            # add new point / centroiud
-            east, north = self.Pixel2Cell(self.mouse['begin'])
-            nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), [(east, north)])
-            if nfeat < 1:
-                return
-            
-            self.UpdateMap(render = False) # redraw map
-            
-            # add new record into atribute table
-            if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'):
-                # select attributes based on layer and category
-                cats = { fids[0] : {
-                        UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
-                            (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
-                        }}
-                
-                posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
-                                                 self.mouse['end'][1] + self.dialogOffset))
-                
-                addRecordDlg = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapLayer,
-                                                                   cats = cats,
-                                                                   pos = posWindow,
-                                                                   action = "add", ignoreError = True)
-                
-                if self.toolbar.GetAction('type') == 'centroid':
-                    for fid in fids:
-                        self._geomAttrb(fid, addRecordDlg, 'area')
-                        self._geomAttrb(fid, addRecordDlg, 'perimeter')
-                
-                if addRecordDlg.IsFound() and \
-                        addRecordDlg.ShowModal() == wx.ID_OK:
-                    sqlfile = tempfile.NamedTemporaryFile(mode = "w")
-                    for sql in addRecordDlg.GetSQLString():
-                        sqlfile.file.write(sql + ";\n")
-                    sqlfile.file.flush()
-                    
-                    gcmd.RunCommand('db.execute',
-                                    parent = self,
-                                    quiet = True, 
-                                    input = sqlfile.name)
-                
-                if addRecordDlg.mapDBInfo:
-                    self._updateATM()
-        
-        elif self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
-            # add new point to the line
-            self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
-            self.DrawLines(pdc = self.pdcTmp)
-        
-    def _geomAttrb(self, fid, dialog, attrb):
-        """!Define geometry attributes
-        """
-        mapLayer = self.toolbar.GetLayer()
-        if self.tree:
-            item = self.tree.FindItemByData('maplayer', mapLayer)
-            vdigit = self.tree.GetPyData(item)[0]['vdigit']
-        else:
-            item = vdigit = None
-        
-        if not vdigit or \
-                'geomAttr' not in vdigit or \
-                attrb not in vdigit['geomAttr']:
-            return
-        
-        val = -1
-        if attrb == 'length':
-            val = self.digit.GetLineLength(fid)
-            type = attrb
-        elif attrb == 'area':
-            val = self.digit.GetAreaSize(fid)
-            type = attrb
-        elif attrb == 'perimeter':
-            val = self.digit.GetAreaPerimeter(fid)
-            type = 'length'
-        
-        if val > 0:
-            layer = int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value'))
-            column = vdigit['geomAttr'][attrb]['column']
-            val = UnitsConvertValue(val, type, vdigit['geomAttr'][attrb]['units'])
-            dialog.SetColumnValue(layer, column, val)
-            dialog.OnReset()
-        
-    def _geomAttrbUpdate(self, fids):
-        """!Update geometry atrributes of currently selected features
-        
-        @param fid list feature id
-        """
-        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
-        vectorName =  mapLayer.GetName()
-        if self.tree:
-            item = self.tree.FindItemByData('maplayer', mapLayer)
-            vdigit = self.tree.GetPyData(item)[0]['vdigit']
-        else:
-            item = vdigit = None
-        
-        if not vdigit or 'geomAttr' not in vdigit:
-            return
-        
-        dbInfo = gselect.VectorDBInfo(vectorName)
-        sqlfile = tempfile.NamedTemporaryFile(mode = "w")
-        for fid in fids:
-            for layer, cats in self.digit.GetLineCats(fid).iteritems():
-                table = dbInfo.GetTable(layer)
-                for attrb, item in vdigit['geomAttr'].iteritems():
-                    val = -1
-                    if attrb == 'length':
-                        val = self.digit.GetLineLength(fid)
-                        type = attrb
-                    elif attrb == 'area':
-                        val = self.digit.GetAreaSize(fid)
-                        type = attrb
-                    elif attrb == 'perimeter':
-                        val = self.digit.GetAreaPerimeter(fid)
-                        type = 'length'
-                    
-                    if val < 0:
-                        continue
-                    val = UnitsConvertValue(val, type, item['units'])
-                    
-                    for cat in cats:
-                        sqlfile.write('UPDATE %s SET %s = %f WHERE %s = %d;\n' % \
-                                          (table, item['column'], val,
-                                           dbInfo.GetKeyColumn(layer), cat))
-            
-            sqlfile.file.flush()
-            gcmd.RunCommand('db.execute',
-                            parent = True,
-                            quiet = True,
-                            input = sqlfile.name)
-            
-    def _updateATM(self):
-        """!Update open Attribute Table Manager
-        
-        @todo: use AddDataRow() instead
-        """
-        # update ATM
-        digitVector = self.toolbar.GetLayer().GetName()
-                            
-        for atm in self.lmgr.dialogs['atm']:
-            atmVector = atm.GetVectorName()
-            if atmVector == digitVector:
-                layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
-                # TODO: use AddDataRow instead
-                atm.LoadData(layer)
-        
-    def OnLeftDownEditLine(self, event):
-        """!Left mouse button pressed - edit linear feature - add new
-        vertex.
-        """
-        self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
-        self.moveInfo['id'].append(wx.NewId())
-        self.DrawLines(pdc = self.pdcTmp)
-        
-    def OnLeftDownMoveLine(self, event):
-        """!Left mouse button pressed - vector digitizer move
-        feature/vertex, edit linear feature
-        """
-        self.moveInfo = dict()
-        # geographic coordinates of initial position (left-down)
-        self.moveInfo['begin'] = None
-        # list of ids to modify    
-        self.moveInfo['id'] = list()
-        
-        # set pen
-        if self.toolbar.GetAction() in ["moveVertex", "editLine"]:
-            pcolor = UserSettings.Get(group = 'vdigit', key = "symbol",
-                                      subkey = ["highlight", "color"])
-            self.pen = self.polypen = wx.Pen(colour = pcolor,
-                                             width = 2, style = wx.SHORT_DASH)
-            self.pdcTmp.SetPen(self.polypen)
-        
-    def OnLeftDownDisplayCA(self, event):
-        """!Left mouse button pressed - vector digitizer display categories
-        or attributes action
-        """
-        try:
-            mapLayer = self.toolbar.GetLayer().GetName()
-        except:
-            return
-        
-        coords = self.Pixel2Cell(self.mouse['begin'])
-        
-        # unselect
-        self.digit.GetDisplay().SetSelected([])
-        
-        # select feature by point
-        cats = {}
-        self.digit.GetDisplay().SelectLineByPoint(coords) 
-        
-        if not self.digit.GetDisplay().GetSelected():
-            for key in ('attributes', 'category'):
-                if self.parent.dialogs[key] and \
-                        self.parent.dialogs[key].IsShown():
-                    self.parent.dialogs[key].Hide()
-            self.UpdateMap(render = False, renderVector = True)
-            return
-        
-        if UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
-                            subkey = 'enabled'):
-            lines = self.digit.GetDisplay().GetSelected()
-        else:
-            lines = (self.digit.GetDisplay().GetSelected()[0],) # only first found
-                        
-        for line in lines:
-            cats[line] = self.digit.GetLineCats(line)
-        
-        posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
-                                         self.mouse['end'][1] + self.dialogOffset))
-        
-        if self.toolbar.GetAction() == "displayAttrs":
-            # select attributes based on coordinates (all layers)
-            if self.parent.dialogs['attributes'] is None:
-                self.parent.dialogs['attributes'] = \
-                    dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapLayer,
-                                                        cats = cats,
-                                                        action = "update")
-            else:
-                # upgrade dialog
-                self.parent.dialogs['attributes'].UpdateDialog(cats = cats)
-           
-            if self.parent.dialogs['attributes'] and \
-                    self.parent.dialogs['attributes'].mapDBInfo:
-                if len(cats.keys()) > 0:
-                    # highlight feature & re-draw map
-                    if not self.parent.dialogs['attributes'].IsShown():
-                        self.parent.dialogs['attributes'].Show()
-                else:
-                    if self.parent.dialogs['attributes'] and \
-                            self.parent.dialogs['attributes'].IsShown():
-                        self.parent.dialogs['attributes'].Hide()
-        
-        else: # displayCats
-            if self.parent.dialogs['category'] is None:
-                # open new dialog
-                dlg = VDigitCategoryDialog(parent = self,
-                                           vectorName = mapLayer,
-                                           cats = cats,
-                                           pos = posWindow,
-                                           title = _("Update categories"))
-                self.parent.dialogs['category'] = dlg
-            else:
-                # update currently open dialog
-                self.parent.dialogs['category'].UpdateDialog(cats = cats)
-                
-            if self.parent.dialogs['category']:
-                if len(cats.keys()) > 0:
-                    # highlight feature & re-draw map
-                    if not self.parent.dialogs['category'].IsShown():
-                        self.parent.dialogs['category'].Show()
-                else:
-                    if self.parent.dialogs['category'].IsShown():
-                        self.parent.dialogs['category'].Hide()
-        
-        self.UpdateMap(render = False, renderVector = True)
-        
-    def OnLeftDownCopyCA(self, event):
-        """!Left mouse button pressed - vector digitizer copy
-        categories or attributes action
-        """
-        if not hasattr(self, "copyCatsList"):
-            self.copyCatsList = []
-        else:
-            self.copyCatsIds = []
-            self.mouse['box'] = 'box'
-        
-    def OnLeftDownCopyLine(self, event):
-        """!Left mouse button pressed - vector digitizer copy lines
-        action
-        """
-        if not hasattr(self, "copyIds"):
-            self.copyIds = []
-            self.layerTmp = None
-        
-    def OnLeftDownBulkLine(self, event):
-        """!Left mouse button pressed - vector digitizer label 3D
-        vector lines
-        """
-        if len(self.polycoords) > 1: # start new line
-            self.polycoords = []
-            self.ClearLines(pdc = self.pdcTmp)
-        self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
-        if len(self.polycoords) == 1:
-            begin = self.Pixel2Cell(self.polycoords[-1])
-            end   = self.Pixel2Cell(self.mouse['end'])
-        else:
-            end   = self.Pixel2Cell(self.polycoords[-1])
-            begin = self.Pixel2Cell(self.mouse['begin'])
-            
-            self.DrawLines(self.pdcTmp, polycoords = (begin, end))
-        
-    def OnLeftDownUndo(self, event):
-        """!Left mouse button pressed with control key - vector
-        digitizer undo functionality
-        """
-        if self.mouse["use"] != "pointer" or not self.toolbar:
-            return
-        
-        action = self.toolbar.GetAction()
-        if (action == "addLine" and \
-                self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or \
-                action == "editLine":
-            # add line or boundary -> remove last point from the line
-            try:
-                removed = self.polycoords.pop()
-                Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
-                              [removed,])
-                # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
-            except:
-                pass
-            
-        if action == "editLine":
-            # remove last vertex & line
-            if len(self.moveInfo['id']) > 1:
-                self.moveInfo['id'].pop()
-                
-            self.UpdateMap(render = False, renderVector = False)
-            
-        elif action in ["deleteLine", "moveLine", "splitLine",
-                        "addVertex", "removeVertex", "moveVertex",
-                        "copyCats", "flipLine", "mergeLine",
-                        "snapLine", "connectLine", "copyLine",
-                        "queryLine", "breakLine", "typeConv"]:
-            # varios tools -> unselected selected features
-            self.digit.GetDisplay().SetSelected([])
-            if action in ["moveLine", "moveVertex", "editLine"] and \
-                    hasattr(self, "moveInfo"):
-                del self.moveInfo
-                
-            elif action == "copyCats":
-                try:
-                    del self.copyCatsList
-                    del self.copyCatsIds
-                except AttributeError:
-                    pass
-                
-            elif action == "copyLine":
-                del self.copyIds
-                if self.layerTmp:
-                    self.Map.DeleteLayer(self.layerTmp)
-                    self.UpdateMap(render = True, renderVector = False)
-                del self.layerTmp
-
-            self.polycoords = []
-            self.UpdateMap(render = False) # render vector
-        
-        elif action == "zbulkLine":
-            # reset polyline
-            self.polycoords = []
-            self.digit.GetDisplay().SetSelected([])
-            self.UpdateMap(render = False)
-        
-        self.redrawAll = True
-        self.UpdateMap(render = False, renderVector = False)
-
-    def _onLeftDown(self, event):
-        """!Left mouse button donw - vector digitizer various actions
-        """
-        try:
-            mapLayer = self.toolbar.GetLayer().GetName()
-        except:
-            gcmd.GMessage(parent = self,
-                          message = _("No vector map selected for editing."))
-            event.Skip()
-            return
-        
-        action = self.toolbar.GetAction()
-        if not action:
-            return
-        
-        if action not in ("moveVertex",
-                          "addVertex",
-                          "removeVertex",
-                          "editLine"):
-            # set pen
-            self.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
-            self.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID)
-            
-        if action in ("addVertex",
-                      "removeVertex",
-                      "splitLines"):
-            # unselect
-            self.digit.GetDisplay().SetSelected([])
-        
-        if action == "addLine":
-            self.OnLeftDownAddLine(event)
-        
-        elif action == "editLine" and \
-                hasattr(self, "moveInfo"):
-            self.OnLeftDownEditLine(event)
-
-        elif action in ("moveLine", "moveVertex", "editLine") and \
-                not hasattr(self, "moveInfo"):
-            self.OnLeftDownMoveLine(event)
-        
-        elif action in ("displayAttrs"
-                        "displayCats"):
-            self.OnLeftDownDisplayCA(event)
-            
-        elif action in ("copyCats",
-                        "copyAttrs"):
-            self.OnLeftDownCopyCA(event)
-            
-        elif action == "copyLine":
-            self.OnLeftDownCopyLine(event)
-            
-        elif action == "zbulkLine":
-            self.OnLeftDownBulkLine(event)
-        
-    def OnLeftUpVarious(self, event):
-        """!Left mouse button released - vector digitizer various
-        actions
-        """
-        pos1 = self.Pixel2Cell(self.mouse['begin'])
-        pos2 = self.Pixel2Cell(self.mouse['end'])
-        
-        nselected = 0
-        action = self.toolbar.GetAction()
-        # -> delete line || move line || move vertex
-        if action in ("moveVertex",
-                      "editLine"):
-            if len(self.digit.GetDisplay().GetSelected()) == 0:
-                nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
-                
-                if action == "editLine":
-                    try:
-                        selVertex = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
-                    except IndexError:
-                        selVertex = None
-                        
-                    if selVertex:
-                        # self.UpdateMap(render=False)
-                        ids = self.digit.GetDisplay().GetSelected(grassId = False)
-                        # move this line to tmp layer
-                        self.polycoords = []
-                        for id in ids:
-                            if id % 2: # register only vertices
-                                e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
-                                self.polycoords.append((e, n))
-                        self.digit.GetDisplay().DrawSelected(False) 
-                                
-                        if selVertex < ids[-1] / 2:
-                            # choose first or last node of line
-                            self.moveInfo['id'].reverse()
-                            self.polycoords.reverse()
-                    else:
-                        # unselect
-                        self.digit.GetDisplay().SetSelected([])
-                        del self.moveInfo
-                
-                    self.UpdateMap(render = False)
-            
-        elif action in ("copyCats",
-                        "copyAttrs"):
-            if not hasattr(self, "copyCatsIds"):
-                # 'from' -> select by point
-                nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
-                if nselected:
-                    self.copyCatsList = self.digit.GetDisplay().GetSelected()
-            else:
-                # -> 'to' -> select by bbox
-                self.digit.GetDisplay().SetSelected([])
-                # return number of selected features (by box/point)
-                nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
-                if nselected == 0:
-                    if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
-                        nselected = 1
-                        
-                if nselected > 0:
-                    self.copyCatsIds = self.digit.GetDisplay().GetSelected()
-        
-        elif action == "queryLine":
-            selected = self.digit.SelectLinesByQuery(bbox = (pos1, pos2))
-            nselected = len(selected)
-            if nselected > 0:
-                self.digit.GetDisplay().SetSelected(selected)
-        
-        else:
-            # -> moveLine || deleteLine, etc. (select by point/box)
-            if action == 'moveLine' and \
-                    len(self.digit.GetDisplay().GetSelected()) > 0:
-                nselected = 0
-            else:
-                if action == 'moveLine':
-                    drawSeg = True
-                else:
-                    drawSeg = False
-                
-                nselected = self.digit.GetDisplay().SelectLinesByBox(bbox = (pos1, pos2),
-                                                                     drawSeg = drawSeg)
-                if nselected == 0:
-                    if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
-                        nselected = 1
-        
-        if nselected > 0:
-            if action in ("moveLine", "moveVertex") and \
-                    hasattr(self, "moveInfo"):
-                # get pseudoDC id of objects which should be redrawn
-                if action == "moveLine":
-                    # -> move line
-                    self.moveInfo['id'] = self.digit.GetDisplay().GetSelected(grassId = False)
-                else: # moveVertex
-                    self.moveInfo['id'] = self.digit.GetDisplay().GetSelectedVertex(pos1)
-                    if len(self.moveInfo['id']) == 0: # no vertex found
-                        self.digit.GetDisplay().SetSelected([])
-            
-            #
-            # check for duplicates
-            #
-            if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'):
-                dupl = self.digit.GetDisplay().GetDuplicates()
-                self.UpdateMap(render = False)
-                    
-                if dupl:
-                    posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
-                                                     self.mouse['end'][1] + self.dialogOffset))
-                    
-                    dlg = VDigitDuplicatesDialog(parent = self, data = dupl, pos = posWindow)
-                    
-                    if dlg.ShowModal() == wx.ID_OK:
-                        self.digit.GetDisplay().UnSelect(dlg.GetUnSelected())
-                        # update selected
-                        self.UpdateMap(render = False)
-                
-            if action != "editLine":
-                # -> move line || move vertex
-                self.UpdateMap(render = False)
-        
-        else: # no vector object found
-            if not (action in ("moveLine",
-                                                 "moveVertex") and \
-                        hasattr(self, "moveInfo") and \
-                        len(self.moveInfo['id']) > 0):
-                # avoid left-click when features are already selected
-                self.UpdateMap(render = False, renderVector = False)
-        
-    def OnLeftUpModifyLine(self, event):
-        """!Left mouse button released - vector digitizer split line,
-        add/remove vertex action
-        """
-        pos1 = self.Pixel2Cell(self.mouse['begin'])
-        
-        pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
-        if not pointOnLine:
-            return
-        
-        if self.toolbar.GetAction() in ["splitLine", "addVertex"]:
-            self.UpdateMap(render = False) # highlight object
-            self.DrawCross(pdc = self.pdcTmp, coords = self.Cell2Pixel((pointOnLine[0], pointOnLine[1])),
-                           size = 5)
-        else: # removeVertex
-            # get only id of vertex
-            try:
-                id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
-            except IndexError:
-                id = None
-            
-            if id:
-                x, y = self.pdcVector.GetIdBounds(id)[0:2]
-                self.pdcVector.RemoveId(id)
-                self.UpdateMap(render = False) # highlight object
-                self.DrawCross(pdc = self.pdcTmp, coords = (x, y),
-                               size = 5)
-            else:
-                # unselect
-                self.digit.GetDisplay().SetSelected([])
-                self.UpdateMap(render = False)
-        
-    def OnLeftUpCopyLine(self, event):
-        """!Left mouse button released - vector digitizer copy feature
-        action
-        """
-        pos1 = self.Pixel2Cell(self.mouse['begin'])
-        pos2 = self.Pixel2Cell(self.mouse['end'])
-        
-        if UserSettings.Get(group = 'vdigit', key = 'bgmap',
-                            subkey = 'value', internal = True) == '':
-            # no background map -> copy from current vector map layer
-            nselected = self.bdigit.GetDisplay().SelectLinesByBox((pos1, pos2))
-            
-            if nselected > 0:
-                # highlight selected features
-                self.UpdateMap(render = False)
-            else:
-                self.UpdateMap(render = False, renderVector = False)
-        else:
-            # copy features from background map
-            self.copyIds = self.digit.SelectLinesFromBackgroundMap(bbox = (pos1, pos2))
-            if len(self.copyIds) > 0:
-                color = UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                         subkey = ['highlight', 'color'])
-                colorStr = str(color[0]) + ":" + str(color[1]) + ":" + str(color[2])
-                dVectTmp = ['d.vect',
-                            'map=%s' % UserSettings.Get(group = 'vdigit', key = 'bgmap',
-                                                        subkey = 'value', internal = True),
-                            'cats=%s' % ListOfCatsToRange(self.copyIds),
-                            '-i',
-                            'color=%s' % colorStr,
-                            'fcolor=%s' % colorStr,
-                            'type=point,line,boundary,centroid',
-                            'width=2']
-                
-                if not self.layerTmp:
-                    self.layerTmp = self.Map.AddLayer(type = 'vector',
-                                                      name = QUERYLAYER,
-                                                      command = dVectTmp)
-                else:
-                    self.layerTmp.SetCmd(dVectTmp)
-            else:
-                if self.layerTmp:
-                    self.Map.DeleteLayer(self.layerTmp)
-                    self.layerTmp = None
-            
-            self.UpdateMap(render = True, renderVector = True)
-            
-    def OnLeftUpBulkLine(self, event):
-        """!Left mouse button released - vector digitizer z-bulk line
-        action
-        """
-        # select lines to be labeled
-        pos1 = self.polycoords[0]
-        pos2 = self.polycoords[1]
-        nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
-        
-        if nselected > 0:
-            # highlight selected features
-            self.UpdateMap(render = False)
-            self.DrawLines(pdc = self.pdcTmp) # redraw temp line
-        else:
-            self.UpdateMap(render = False, renderVector = False)
-            
-    def OnLeftUpConnectLine(self, event):
-        """!Left mouse button released - vector digitizer connect line
-        action
-        """
-        if len(self.digit.GetDisplay().GetSelected()) > 0:
-            self.UpdateMap(render = False)
-        
-    def _onLeftUp(self, event):
-        """!Left mouse button released"""
-        if hasattr(self, "moveInfo"):
-            if len(self.digit.GetDisplay().GetSelected()) == 0:
-                self.moveInfo['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down
-            
-            # eliminate initial mouse moving efect
-            self.mouse['begin'] = self.mouse['end'] 
-        
-        action = self.toolbar.GetAction()
-        if action in ("deleteLine",
-                      "moveLine",
-                      "moveVertex",
-                      "copyCats",
-                      "copyAttrs",
-                      "editLine",
-                      "flipLine",
-                      "mergeLine",
-                      "snapLine",
-                      "queryLine",
-                      "breakLine",
-                      "typeConv",
-                      "connectLine"):
-            self.OnLeftUpVarious(event)
-        
-        elif action in ("splitLine",
-                        "addVertex",
-                        "removeVertex"):
-            self.OnLeftUpModifyLine(event)
-        
-        elif action == "copyLine":
-            self.OnLeftUpCopyLine(event)
-            
-        elif action == "zbulkLine" and \
-                len(self.polycoords) == 2:
-            self.OnLeftUpBulkLine(event)
-        
-        elif action == "connectLine":
-            self.OnLeftUpConnectLine(event)
-        
-        if len(self.digit.GetDisplay().GetSelected()) > 0:
-            self.redrawAll = None
-        
-    def _onRightDown(self, event):
-        # digitization tool (confirm action)
-        action = self.toolbar.GetAction()
-        if action in ("moveLine", "moveVertex") and \
-                hasattr(self, "moveInfo"):
-            pFrom = self.moveInfo['begin']
-            pTo = self.Pixel2Cell(event.GetPositionTuple())
-            
-            move = (pTo[0] - pFrom[0],
-                    pTo[1] - pFrom[1])
-            
-            if action == "moveLine":
-                # move line
-                if self.digit.MoveSelectedLines(move) < 0:
-                    return
-            elif action == "moveVertex":
-                # move vertex
-                fid = self.digit.MoveSelectedVertex(pFrom, move)
-                if fid < 0:
-                    return
-                
-                self._geomAttrbUpdate([fid,])
-            
-            del self.moveInfo
-        
-    def _onRightUp(self, event):
-        """!Right mouse button released (confirm action)
-        """
-        action = self.toolbar.GetAction()
-        if action == "addLine" and \
-                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
-            # -> add new line / boundary
-            try:
-                mapName = self.toolbar.GetLayer().GetName()
-            except:
-                mapName = None
-                gcmd.GError(parent = self,
-                            message = _("No vector map selected for editing."))
-                    
-            if mapName:
-                if self.toolbar.GetAction('type') == 'line':
-                    line = True
-                else:
-                    line = False
-                    
-                if len(self.polycoords) < 2: # ignore 'one-point' lines
-                    return
-                    
-                nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), self.polycoords)
-                if nfeat < 0:
-                    return
-                    
-                position = self.Cell2Pixel(self.polycoords[-1])
-                self.polycoords = []
-                self.UpdateMap(render = False)
-                self.redrawAll = True
-                self.Refresh()
-                
-                # add new record into atribute table
-                if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled') and \
-                        (line is True or \
-                             (not line and nfeat > 0)):
-                    posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
-                                                     position[1] + self.dialogOffset))
-                        
-                    # select attributes based on layer and category
-                    cats = { fids[0] : {
-                            UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
-                                (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
-                            }}
-                    
-                    addRecordDlg = dbm_dialogs.DisplayAttributesDialog(parent = self, map = mapName,
-                                                                       cats = cats,
-                                                                       pos = posWindow,
-                                                                       action = "add", ignoreError = True)
-                    
-                    for fid in fids:
-                        self._geomAttrb(fid, addRecordDlg, 'length')
-                        # auto-placing centroid
-                        self._geomAttrb(fid, addRecordDlg, 'area')
-                        self._geomAttrb(fid, addRecordDlg, 'perimeter')
-
-                    
-                    if addRecordDlg.mapDBInfo and \
-                            addRecordDlg.ShowModal() == wx.ID_OK:
-                        sqlfile = tempfile.NamedTemporaryFile(mode = "w")
-                        for sql in addRecordDlg.GetSQLString():
-                            sqlfile.file.write(sql + ";\n")
-                        sqlfile.file.flush()
-                        gcmd.RunCommand('db.execute',
-                                        parent = True,
-                                        quiet = True,
-                                        input = sqlfile.name)
-                        
-                    if addRecordDlg.mapDBInfo:
-                        self._updateATM()
-            
-        elif action == "deleteLine":
-            # -> delete selected vector features
-            if self.digit.DeleteSelectedLines() < 0:
-                return
-            self._updateATM()
-        elif action == "splitLine":
-            # split line
-            if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
-                return
-        elif action == "addVertex":
-            # add vertex
-            fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin']))
-            if fid < 0:
-                return
-        elif action == "removeVertex":
-            # remove vertex
-            fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin']))
-            if fid < 0:
-                return
-            self._geomAttrbUpdate([fid,])
-        elif action in ("copyCats", "copyAttrs"):
-            if action == 'copyCats':
-                if self.digit.CopyCats(self.copyCatsList,
-                                       self.copyCatsIds, copyAttrb = False) < 0:
-                    return
-            else:
-                if self.digit.CopyCats(self.copyCatsList,
-                                       self.copyCatsIds, copyAttrb = True) < 0:
-                    return
-                
-            del self.copyCatsList
-            del self.copyCatsIds
-            
-            self._updateATM()
-                
-        elif action == "editLine" and \
-                hasattr(self, "moveInfo"):
-            line = self.digit.GetDisplay().GetSelected()[0]
-            if self.digit.EditLine(line, self.polycoords) < 0:
-                return
-                
-            del self.moveInfo
-                
-        elif action == "flipLine":
-            if self.digit.FlipLine() < 0:
-                return
-        elif action == "mergeLine":
-            if self.digit.MergeLine() < 0:
-                return
-        elif action == "breakLine":
-            if self.digit.BreakLine() < 0:
-                return
-        elif action == "snapLine":
-            if self.digit.SnapLine() < 0:
-                return
-        elif action == "connectLine":
-            if len(self.digit.GetDisplay().GetSelected()) > 1:
-                if self.digit.ConnectLine() < 0:
-                    return
-        elif action == "copyLine":
-            if self.digit.CopyLine(self.copyIds) < 0:
-                return
-            del self.copyIds
-            if self.layerTmp:
-                self.Map.DeleteLayer(self.layerTmp)
-                self.UpdateMap(render = True, renderVector = False)
-            del self.layerTmp
-        
-        elif action == "zbulkLine" and len(self.polycoords) == 2:
-            pos1 = self.polycoords[0]
-            pos2 = self.polycoords[1]
-            
-            selected = self.digit.GetDisplay().GetSelected()
-            dlg = VDigitZBulkDialog(parent = self, title = _("Z bulk-labeling dialog"),
-                                    nselected = len(selected))
-            if dlg.ShowModal() == wx.ID_OK:
-                if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
-                                         dlg.step.GetValue()) < 0:
-                    return
-            self.UpdateMap(render = False)
-        elif action == "typeConv":
-            # -> feature type conversion
-            # - point <-> centroid
-            # - line <-> boundary
-            if self.digit.TypeConvForSelectedLines() < 0:
-                return
-
-        if action != "addLine":
-            # unselect and re-render
-            self.digit.GetDisplay().SetSelected([])
-            self.polycoords = []
-            self.UpdateMap(render = False)
-        
-    def _onMouseMoving(self, event):
-        self.mouse['end'] = event.GetPositionTuple()[:]
-        
-        Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
-                       (self.mouse['end'][0], self.mouse['end'][1]))
-
-        action = self.toolbar.GetAction()
-        if action == "addLine" and \
-                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
-            if len(self.polycoords) > 0:
-                self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1]))
-        
-        elif action in ["moveLine", "moveVertex", "editLine"] \
-                and hasattr(self, "moveInfo"):
-            dx = self.mouse['end'][0] - self.mouse['begin'][0]
-            dy = self.mouse['end'][1] - self.mouse['begin'][1]
-        
-            # draw lines on new position
-            if action == "moveLine" and \
-                    len(self.moveInfo['id']) > 0:
-                # move line
-                for id in self.moveInfo['id']:
-                    self.pdcTmp.TranslateId(id, dx, dy)
-            elif action in ["moveVertex", "editLine"]:
-                # move vertex ->
-                # (vertex, left vertex, left line,
-                # right vertex, right line)
-                
-                # do not draw static lines
-                if action == "moveVertex" and \
-                        len(self.moveInfo['id']) > 0:
-                    self.polycoords = []
-                    self.pdcTmp.RemoveId(self.moveInfo['id'][0])
-                    if self.moveInfo['id'][1] > 0: # previous vertex
-                        x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][1])[0:2])
-                        self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1)
-                        self.polycoords.append((x, y))
-                    self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
-
-                    if self.moveInfo['id'][2] > 0: # next vertex
-                        x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][2])[0:2])
-                        self.pdcTmp.RemoveId(self.moveInfo['id'][2]-1)
-                        self.polycoords.append((x, y))
-                    
-                    self.ClearLines(pdc = self.pdcTmp)
-                    self.DrawLines(pdc = self.pdcTmp)
-                        
-                if action == "editLine":
-                    self.MouseDraw(pdc = self.pdcTmp,
-                                   begin = self.Cell2Pixel(self.polycoords[-1]))
-                
-            self.Refresh() # TODO: use RefreshRect()
-            self.mouse['begin'] = self.mouse['end']
-            
-        elif action == "zbulkLine":
-            if len(self.polycoords) == 1:
-                # draw mouse moving
-                self.MouseDraw(self.pdcTmp)
-                
-    def _zoom(self, event):
-        tmp1 = self.mouse['end']
-        tmp2 = self.Cell2Pixel(self.moveInfo['begin'])
-        dx = tmp1[0] - tmp2[0]
-        dy = tmp1[1] - tmp2[1]
-        self.moveInfo['beginDiff'] = (dx, dy)
-        for id in self.moveInfo['id']:
-            self.pdcTmp.RemoveId(id)
-        

Deleted: grass/trunk/gui/wxpython/gui_modules/mapdisp_window.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp_window.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp_window.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1918 +0,0 @@
-"""!
- at package mapdisp_window.py
-
- at brief Map display canvas - buffered window.
-
-Classes:
- - MapWindow
- - BufferedWindow
-
-(C) 2006-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
- at author Michael Barton
- at author Jachym Cepicky
-"""
-
-import os
-import time
-import math
-import sys
-import tempfile
-import traceback
-
-import wx
-
-import grass.script as grass
-
-import dbm
-import gdialogs
-import gcmd
-import utils
-import globalvar
-import gselect
-from debug import Debug
-from preferences import globalSettings as UserSettings
-from units import ConvertValue as UnitsConvertValue
-
-try:
-    import grass.lib.gis as gislib
-    haveCtypes = True
-except ImportError:
-    haveCtypes = False
-
-class MapWindow(object):
-    """!Abstract map display window class
-    
-    Superclass for BufferedWindow class (2D display mode), and GLWindow
-    (3D display mode).
-    
-    Subclasses have to define
-     - _bindMouseEvents method which binds MouseEvent handlers
-     - Pixel2Cell
-     - Cell2Pixel (if it is possible)
-    
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None, **kwargs):
-        self.parent = parent # MapFrame
-        self.Map    = Map
-        self.tree   = tree
-        self.lmgr   = lmgr
-        
-        # mouse attributes -- position on the screen, begin and end of
-        # dragging, and type of drawing
-        self.mouse = {
-            'begin': [0, 0], # screen coordinates
-            'end'  : [0, 0],
-            'use'  : "pointer",
-            'box'  : "point"
-            }
-        # last east, north coordinates, changes on mouse motion
-        self.lastEN = None 
-        
-        # stores overridden cursor
-        self._overriddenCursor = None
-
-    def RegisterMouseEventHandler(self, event, handler, cursor = None):
-        """!Binds event handler
-        
-        Call event.Skip() in handler to allow default processing in MapWindow.
-        
-        \code
-        # your class methods
-        def OnButton(self, event):
-            # current map display's map window
-            # expects LayerManager to be the parent
-            self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
-            if self.mapwin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
-                                                     wx.StockCursor(wx.CURSOR_CROSS)):
-                self.parent.GetLayerTree().GetMapDisplay().Raise()
-            else:
-                # handle that you cannot get coordinates
-        
-        def OnMouseAction(self, event):
-            # get real world coordinates of mouse click
-            coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
-            self.text.SetLabel('Coor: ' + str(coor))
-            self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN)
-            event.Skip()
-        \endcode
-        
-        @param event one of mouse events
-        @param handler function to handle event
-        @param cursor cursor which temporary overrides current cursor
-        
-        @return True if successful
-        @return False if event cannot be bind
-        """
-        
-        # if it is a VDigitWindow it cannot be used
-        # hasattr is ugly
-        if hasattr(self, "digit"):
-            return False
-        
-        self.Bind(event, handler)
-        self.mouse['useBeforeGenericEvent'] = self.mouse['use']
-        self.mouse['use'] = 'genericEvent'
-        
-        if cursor:
-            self._overriddenCursor = self.GetCursor()
-            self.SetCursor(cursor)
-        
-        return True
-
-
-    def UnregisterMouseEventHandler(self, event):
-        """!Unbinds event handler a restores previous state
-        
-        You should unbind to restore normal MapWindow behaviour.
-        Note that this operation will unbind any other external (non-MapWindow) handlers.
-        
-        @param event event to unbind
-        
-        @return True if successful
-        @return False if event cannot be unbind
-        """
-        if hasattr(self, "digit"):
-            return False
-        
-        # it is not yet possible in wxPython to unbind exact event
-        ret = self.Unbind(event)
-        
-        # restore bind state
-        self._bindMouseEvents()
-        
-        # restore mouse use (previous state)
-        self.mouse['use'] = self.mouse['useBeforeGenericEvent']
-        
-        # restore overridden cursor
-        if self._overriddenCursor:
-            self.SetCursor(self._overriddenCursor)
-        
-        return ret
-    
-    def Pixel2Cell(self, (x, y)):
-        raise NotImplementedError()
-    
-    def Cell2Pixel(self, (east, north)):
-        raise NotImplementedError()
-
-    def OnMotion(self, event):
-        """!Tracks mouse motion and update statusbar
-        
-        @see GetLastEN
-        """
-        try:
-            self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
-        except (ValueError):
-            self.lastEN = None
-        # FIXME: special case for vdigit and access to statusbarManager
-        if self.parent.statusbarManager.GetMode() == 0: # Coordinates            
-            updated = False
-            if hasattr(self, "digit"):
-                precision = int(UserSettings.Get(group = 'projection', key = 'format',
-                                             subkey = 'precision'))
-                updated = self._onMotion(self.lastEN, precision)
-
-            if not updated:
-                self.parent.CoordinatesChanged()
-        
-        event.Skip()
-
-    def GetLastEN(self):
-        """!Returns last coordinates of mouse cursor.
-        
-        @see OnMotion
-        """
-        return self.lastEN
-    
-    def GetLayerByName(self, name, mapType, dataType = 'layer'):
-        """!Get layer from layer tree by nam
-        
-        @param name layer name
-        @param type 'item' / 'layer' / 'nviz'
-
-        @return layer / map layer properties / nviz properties
-        @return None
-        """
-        if not self.tree:
-            return None
-        
-        try:
-            mapLayer = self.Map.GetListOfLayers(l_type = mapType, l_name = name)[0]
-        except IndexError:
-            return None
-        
-        if dataType == 'layer':
-            return mapLayer
-        item = self.tree.FindItemByData('maplayer', mapLayer)
-        if not item:
-            return None
-        if dataType == 'nviz':
-            return self.tree.GetPyData(item)[0]['nviz']
-        
-        return item
-        
-    def GetSelectedLayer(self, type = 'layer', multi = False):
-        """!Get selected layer from layer tree
-        
-        @param type 'item' / 'layer' / 'nviz'
-        @param multi return first selected layer or all
-        
-        @return layer / map layer properties / nviz properties
-        @return None / [] on failure
-        """
-        ret = []
-        if not self.tree or \
-                not self.tree.GetSelection():
-            if multi:
-                return []
-            else:
-                return None
-        
-        if multi and \
-                type == 'item':
-            return self.tree.GetSelections()
-        
-        for item in self.tree.GetSelections():
-            if not item.IsChecked():
-                if multi:
-                    continue
-                else:
-                    return None
-
-            if type == 'item': # -> multi = False
-                return item
-        
-            try:
-                if type == 'nviz':
-                    layer = self.tree.GetPyData(item)[0]['nviz']
-                else:
-                    layer = self.tree.GetPyData(item)[0]['maplayer']
-            except:
-                layer = None
-
-            if multi:
-                ret.append(layer)
-            else:
-                return layer
-            
-        return ret
-    
-class BufferedWindow(MapWindow, wx.Window):
-    """!A Buffered window class (2D view mode)
-
-    Superclass for VDigitWindow (vector digitizer).
-    
-    When the drawing needs to change, you app needs to call the
-    UpdateMap() method. Since the drawing is stored in a bitmap, you
-    can also save the drawing to file by calling the
-    SaveToFile() method.
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
-        MapWindow.__init__(self, parent, id, Map, tree, lmgr, **kwargs)
-        wx.Window.__init__(self, parent, id, style = style, **kwargs)
-        
-        # flags
-        self.resize = False # indicates whether or not a resize event has taken place
-        self.dragimg = None # initialize variable for map panning
-        
-        # variables for drawing on DC
-        self.pen = None      # pen for drawing zoom boxes, etc.
-        self.polypen = None  # pen for drawing polylines (measurements, profiles, etc)
-        # List of wx.Point tuples defining a polyline (geographical coordinates)
-        self.polycoords = []
-        # ID of rubber band line
-        self.lineid = None
-        # ID of poly line resulting from cumulative rubber band lines (e.g. measurement)
-        self.plineid = None
-        
-        # event bindings
-        self.Bind(wx.EVT_PAINT,        self.OnPaint)
-        self.Bind(wx.EVT_SIZE,         self.OnSize)
-        self.Bind(wx.EVT_IDLE,         self.OnIdle)
-        self._bindMouseEvents()
-        
-        self.processMouse = True
-        
-        # render output objects
-        self.mapfile = None   # image file to be rendered
-        self.img     = None   # wx.Image object (self.mapfile)
-        # decoration overlays
-        self.overlays = {}
-        # images and their PseudoDC ID's for painting and dragging
-        self.imagedict = {}   
-        self.select = {}      # selecting/unselecting decorations for dragging
-        self.textdict = {}    # text, font, and color indexed by id
-        self.currtxtid = None # PseudoDC id for currently selected text
-        
-        # zoom objects
-        self.zoomhistory  = [] # list of past zoom extents
-        self.currzoom     = 0  # current set of extents in zoom history being used
-        self.zoomtype     = 1  # 1 zoom in, 0 no zoom, -1 zoom out
-        self.hitradius    = 10 # distance for selecting map decorations
-        self.dialogOffset = 5  # offset for dialog (e.g. DisplayAttributesDialog)
-        
-        # OnSize called to make sure the buffer is initialized.
-        # This might result in OnSize getting called twice on some
-        # platforms at initialization, but little harm done.
-        ### self.OnSize(None)
-        
-        self._definePseudoDC()
-        # redraw all pdc's, pdcTmp layer is redrawn always (speed issue)
-        self.redrawAll = True
-        
-        # will store an off screen empty bitmap for saving to file
-        self._buffer = None
-        
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
-        
-        # vars for handling mouse clicks
-        self.dragid   = -1
-        self.lastpos  = (0, 0)
-        
-    def _definePseudoDC(self):
-        """!Define PseudoDC objects to use
-        """
-        # create PseudoDC used for background map, map decorations like scales and legends
-        self.pdc = wx.PseudoDC()
-        # used for digitization tool
-        self.pdcVector = None
-        # decorations (region box, etc.)
-        self.pdcDec = wx.PseudoDC()
-        # pseudoDC for temporal objects (select box, measurement tool, etc.)
-        self.pdcTmp = wx.PseudoDC()
-        
-    def _bindMouseEvents(self):
-        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
-        self.Bind(wx.EVT_MOTION,       self.OnMotion)
-        
-    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0]):
-        """!Draws map and overlay decorations
-        """
-        if drawid == None:
-            if pdctype == 'image' and img:
-                drawid = self.imagedict[img]
-            elif pdctype == 'clear':
-                drawid == None
-            else:
-                drawid = wx.NewId()
-        
-        if img and pdctype == 'image':
-            # self.imagedict[img]['coords'] = coords
-            self.select[self.imagedict[img]['id']] = False # ?
-        
-        pdc.BeginDrawing()
-        
-        if drawid != 99:
-            bg = wx.TRANSPARENT_BRUSH
-        else:
-            bg = wx.Brush(self.GetBackgroundColour())
-        
-        pdc.SetBackground(bg)
-        
-        Debug.msg (5, "BufferedWindow.Draw(): id=%s, pdctype = %s, coord=%s" % \
-                       (drawid, pdctype, coords))
-        
-        # set PseudoDC id
-        if drawid is not None:
-            pdc.SetId(drawid)
-            
-        if pdctype == 'clear': # erase the display
-            bg = wx.WHITE_BRUSH
-            # bg = wx.Brush(self.GetBackgroundColour())
-            pdc.SetBackground(bg)
-            pdc.RemoveAll()
-            pdc.Clear()
-            pdc.EndDrawing()
-            
-            self.Refresh()
-            return
-        
-        if pdctype == 'image': # draw selected image
-            bitmap = wx.BitmapFromImage(img)
-            w,h = bitmap.GetSize()
-            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
-            pdc.SetIdBounds(drawid, wx.Rect(coords[0],coords[1], w, h))
-        
-        elif pdctype == 'box': # draw a box on top of the map
-            if self.pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.pen)
-                x2 = max(coords[0],coords[2])
-                x1 = min(coords[0],coords[2])
-                y2 = max(coords[1],coords[3])
-                y1 = min(coords[1],coords[3])
-                rwidth = x2-x1
-                rheight = y2-y1
-                rect = wx.Rect(x1, y1, rwidth, rheight)
-                pdc.DrawRectangleRect(rect)
-                pdc.SetIdBounds(drawid, rect)
-                
-        elif pdctype == 'line': # draw a line on top of the map
-            if self.pen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.pen)
-                pdc.DrawLinePoint(wx.Point(coords[0], coords[1]),wx.Point(coords[2], coords[3]))
-                pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], coords[2], coords[3]))
-        
-        elif pdctype == 'polyline': # draw a polyline on top of the map
-            if self.polypen:
-                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
-                pdc.SetPen(self.polypen)
-                if (len(coords) < 2):
-                    return
-                i = 1
-                while i < len(coords):
-                    pdc.DrawLinePoint(wx.Point(coords[i-1][0], coords[i-1][1]),
-                                      wx.Point(coords[i][0], coords[i][1]))
-                    i += 1
-                
-                # get bounding rectangle for polyline
-                xlist = []
-                ylist = []
-                if len(coords) > 0:
-                    for point in coords:
-                        x,y = point
-                        xlist.append(x)
-                        ylist.append(y)
-                    x1 = min(xlist)
-                    x2 = max(xlist)
-                    y1 = min(ylist)
-                    y2 = max(ylist)
-                    pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
-                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
-        
-        elif pdctype == 'point': # draw point
-            if self.pen:
-                pdc.SetPen(self.pen)
-                pdc.DrawPoint(coords[0], coords[1])
-                coordsBound = (coords[0] - 5,
-                               coords[1] - 5,
-                               coords[0] + 5,
-                               coords[1] + 5)
-                pdc.SetIdBounds(drawid, wx.Rect(coordsBound))
-        
-        elif pdctype == 'text': # draw text on top of map
-            if not img['active']:
-                return # only draw active text
-            if 'rotation' in img:
-                rotation = float(img['rotation'])
-            else:
-                rotation = 0.0
-            w, h = self.GetFullTextExtent(img['text'])[0:2]
-            pdc.SetFont(img['font'])
-            pdc.SetTextForeground(img['color'])
-            coords, bbox = self.TextBounds(img)
-            if rotation == 0:
-                pdc.DrawText(img['text'], coords[0], coords[1])
-            else:
-                pdc.DrawRotatedText(img['text'], coords[0], coords[1], rotation)
-            pdc.SetIdBounds(drawid, bbox)
-        
-        pdc.EndDrawing()
-        
-        self.Refresh()
-        
-        return drawid
-    
-    def TextBounds(self, textinfo, relcoords = False):
-        """!Return text boundary data
-        
-        @param textinfo text metadata (text, font, color, rotation)
-        @param coords reference point
-        
-        @return coords of nonrotated text bbox (TL corner)
-        @return bbox of rotated text bbox (wx.Rect)
-        @return relCoords are text coord inside bbox
-        """
-        if 'rotation' in textinfo:
-            rotation = float(textinfo['rotation'])
-        else:
-            rotation = 0.0
-        
-        coords = textinfo['coords']
-        bbox = wx.Rect(coords[0], coords[1], 0, 0)
-        relCoords = (0, 0)
-        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
-                   (textinfo['text'], rotation))
-        
-        self.Update()
-        
-        self.SetFont(textinfo['font'])
-        
-        w, h = self.GetTextExtent(textinfo['text'])
-        
-        if rotation == 0:
-            bbox[2], bbox[3] = w, h
-            if relcoords:
-                return coords, bbox, relCoords
-            else:
-                return coords, bbox
-        
-        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
-        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
-        if rotation > 0 and rotation < 90:
-            bbox[1] -= boxh
-            relCoords = (0, boxh)
-        elif rotation >= 90 and rotation < 180:
-            bbox[0] -= boxw
-            bbox[1] -= boxh
-            relCoords = (boxw, boxh)
-        elif rotation >= 180 and rotation < 270:
-            bbox[0] -= boxw
-            relCoords = (boxw, 0)
-        bbox[2] = boxw
-        bbox[3] = boxh
-        bbox.Inflate(h,h)
-        if relcoords:
-            return coords, bbox, relCoords
-        else:
-            return coords, bbox
-
-    def OnPaint(self, event):
-        """!Draw PseudoDC's to buffered paint DC
-        
-        If self.redrawAll is False on self.pdcTmp content is re-drawn
-        """
-        Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
-        dc = wx.BufferedPaintDC(self, self.buffer)
-        dc.Clear()
-        
-        # use PrepareDC to set position correctly
-        self.PrepareDC(dc)
-        
-        # create a clipping rect from our position and size
-        # and update region
-        rgn = self.GetUpdateRegion().GetBox()
-        dc.SetClippingRect(rgn)
-        
-        switchDraw = False
-        if self.redrawAll is None:
-            self.redrawAll = True
-            switchDraw = True
-        
-        if self.redrawAll: # redraw pdc and pdcVector
-            # draw to the dc using the calculated clipping rect
-            self.pdc.DrawToDCClipped(dc, rgn)
-            
-            # draw vector map layer
-            if hasattr(self, "digit"):
-                # decorate with GDDC (transparency)
-                try:
-                    gcdc = wx.GCDC(dc)
-                    self.pdcVector.DrawToDCClipped(gcdc, rgn)
-                except NotImplementedError, e:
-                    print >> sys.stderr, e
-                    self.pdcVector.DrawToDCClipped(dc, rgn)
-            
-            self.bufferLast = None
-        else: # do not redraw pdc and pdcVector
-            if self.bufferLast is None:
-                # draw to the dc
-                self.pdc.DrawToDC(dc)
-                
-                if hasattr(self, "digit"):
-                    # decorate with GDDC (transparency)
-                    try:
-                        gcdc = wx.GCDC(dc)
-                        self.pdcVector.DrawToDC(gcdc)
-                    except NotImplementedError, e:
-                        print >> sys.stderr, e
-                        self.pdcVector.DrawToDC(dc)
-                
-                # store buffered image
-                # self.bufferLast = wx.BitmapFromImage(self.buffer.ConvertToImage())
-                self.bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
-            
-            self.pdc.DrawBitmap(self.bufferLast, 0, 0, False)
-            self.pdc.DrawToDC(dc)
-        
-        # draw decorations (e.g. region box)
-        try:
-            gcdc = wx.GCDC(dc)
-            self.pdcDec.DrawToDC(gcdc)
-        except NotImplementedError, e:
-            print >> sys.stderr, e
-            self.pdcDec.DrawToDC(dc)
-        
-        # draw temporary object on the foreground
-        ### self.pdcTmp.DrawToDCClipped(dc, rgn)
-        self.pdcTmp.DrawToDC(dc)
-        
-        if switchDraw:
-            self.redrawAll = False
-        
-    def OnSize(self, event):
-        """!Scale map image so that it is the same size as the Window
-        """
-        Debug.msg(3, "BufferedWindow.OnSize():")
-        
-        # set size of the input image
-        self.Map.ChangeMapSize(self.GetClientSize())
-        # align extent based on center point and display resolution
-        # this causes that image is not resized when display windows is resized
-        ### self.Map.AlignExtentFromDisplay()
-        
-        # Make new off screen bitmap: this bitmap will always have the
-        # current drawing in it, so it can be used to save the image to
-        # a file, or whatever.
-        self.buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
-        
-        # get the image to be rendered
-        self.img = self.GetImage()
-        
-        # update map display
-        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
-            self.img = self.img.Scale(self.Map.width, self.Map.height)
-            if len(self.Map.GetListOfLayers()) > 0:
-                self.UpdateMap()
-        
-        # re-render image on idle
-        self.resize = True
-
-        # reposition checkbox in statusbar
-        self.parent.StatusbarReposition()
-        
-        # update statusbar
-        self.parent.StatusbarUpdate()
-        
-    def OnIdle(self, event):
-        """!Only re-render a composite map image from GRASS during
-        idle time instead of multiple times during resizing.
-        """
-        if self.resize:
-            self.UpdateMap(render = True)
-        
-        event.Skip()
-
-    def SaveToFile(self, FileName, FileType, width, height):
-        """!This draws the pseudo DC to a buffer that can be saved to
-        a file.
-        
-        @param FileName file name
-        @param FileType type of bitmap
-        @param width image width
-        @param height image height
-        """
-        busy = wx.BusyInfo(message = _("Please wait, exporting image..."),
-                           parent = self)
-        wx.Yield()
-        
-        self.Map.ChangeMapSize((width, height))
-        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
-        self.Map.Render(force = True, windres = True)
-        img = self.GetImage()
-        self.Draw(self.pdc, img, drawid = 99)
-        dc = wx.BufferedPaintDC(self, ibuffer)
-        dc.Clear()
-        self.PrepareDC(dc)
-        self.pdc.DrawToDC(dc)
-        if self.pdcVector:
-            self.pdcVector.DrawToDC(dc)
-        ibuffer.SaveFile(FileName, FileType)
-        
-        busy.Destroy()
-        
-        self.UpdateMap(render = True)
-        self.Refresh()
-        
-    def GetOverlay(self):
-        """!Converts rendered overlay files to wx.Image
-        
-        Updates self.imagedict
-        
-        @return list of images
-        """
-        imgs = []
-        for overlay in self.Map.GetListOfLayers(l_type = "overlay", l_active = True):
-            if os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
-                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
-                self.imagedict[img] = { 'id' : overlay.id,
-                                        'layer' : overlay }
-                imgs.append(img)
-
-        return imgs
-    
-    def GetImage(self):
-        """!Converts redered map files to wx.Image
-        
-        Updates self.imagedict (id=99)
-        
-        @return wx.Image instance (map composition)
-        """
-        imgId = 99
-        if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
-                os.path.getsize(self.Map.mapfile):
-            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
-        else:
-            img = None
-        
-        self.imagedict[img] = { 'id': imgId }
-        
-        return img
-
-    def UpdateMap(self, render = True, renderVector = True):
-        """!Updates the canvas anytime there is a change to the
-        underlaying images or to the geometry of the canvas.
-        
-        @param render re-render map composition
-        @param renderVector re-render vector map layer enabled for editing (used for digitizer)
-        """
-        start = time.clock()
-        
-        self.resize = False
-        
-        if not self.Map.cmdfile and self.img is None:
-            render = True
-        
-        #
-        # initialize process bar (only on 'render')
-        #
-        if render or renderVector:
-            self.parent.GetProgressBar().Show()
-            if self.parent.GetProgressBar().GetRange() > 0:
-                self.parent.GetProgressBar().SetValue(1)
-        
-        #
-        # render background image if needed
-        #
-        # update layer dictionary if there has been a change in layers
-        if self.tree and self.tree.reorder:
-            self.tree.ReorderLayers()
-        
-        # reset flag for auto-rendering
-        if self.tree:
-            self.tree.rerender = False
-        
-        try:
-            if render:
-                # update display size
-                self.Map.ChangeMapSize(self.GetClientSize())
-                if self.parent.GetProperty('resolution'):
-                    # use computation region resolution for rendering
-                    windres = True
-                else:
-                    windres = False
-                
-                self.mapfile = self.Map.Render(force = True, mapWindow = self.parent,
-                                               windres = windres)
-            else:
-                self.mapfile = self.Map.Render(force = False, mapWindow = self.parent)
-            
-        except gcmd.GException, e:
-            gcmd.GError(message = e.value)
-            self.mapfile = None
-        
-        self.img = self.GetImage() # id=99
-        
-        #
-        # clear pseudoDcs
-        #
-        for pdc in (self.pdc,
-                    self.pdcDec,
-                    self.pdcTmp):
-            pdc.Clear()
-            pdc.RemoveAll()
-        
-        #
-        # draw background map image to PseudoDC
-        #
-        if not self.img:
-            self.Draw(self.pdc, pdctype = 'clear')
-        else:
-            try:
-                id = self.imagedict[self.img]['id']
-            except:
-                return False
-            
-            self.Draw(self.pdc, self.img, drawid = id)
-        
-        #
-        # render vector map layer
-        #
-        if renderVector and hasattr(self, "digit"):
-            self._updateMap()
-        #
-        # render overlays
-        #
-        for img in self.GetOverlay():
-            # draw any active and defined overlays
-            if self.imagedict[img]['layer'].IsActive():
-                id = self.imagedict[img]['id']
-                self.Draw(self.pdc, img = img, drawid = id,
-                          pdctype = self.overlays[id]['pdcType'], coords = self.overlays[id]['coords'])
-        
-        for id in self.textdict.keys():
-            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
-                      pdctype = 'text', coords = [10, 10, 10, 10])
-        
-        # optionally draw computational extent box
-        self.DrawCompRegionExtent()
-        
-        #
-        # redraw pdcTmp if needed
-        #
-        if len(self.polycoords) > 0:
-            self.DrawLines(self.pdcTmp)
-            
-        if not self.parent.IsStandalone() and \
-                self.parent.GetLayerManager().gcpmanagement:
-            # -> georectifier (redraw GCPs)
-            if self.parent.GetMapToolbar():
-                if self == self.parent.TgtMapWindow:
-                    coordtype = 'target'
-                else:
-                    coordtype = 'source'
-
-                self.parent.DrawGCP(coordtype)
-
-        # 
-        # clear measurement
-        #
-        if self.mouse["use"] == "measure":
-            self.ClearLines(pdc = self.pdcTmp)
-            self.polycoords = []
-            self.mouse['use'] = 'pointer'
-            self.mouse['box'] = 'point'
-            self.mouse['end'] = [0, 0]
-            self.SetCursor(self.parent.cursors["default"])
-            
-        stop = time.clock()
-        
-        #
-        # hide process bar
-        #
-        self.parent.GetProgressBar().Hide()
-
-        #
-        # update statusbar 
-        #
-        ### self.Map.SetRegion()
-        self.parent.StatusbarUpdate()
-        
-        
-        Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
-                   (render, renderVector, (stop-start)))
-        
-        return True
-
-    def DrawCompRegionExtent(self):
-        """!Draw computational region extent in the display
-        
-        Display region is drawn as a blue box inside the computational region,
-        computational region inside a display region as a red box).
-        """
-        if hasattr(self, "regionCoords"):
-            compReg = self.Map.GetRegion()
-            dispReg = self.Map.GetCurrentRegion()
-            reg = None
-            if self.IsInRegion(dispReg, compReg):
-                self.polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
-                reg = dispReg
-            else:
-                self.polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
-                                      width = 3, style = wx.SOLID)
-                reg = compReg
-            
-            self.regionCoords = []
-            self.regionCoords.append((reg['w'], reg['n']))
-            self.regionCoords.append((reg['e'], reg['n']))
-            self.regionCoords.append((reg['e'], reg['s']))
-            self.regionCoords.append((reg['w'], reg['s']))
-            self.regionCoords.append((reg['w'], reg['n']))
-            # draw region extent
-            self.DrawLines(pdc = self.pdcDec, polycoords = self.regionCoords)
-
-    def IsInRegion(self, region, refRegion):
-        """!
-        Test if 'region' is inside of 'refRegion'
-
-        @param region input region
-        @param refRegion reference region (e.g. computational region)
-
-        @return True if region is inside of refRegion
-        @return False 
-        """
-        if region['s'] >= refRegion['s'] and \
-                region['n'] <= refRegion['n'] and \
-                region['w'] >= refRegion['w'] and \
-                region['e'] <= refRegion['e']:
-            return True
-        
-        return False
-
-    def EraseMap(self):
-        """!Erase map canvas
-        """
-        self.Draw(self.pdc, pdctype = 'clear')
-        
-        if hasattr(self, "digit"):
-            self.Draw(self.pdcVector, pdctype = 'clear')
-        
-        self.Draw(self.pdcDec, pdctype = 'clear')
-        self.Draw(self.pdcTmp, pdctype = 'clear')
-        
-    def DragMap(self, moveto):
-        """!Drag the entire map image for panning.
-        
-        @param moveto dx,dy
-        """
-        dc = wx.BufferedDC(wx.ClientDC(self))
-        dc.SetBackground(wx.Brush("White"))
-        dc.Clear()
-        
-        self.dragimg = wx.DragImage(self.buffer)
-        self.dragimg.BeginDrag((0, 0), self)
-        self.dragimg.GetImageRect(moveto)
-        self.dragimg.Move(moveto)
-        
-        self.dragimg.DoDrawImage(dc, moveto)
-        self.dragimg.EndDrag()
-        
-    def DragItem(self, id, event):
-        """!Drag an overlay decoration item
-        """
-        if id == 99 or id == '' or id == None: return
-        Debug.msg (5, "BufferedWindow.DragItem(): id=%d" % id)
-        x, y = self.lastpos
-        dx = event.GetX() - x
-        dy = event.GetY() - y
-        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
-        r = self.pdc.GetIdBounds(id)
-        
-        if type(r) is list:
-            r = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100: # text dragging
-            rtop = (r[0],r[1]-r[3],r[2],r[3])
-            r = r.Union(rtop)
-            rleft = (r[0]-r[2],r[1],r[2],r[3])
-            r = r.Union(rleft)
-        self.pdc.TranslateId(id, dx, dy)
-        
-        r2 = self.pdc.GetIdBounds(id)
-        if type(r2) is list:
-            r2 = wx.Rect(r[0], r[1], r[2], r[3])
-        if id > 100: # text
-            self.textdict[id]['bbox'] = r2
-            self.textdict[id]['coords'][0] += dx
-            self.textdict[id]['coords'][1] += dy
-        r = r.Union(r2)
-        r.Inflate(4,4)
-        self.RefreshRect(r, False)
-        self.lastpos = (event.GetX(), event.GetY())
-                
-    def MouseDraw(self, pdc = None, begin = None, end = None):
-        """!Mouse box or line from 'begin' to 'end'
-        
-        If not given from self.mouse['begin'] to self.mouse['end'].
-        """
-        if not pdc:
-            return
-        
-        if begin is None:
-            begin = self.mouse['begin']
-        if end is None:
-            end   = self.mouse['end']
-        
-        Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
-                       (self.mouse['use'], self.mouse['box'],
-                        begin[0], begin[1], end[0], end[1]))
-        
-        if self.mouse['box'] == "box":
-            boxid = wx.ID_NEW
-            mousecoords = [begin[0], begin[1],
-                           end[0], end[1]]
-            r = pdc.GetIdBounds(boxid)
-            if type(r) is list:
-                r = wx.Rect(r[0], r[1], r[2], r[3])
-            r.Inflate(4, 4)
-            try:
-                pdc.ClearId(boxid)
-            except:
-                pass
-            self.RefreshRect(r, False)
-            pdc.SetId(boxid)
-            self.Draw(pdc, drawid = boxid, pdctype = 'box', coords = mousecoords)
-        
-        elif self.mouse['box'] == "line":
-            self.lineid = wx.ID_NEW
-            mousecoords = [begin[0], begin[1], \
-                           end[0], end[1]]
-            x1 = min(begin[0],end[0])
-            x2 = max(begin[0],end[0])
-            y1 = min(begin[1],end[1])
-            y2 = max(begin[1],end[1])
-            r = wx.Rect(x1,y1,x2-x1,y2-y1)
-            r.Inflate(4,4)
-            try:
-                pdc.ClearId(self.lineid)
-            except:
-                pass
-            self.RefreshRect(r, False)
-            pdc.SetId(self.lineid)
-            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = mousecoords)
-
-    def DrawLines(self, pdc = None, polycoords = None):
-        """!Draw polyline in PseudoDC
-        
-        Set self.pline to wx.NEW_ID + 1
-        
-        polycoords - list of polyline vertices, geographical coordinates
-        (if not given, self.polycoords is used)
-        """
-        if not pdc:
-            pdc = self.pdcTmp
-        
-        if not polycoords:
-            polycoords = self.polycoords
-        
-        if len(polycoords) > 0:
-            self.plineid = wx.ID_NEW + 1
-            # convert from EN to XY
-            coords = []
-            for p in polycoords:
-                coords.append(self.Cell2Pixel(p))
-
-            self.Draw(pdc, drawid = self.plineid, pdctype = 'polyline', coords = coords)
-            
-            Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \
-                           (coords, self.plineid))
-            
-            return self.plineid
-        
-        return -1
-
-    def DrawCross(self, pdc, coords, size, rotation = 0,
-                  text = None, textAlign = 'lr', textOffset = (5, 5)):
-        """!Draw cross in PseudoDC
-
-        @todo implement rotation
-
-        @param pdc PseudoDC
-        @param coord center coordinates
-        @param rotation rotate symbol
-        @param text draw also text (text, font, color, rotation)
-        @param textAlign alignment (default 'lower-right')
-        @textOffset offset for text (from center point)
-        """
-        Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
-                  (pdc, coords, size))
-        coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
-                       (coords[0], coords[1] - size, coords[0], coords[1] + size))
-
-        self.lineid = wx.NewId()
-        for lineCoords in coordsCross:
-            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = lineCoords)
-        
-        if not text:
-            return self.lineid
-        
-        if textAlign == 'ul':
-            coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
-        elif textAlign == 'ur':
-            coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
-        elif textAlign == 'lr':
-            coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
-        else:
-            coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
-        
-        self.Draw(pdc, img = text,
-                  pdctype = 'text', coords = coord)
-        
-        return self.lineid
-
-    def MouseActions(self, event):
-        """!Mouse motion and button click notifier
-        """
-        if not self.processMouse:
-            return
-        
-        # zoom with mouse wheel
-        if event.GetWheelRotation() != 0:
-            self.OnMouseWheel(event)
-            
-        # left mouse button pressed
-        elif event.LeftDown():
-            self.OnLeftDown(event)
-        
-        # left mouse button released
-        elif event.LeftUp():
-            self.OnLeftUp(event)
-        
-        # dragging
-        elif event.Dragging():
-            self.OnDragging(event)
-        
-        # double click
-        elif event.ButtonDClick():
-            self.OnButtonDClick(event)
-        
-        # middle mouse button pressed
-        elif event.MiddleDown():
-            self.OnMiddleDown(event)
-        
-        # middle mouse button relesed
-        elif event.MiddleUp():
-            self.OnMiddleUp(event)
-        
-        # right mouse button pressed
-        elif event.RightDown():
-            self.OnRightDown(event)
-        
-        # right mouse button released
-        elif event.RightUp():
-            self.OnRightUp(event)
-        
-        elif event.Entering():
-            self.OnMouseEnter(event)
-        
-        elif event.Moving():
-            self.OnMouseMoving(event)
-                
-    def OnMouseWheel(self, event):
-        """!Mouse wheel moved
-        """
-        self.processMouse = False
-        current  = event.GetPositionTuple()[:]
-        wheel = event.GetWheelRotation()
-        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
-        # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
-        begin = (current[0] - self.Map.width / 4,
-                 current[1] - self.Map.height / 4)
-        end   = (current[0] + self.Map.width / 4,
-                 current[1] + self.Map.height / 4)
-        
-        if wheel > 0:
-            zoomtype = 1
-        else:
-            zoomtype = -1
-        
-        # zoom
-        self.Zoom(begin, end, zoomtype)
-        
-        # redraw map
-        self.UpdateMap()
-        
-        # update statusbar
-        self.parent.StatusbarUpdate()
-        
-        self.Refresh()
-        self.processMouse = True
-        
-    def OnDragging(self, event):
-        """!Mouse dragging
-        """
-        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
-        current  = event.GetPositionTuple()[:]
-        previous = self.mouse['begin']
-        move = (current[0] - previous[0],
-                current[1] - previous[1])
-        
-        if hasattr(self, "digit"):
-            digitToolbar = self.toolbar
-        else:
-            digitToolbar = None
-        
-        # dragging or drawing box with left button
-        if self.mouse['use'] == 'pan' or \
-                event.MiddleIsDown():
-            self.DragMap(move)
-        
-        # dragging decoration overlay item
-        elif (self.mouse['use'] == 'pointer' and 
-                not digitToolbar and 
-                self.dragid != None):
-            self.DragItem(self.dragid, event)
-        
-        # dragging anything else - rubber band box or line
-        else:
-            if (self.mouse['use'] == 'pointer' and 
-                not digitToolbar):
-                return
-            
-            self.mouse['end'] = event.GetPositionTuple()[:]
-            if (event.LeftIsDown() and 
-                not (digitToolbar and 
-                    digitToolbar.GetAction() in ("moveLine",) and 
-                     self.digit.GetDisplay().GetSelected() > 0)):
-                self.MouseDraw(pdc = self.pdcTmp)
-        
-    def OnLeftDown(self, event):
-        """!Left mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
-                   self.mouse["use"])
-        
-        self.mouse['begin'] = event.GetPositionTuple()[:]
-        
-        if self.mouse["use"] in ["measure", "profile"]:
-            # measure or profile
-            if len(self.polycoords) == 0:
-                self.mouse['end'] = self.mouse['begin']
-                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
-                self.ClearLines(pdc=self.pdcTmp)
-            else:
-                self.mouse['begin'] = self.mouse['end']
-        
-        elif self.mouse['use'] in ('zoom', 'legend'):
-            pass
-        
-        # vector digizer
-        elif self.mouse["use"] == "pointer" and \
-                hasattr(self, "digit"):
-            if event.ControlDown():
-                self.OnLeftDownUndo(event)
-            else:
-                self._onLeftDown(event)
-        
-        elif self.mouse['use'] == 'pointer':
-            # get decoration or text id
-            self.idlist = []
-            self.dragid = ''
-            self.lastpos = self.mouse['begin']
-            idlist = self.pdc.FindObjects(self.lastpos[0], self.lastpos[1],
-                                          self.hitradius)
-            if 99 in idlist:
-                idlist.remove(99)                             
-            if idlist != []:
-                self.dragid = idlist[0] #drag whatever is on top
-        else:
-            pass
-        
-        event.Skip()
-        
-    def OnLeftUp(self, event):
-        """!Left mouse button released
-        """
-        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
-                       self.mouse["use"])
-        
-        self.mouse['end'] = event.GetPositionTuple()[:]
-        
-        if self.mouse['use'] in ["zoom", "pan"]:
-            # set region in zoom or pan
-            begin = self.mouse['begin']
-            end = self.mouse['end']
-            
-            if self.mouse['use'] == 'zoom':
-                # set region for click (zero-width box)
-                if begin[0] - end[0] == 0 or \
-                        begin[1] - end[1] == 0:
-                    # zoom 1/2 of the screen (TODO: settings)
-                    begin = (end[0] - self.Map.width / 4,
-                             end[1] - self.Map.height / 4)
-                    end   = (end[0] + self.Map.width / 4,
-                             end[1] + self.Map.height / 4)
-            
-            self.Zoom(begin, end, self.zoomtype)
-
-            # redraw map
-            self.UpdateMap(render = True)
-            
-            # update statusbar
-            self.parent.StatusbarUpdate()
-            
-        elif self.mouse["use"] == "query":
-            # querying
-            layers = self.GetSelectedLayer(multi = True)
-            isRaster = False
-            nVectors = 0
-            for l in layers:
-                if l.GetType() == 'raster':
-                    isRaster = True
-                    break
-                if l.GetType() == 'vector':
-                    nVectors += 1
-            
-            if isRaster or nVectors > 1:
-                self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
-            else:
-                self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
-                # clear temp canvas
-                self.UpdateMap(render = False, renderVector = False)
-            
-        elif self.mouse["use"] == "queryVector":
-            # editable mode for vector map layers
-            self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
-            
-            # clear temp canvas
-            self.UpdateMap(render = False, renderVector = False)
-        
-        elif self.mouse["use"] in ["measure", "profile"]:
-            # measure or profile
-            if self.mouse["use"] == "measure":
-                self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
-            
-            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
-            self.ClearLines(pdc = self.pdcTmp)
-            self.DrawLines(pdc = self.pdcTmp)
-        
-        elif self.mouse["use"] == "pointer" and \
-                not self.parent.IsStandalone() and \
-                self.parent.GetLayerManager().gcpmanagement:
-            # -> GCP manager
-            if self.parent.GetToolbar('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 \
-                hasattr(self, "digit"):
-            self._onLeftUp(event)
-            
-        elif (self.mouse['use'] == 'pointer' and 
-                self.dragid >= 0):
-            # end drag of overlay decoration
-            
-            if self.dragid < 99 and self.dragid in self.overlays:
-                self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
-            elif self.dragid > 100 and self.dragid in self.textdict:
-                self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
-            else:
-                pass
-            self.dragid = None
-            self.currtxtid = None
-            
-        elif self.mouse['use'] == 'legend':
-            self.ResizeLegend(self.mouse["begin"], self.mouse["end"])
-            self.parent.dialogs['legend'].FindWindowByName("resize").SetValue(False)
-            self.Map.GetOverlay(1).SetActive(True)
-            self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
-            self.parent.MapWindow.mouse['use'] = 'pointer'
-            
-            self.UpdateMap()
-            
-    def OnButtonDClick(self, event):
-        """!Mouse button double click
-        """
-        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
-                   self.mouse["use"])
-        
-        if self.mouse["use"] == "measure":
-            # measure
-            self.ClearLines(pdc=self.pdcTmp)
-            self.polycoords = []
-            self.mouse['use'] = 'pointer'
-            self.mouse['box'] = 'point'
-            self.mouse['end'] = [0, 0]
-            self.Refresh()
-            self.SetCursor(self.parent.cursors["default"])
-        
-        elif self.mouse["use"] != "profile" or \
-                (self.mouse['use'] != 'pointer' and \
-                     hasattr(self, "digit")):
-               # select overlay decoration options dialog
-            clickposition = event.GetPositionTuple()[:]
-            idlist  = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
-            if idlist == []:
-                return
-            self.dragid = idlist[0]
-
-            # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
-            if self.dragid > 100:
-                self.currtxtid = self.dragid
-                self.parent.OnAddText(None)
-            elif self.dragid == 0:
-                self.parent.OnAddBarscale(None)
-            elif self.dragid == 1:
-                self.parent.OnAddLegend(None)
-        
-    def OnRightDown(self, event):
-        """!Right mouse button pressed
-        """
-        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
-                   self.mouse["use"])
-        
-        if hasattr(self, "digit"):
-            self._onRightDown(event)
-        
-        event.Skip()
-        
-    def OnRightUp(self, event):
-        """!Right mouse button released
-        """
-        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
-                   self.mouse["use"])
-        
-        if hasattr(self, "digit"):
-            self._onRightUp(event)
-        
-        self.redrawAll = True
-        self.Refresh()
-        
-        event.Skip()
-        
-    def OnMiddleDown(self, event):
-        """!Middle mouse button pressed
-        """
-        if not event:
-            return
-        
-        self.mouse['begin'] = event.GetPositionTuple()[:]
-        
-    def OnMiddleUp(self, event):
-        """!Middle mouse button released
-        """
-        self.mouse['end'] = event.GetPositionTuple()[:]
-        
-        # set region in zoom or pan
-        begin = self.mouse['begin']
-        end   = self.mouse['end']
-        
-        self.Zoom(begin, end, 0) # no zoom
-        
-        # redraw map
-        self.UpdateMap(render = True)
-        
-        # update statusbar
-        self.parent.StatusbarUpdate()
-        
-    def OnMouseEnter(self, event):
-        """!Mouse entered window and no mouse buttons were pressed
-        """
-        if not self.parent.IsStandalone() and \
-                self.parent.GetLayerManager().gcpmanagement:
-            if self.parent.GetToolbar('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
-        """
-        if self.mouse["use"] == "pointer" and \
-                hasattr(self, "digit"):
-            self._onMouseMoving(event)
-        
-        event.Skip()
-        
-    def ClearLines(self, pdc = None):
-        """!Clears temporary drawn lines from PseudoDC
-        """
-        if not pdc:
-            pdc = self.pdcTmp
-        try:
-            pdc.ClearId(self.lineid)
-            pdc.RemoveId(self.lineid)
-        except:
-            pass
-        
-        try:
-            pdc.ClearId(self.plineid)
-            pdc.RemoveId(self.plineid)
-        except:
-            pass
-        
-        Debug.msg(4, "BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
-                  (self.lineid, self.plineid))
-        
-        return True
-
-    def Pixel2Cell(self, (x, y)):
-        """!Convert image coordinates to real word coordinates
-        
-        @param x, y image coordinates
-        
-        @return easting, northing
-        @return None on error
-        """
-        try:
-            x = int(x)
-            y = int(y)
-        except:
-            return None
-        
-        if self.Map.region["ewres"] > self.Map.region["nsres"]:
-            res = self.Map.region["ewres"]
-        else:
-            res = self.Map.region["nsres"]
-        
-        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
-        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
-        
-        east  = w + x * res
-        north = n - y * res
-        
-        return (east, north)
-    
-    def Cell2Pixel(self, (east, north)):
-        """!Convert real word coordinates to image coordinates
-        """
-        try:
-            east  = float(east)
-            north = float(north)
-        except:
-            return None
-        
-        if self.Map.region["ewres"] > self.Map.region["nsres"]:
-            res = self.Map.region["ewres"]
-        else:
-            res = self.Map.region["nsres"]
-        
-        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
-        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
-        
-        x = (east  - w) / res
-        y = (n - north) / res
-        
-        return (x, y)
-    
-    def ResizeLegend(self, begin, end):
-        w = abs(begin[0] - end[0])
-        h = abs(begin[1] - end[1])
-        if begin[0] < end[0]:
-            x = begin[0]
-        else:
-            x = end[0]
-        if begin[1] < end[1]:
-            y = begin[1]
-        else:
-            y = end[1]
-        screenRect = wx.Rect(x, y, w, h)
-        screenSize = self.GetClientSizeTuple()
-        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
-              (screenSize[1] - y) / float(screenSize[1]) * 100,
-              x / float(screenSize[0]) * 100,
-              (x + w) / float(screenSize[0]) * 100]
-        for i, subcmd in enumerate(self.overlays[1]['cmd']):
-            if subcmd.startswith('at='):
-                self.overlays[1]['cmd'][i] = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
-        self.Map.ChangeOverlay(1, True, command = self.overlays[1]['cmd'])
-        self.overlays[1]['coords'] = (0,0)
-        
-    def Zoom(self, begin, end, zoomtype):
-        """!Calculates new region while (un)zoom/pan-ing
-        """
-        x1, y1 = begin
-        x2, y2 = end
-        newreg = {}
-        
-        # threshold - too small squares do not make sense
-        # can only zoom to windows of > 5x5 screen pixels
-        if abs(x2-x1) > 5 and abs(y2-y1) > 5 and zoomtype != 0:
-            if x1 > x2:
-                x1, x2 = x2, x1
-            if y1 > y2:
-                y1, y2 = y2, y1
-            
-            # zoom in
-            if zoomtype > 0:
-                newreg['w'], newreg['n'] = self.Pixel2Cell((x1, y1))
-                newreg['e'], newreg['s'] = self.Pixel2Cell((x2, y2))
-            
-            # zoom out
-            elif zoomtype < 0:
-                newreg['w'], newreg['n'] = self.Pixel2Cell((-x1 * 2, -y1 * 2))
-                newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + 2 * \
-                                                                (self.Map.width  - x2),
-                                                            self.Map.height + 2 * \
-                                                                (self.Map.height - y2)))
-        # pan
-        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))
-        
-        # if new region has been calculated, set the values
-        if newreg != {}:
-            # LL locations
-            if self.Map.projinfo['proj'] == 'll':
-                self.Map.region['n'] = min(self.Map.region['n'], 90.0)
-                self.Map.region['s'] = max(self.Map.region['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
-            if not self.parent.HasProperty('alignExtent') or \
-                    self.parent.GetProperty('alignExtent'):
-                self.Map.AlignExtentFromDisplay()
-            else:
-                for k in ('n', 's', 'e', 'w'):
-                    self.Map.region[k] = newreg[k]
-            
-            if hasattr(self, "digit") and \
-                    hasattr(self, "moveInfo"):
-                self._zoom(None)
-            
-            self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                             self.Map.region['e'], self.Map.region['w'])
-        
-        if self.redrawAll is False:
-            self.redrawAll = True
-        
-    def ZoomBack(self):
-        """!Zoom to previous extents in zoomhistory list
-        """
-        zoom = list()
-        
-        if len(self.zoomhistory) > 1:
-            self.zoomhistory.pop()
-            zoom = self.zoomhistory[-1]
-        
-        # disable tool if stack is empty
-        if len(self.zoomhistory) < 2: # disable tool
-            toolbar = self.parent.GetMapToolbar()
-            toolbar.Enable('zoomback', enable = False)
-        
-        # zoom to selected region
-        self.Map.GetRegion(n = zoom[0], s = zoom[1],
-                           e = zoom[2], w = zoom[3],
-                           update = True)
-        # update map
-        self.UpdateMap()
-        
-        # update statusbar
-        self.parent.StatusbarUpdate()
-
-    def ZoomHistory(self, n, s, e, w):
-        """!Manages a list of last 10 zoom extents
-
-        @param n,s,e,w north, south, east, west
-
-        @return removed history item if exists (or None)
-        """
-        removed = None
-        self.zoomhistory.append((n,s,e,w))
-        
-        if len(self.zoomhistory) > 10:
-            removed = self.zoomhistory.pop(0)
-        
-        if removed:
-            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
-                      (self.zoomhistory, removed))
-        else:
-            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s" %
-                      (self.zoomhistory))
-        
-        # update toolbar
-        if len(self.zoomhistory) > 1:
-            enable = True
-        else:
-            enable = False
-        
-        toolbar = self.parent.GetMapToolbar()
-        
-        toolbar.Enable('zoomback', enable)
-        
-        return removed
-
-    def ResetZoomHistory(self):
-        """!Reset zoom history"""
-        self.zoomhistory = list()
-                
-    def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
-        """!Set display extents to match selected raster
-        or vector map(s).
-
-        @param layers list of layers to be zoom to
-        @param ignoreNulls True to ignore null-values (valid only for rasters)
-        @param render True to re-render display
-        """
-        zoomreg = {}
-        
-        if not layers:
-            layers = self.GetSelectedLayer(multi = True)
-        
-        if not layers:
-            return
-        
-        rast = []
-        vect = []
-        updated = False
-        for l in layers:
-            # only raster/vector layers are currently supported
-            if l.type == 'raster':
-                rast.append(l.GetName())
-            elif l.type == 'vector':
-                if hasattr(self, "digit") and \
-                        self.toolbar.GetLayer() == l:
-                    w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
-                    self.Map.GetRegion(n = n, s = s, w = w, e = e,
-                                       update = True)
-                    updated = True
-                else:
-                    vect.append(l.name)
-            elif l.type == 'rgb':
-                for rname in l.GetName().splitlines():
-                    rast.append(rname)
-            
-        if not updated:
-            self.Map.GetRegion(rast = rast,
-                               vect = vect,
-                               update = True)
-        
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        if render:
-            self.UpdateMap()
-        
-        self.parent.StatusbarUpdate()
-        
-    def ZoomToWind(self):
-        """!Set display geometry to match computational region
-        settings (set with g.region)
-        """
-        self.Map.region = self.Map.GetRegion()
-        
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        self.UpdateMap()
-        
-        self.parent.StatusbarUpdate()
-
-    def ZoomToDefault(self):
-        """!Set display geometry to match default region settings
-        """
-        self.Map.region = self.Map.GetRegion(default = True)
-        self.Map.AdjustRegion() # aling region extent to the display
-
-        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
-                         self.Map.region['e'], self.Map.region['w'])
-        
-        self.UpdateMap()
-        
-        self.parent.StatusbarUpdate()
-    
-    
-    def GoTo(self, e, n):
-        region = self.Map.GetCurrentRegion()
-
-        region['center_easting'], region['center_northing'] = e, n
-        
-        dn = (region['nsres'] * region['rows']) / 2.
-        region['n'] = region['center_northing'] + dn
-        region['s'] = region['center_northing'] - dn
-        de = (region['ewres'] * region['cols']) / 2.
-        region['e'] = region['center_easting'] + de
-        region['w'] = region['center_easting'] - de
-
-        self.Map.AdjustRegion()
-
-        # add to zoom history
-        self.ZoomHistory(region['n'], region['s'],
-                                   region['e'], region['w'])        
-        self.UpdateMap()
-    
-    def DisplayToWind(self):
-        """!Set computational region (WIND file) to match display
-        extents
-        """
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        # We ONLY want to set extents here. Don't mess with resolution. Leave that
-        # for user to set explicitly with g.region
-        new = self.Map.AlignResolution()
-        gcmd.RunCommand('g.region',
-                        parent = self,
-                        overwrite = True,
-                        n = new['n'],
-                        s = new['s'],
-                        e = new['e'],
-                        w = new['w'],
-                        rows = int(new['rows']),
-                        cols = int(new['cols']))
-        
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-        
-    def ZoomToSaved(self):
-        """!Set display geometry to match extents in
-        saved region file
-        """
-        dlg = gdialogs.SavedRegion(parent = self,
-                                   title = _("Zoom to saved region extents"),
-                                   loadsave='load')
-        
-        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.wind:
-            dlg.Destroy()
-            return
-        
-        if not grass.find_file(name = dlg.wind, element = 'windows')['name']:
-            wx.MessageBox(parent = self,
-                          message = _("Region <%s> not found. Operation canceled.") % dlg.wind,
-                          caption = _("Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
-            dlg.Destroy()
-            return
-        
-        self.Map.GetRegion(regionName = dlg.wind,
-                           update = True)
-        
-        dlg.Destroy()
-        
-        self.ZoomHistory(self.Map.region['n'],
-                         self.Map.region['s'],
-                         self.Map.region['e'],
-                         self.Map.region['w'])
-        
-        self.UpdateMap()
-                
-    def SaveDisplayRegion(self):
-        """!Save display extents to named region file.
-        """
-        dlg = gdialogs.SavedRegion(parent = self,
-                                   title = _("Save display extents to region file"),
-                                   loadsave='save')
-        
-        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.wind:
-            dlg.Destroy()
-            return
-        
-        # test to see if it already exists and ask permission to overwrite
-        if grass.find_file(name = dlg.wind, element = 'windows')['name']:
-            overwrite = wx.MessageBox(parent = self,
-                                      message = _("Region file <%s> already exists. "
-                                                  "Do you want to overwrite it?") % (dlg.wind),
-                                      caption = _("Warning"), style = wx.YES_NO | wx.CENTRE)
-            if (overwrite == wx.YES):
-                self.SaveRegion(dlg.wind)
-        else:
-            self.SaveRegion(dlg.wind)
-        
-        dlg.Destroy()
-        
-    def SaveRegion(self, wind):
-        """!Save region settings
-        
-        @param wind region name
-        """
-        new = self.Map.GetCurrentRegion()
-        
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        gcmd.RunCommand('g.region',
-                        overwrite = True,
-                        parent = self,
-                        flags = 'u',
-                        n = new['n'],
-                        s = new['s'],
-                        e = new['e'],
-                        w = new['w'],
-                        rows = int(new['rows']),
-                        cols = int(new['cols']),
-                        save = wind)
-        
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-        
-    def Distance(self, beginpt, endpt, screen = True):
-        """!Calculete distance
-        
-        Ctypes required for LL-locations
-        
-        @param beginpt first point
-        @param endpt second point
-        @param screen True for screen coordinates otherwise EN
-        """
-        if screen:
-            e1, n1 = self.Pixel2Cell(beginpt)
-            e2, n2 = self.Pixel2Cell(endpt)
-        else:
-            e1, n1 = beginpt
-            e2, n2 = endpt
-            
-        dEast  = (e2 - e1)
-        dNorth = (n2 - n1)
-        
-        if self.parent.Map.projinfo['proj'] == 'll' and haveCtypes:
-            dist = gislib.G_distance(e1, n1, e2, n2)
-        else:
-            dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
-        
-        return (dist, (dEast, dNorth))
-
-    def GetMap(self):
-        """!Get render.Map() instance"""
-        return self.Map

Deleted: grass/trunk/gui/wxpython/gui_modules/mcalc_builder.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mcalc_builder.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/mcalc_builder.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,588 +0,0 @@
-"""!
- at package mcalc_builder.py
-
- at brief Map calculator, wrapper for r.mapcalc
-
-Classes:
- - MapCalcFrame
-
-(C) 2008, 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton, Arizona State University
- at author Martin Landa <landa.martin gmail.com>
- at author Tim Michelsen (load/save expression)
-"""
-
-import os
-import sys
-import time
-
-import globalvar
-import wx
-
-import grass.script as grass
-
-import gcmd
-import gselect
-import menuform
-try:
-    import subprocess
-except:
-    sys.path.append(os.path.join(globalvar.ETCWXDIR, "compat"))
-    import subprocess
-from preferences import globalSettings as UserSettings
-
-class MapCalcFrame(wx.Frame):
-    """!Mapcalc Frame class. Calculator-style window to create and run
-    r(3).mapcalc statements.
-    """
-    def __init__(self, parent, cmd, id = wx.ID_ANY,
-                 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, **kwargs):
-        self.parent = parent
-        if self.parent:
-            self.log = self.parent.GetLogWindow()
-        else:
-            self.log = None
-        
-        # grass command
-        self.cmd = cmd
-
-        if self.cmd == 'r.mapcalc':
-            self.rast3d = False
-            title = _('GRASS GIS Raster Map Calculator')
-        if self.cmd == 'r3.mapcalc':
-            self.rast3d = True
-            title = _('GRASS GIS 3D Raster Map Calculator')
-            
-        wx.Frame.__init__(self, parent, id = id, title = title, **kwargs)
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        self.CreateStatusBar()
-        
-        #
-        # variables
-        #
-        self.heading = _('mapcalc statement')
-        self.funct_dict = {
-            'abs(x)':'abs()',
-            'acos(x)':'acos()',
-            'asin(x)':'asin()',
-            'atan(x)':'atan()',
-            'atan(x,y)':'atan( , )',
-            'cos(x)':'cos()',
-            'double(x)':'double()',
-            'eval([x,y,...,]z)':'eval()',
-            'exp(x)':'exp()',
-            'exp(x,y)':'exp( , )',
-            'float(x)':'float()',
-            'graph(x,x1,y1[x2,y2..])':'graph( , , )',
-            'if(x)':'if()',
-            'if(x,a)':'if( , )',
-            'if(x,a,b)':'if( , , )',
-            'if(x,a,b,c)':'if( , , , )',
-            'int(x)':'if()',
-            'isnull(x)':'isnull()',
-            'log(x)':'log(',
-            'log(x,b)':'log( , )',
-            'max(x,y[,z...])':'max( , )',
-            'median(x,y[,z...])':'median( , )',
-            'min(x,y[,z...])':'min( , )',
-            'mode(x,y[,z...])':'mode( , )',
-            'not(x)':'not()',
-            'pow(x,y)':'pow( , )',
-            'rand(a,b)':'rand( , )',
-            'round(x)':'round()',
-            'sin(x)':'sin()',
-            'sqrt(x)':'sqrt()',
-            'tan(x)':'tan()',
-            'xor(x,y)':'xor( , )',
-            'row()':'row()',
-            'col()':'col()',
-            'x()':'x()',
-            'y()':'y()',
-            'ewres()':'ewres()',
-            'nsres()':'nsres()',
-            'null()':'null()'
-            }
-        
-        if self.rast3d:
-            self.funct_dict['z()'] = 'z()'
-            self.funct_dict['tbres()'] = 'tbres()'
-            element = 'rast3d'
-        else:
-            element = 'cell'
-        
-        self.operatorBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                        label=" %s " % _('Operators'))
-        self.operandBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                       label=" %s " % _('Operands'))
-        self.expressBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                       label=" %s " % _('Expression'))
-        
-        #
-        # Buttons
-        #
-        self.btn_clear = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
-        self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
-        self.btn_run = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Run"))
-        self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
-        self.btn_run.SetDefault()
-        self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-        self.btn_cmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                 label = _("Command dialog"))
-        self.btn_cmd.SetToolTipString(_('Open %s dialog') % self.cmd)
-        self.btn_save = wx.Button(parent = self.panel, id = wx.ID_SAVE)
-        self.btn_save.SetToolTipString(_('Save expression to file'))
-        self.btn_load = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                  label = _("&Load"))
-        self.btn_load.SetToolTipString(_('Load expression from file'))
-        
-        self.btn = dict()        
-        self.btn['pow'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "^")
-        self.btn['pow'].SetToolTipString(_('exponent'))
-        self.btn['div'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "/")
-        self.btn['div'].SetToolTipString(_('divide'))
-        self.btn['add'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "+")
-        self.btn['add'].SetToolTipString(_('add'))
-        self.btn['minus'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "-")
-        self.btn['minus'].SetToolTipString(_('subtract'))
-        self.btn['mod'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "%")
-        self.btn['mod'].SetToolTipString(_('modulus'))
-        self.btn['mult'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "*")
-        self.btn['mult'].SetToolTipString(_('multiply'))
-
-        self.btn['parenl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "(") 
-        self.btn['parenr'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ")")
-        self.btn['lshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<<")
-        self.btn['lshift'].SetToolTipString(_('left shift'))
-        self.btn['rshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>")
-        self.btn['rshift'].SetToolTipString(_('right shift'))
-        self.btn['rshiftu'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>>")
-        self.btn['rshiftu'].SetToolTipString(_('right shift (unsigned)'))
-        self.btn['gt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">")
-        self.btn['gt'].SetToolTipString(_('greater than'))
-        self.btn['gteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">=")
-        self.btn['gteq'].SetToolTipString(_('greater than or equal to'))
-        self.btn['lt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<")
-        self.btn['lt'].SetToolTipString(_('less than'))
-        self.btn['lteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<=")
-        self.btn['lteq'].SetToolTipString(_('less than or equal to'))
-        self.btn['eq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "==")
-        self.btn['eq'].SetToolTipString(_('equal to'))
-        self.btn['noteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!=")
-        self.btn['noteq'].SetToolTipString(_('not equal to'))
-
-        self.btn['compl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "~")
-        self.btn['compl'].SetToolTipString(_('one\'s complement'))
-        self.btn['not'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!")
-        self.btn['not'].SetToolTipString(_('NOT'))
-        self.btn['andbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = '&&')
-        self.btn['andbit'].SetToolTipString(_('bitwise AND'))
-        self.btn['orbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|")
-        self.btn['orbit'].SetToolTipString(_('bitwise OR'))
-        self.btn['and'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&")
-        self.btn['and'].SetToolTipString(_('logical AND'))
-        self.btn['andnull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&&&")
-        self.btn['andnull'].SetToolTipString(_('logical AND (ignores NULLs)'))
-        self.btn['or'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "||")
-        self.btn['or'].SetToolTipString(_('logical OR'))
-        self.btn['ornull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|||")
-        self.btn['ornull'].SetToolTipString(_('logical OR (ignores NULLs)'))
-        self.btn['cond'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "a ? b : c") 
-        self.btn['cond'].SetToolTipString(_('conditional'))
-        
-        #
-        # Text area
-        #
-        self.text_mcalc = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size = (-1, 75),
-                                      style = wx.TE_MULTILINE)
-        wx.CallAfter(self.text_mcalc.SetFocus)
-        
-        #
-        # Map and function insertion text and ComboBoxes
-        self.newmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
-        if self.rast3d:
-            self.newmaplabel.SetLabel(_('Name for new 3D raster map to create'))
-        else:
-            self.newmaplabel.SetLabel(_('Name for new raster map to create'))
-        self.newmaptxt = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size=(250, -1))
-        self.mapsellabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
-        if self.rast3d:
-            self.mapsellabel.SetLabel(_('Insert existing 3D raster map'))
-        else:
-            self.mapsellabel.SetLabel(_('Insert existing raster map'))
-        self.mapselect = gselect.Select(parent = self.panel, id = wx.ID_ANY, size = (250, -1),
-                                        type = element, multiple = False)
-        self.functlabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
-                                        label = _('Insert mapcalc function'))
-        self.function = wx.ComboBox(parent = self.panel, id = wx.ID_ANY, 
-                                    size = (250, -1), choices = sorted(self.funct_dict.keys()),
-                                    style = wx.CB_DROPDOWN |
-                                    wx.CB_READONLY | wx.TE_PROCESS_ENTER)
-        
-        self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                     label=_("Allow output files to overwrite existing files"))
-        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
-        
-        self.addbox = wx.CheckBox(parent=self.panel,
-                                  label=_('Add created raster map into layer tree'), style = wx.NO_BORDER)
-        self.addbox.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
-        if not self.parent or self.parent.GetName() != 'LayerManager':
-            self.addbox.Hide()
-        
-        #
-        # Bindings
-        #
-        for btn in self.btn.keys():
-            self.btn[btn].Bind(wx.EVT_BUTTON, self.AddMark)
-        
-        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-        self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
-        self.btn_run.Bind(wx.EVT_BUTTON, self.OnMCalcRun)
-        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
-        self.btn_cmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
-        self.btn_save.Bind(wx.EVT_BUTTON, self.OnSaveExpression)
-        self.btn_load.Bind(wx.EVT_BUTTON, self.OnLoadExpression)
-        
-        self.mapselect.Bind(wx.EVT_TEXT, self.OnSelect)
-        self.function.Bind(wx.EVT_COMBOBOX, self._return_funct)
-        self.function.Bind(wx.EVT_TEXT_ENTER, self.OnSelect)
-        self.newmaptxt.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
-        self.text_mcalc.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
-
-        self._layout()
-
-        self.SetMinSize(self.GetBestSize())
-    
-    def _return_funct(self,event):
-	i = event.GetString()
-	self._addSomething(self.funct_dict[i])
-    
-    def _layout(self):
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        controlSizer = wx.BoxSizer(wx.HORIZONTAL)
-        operatorSizer = wx.StaticBoxSizer(self.operatorBox, wx.HORIZONTAL)
-
-        buttonSizer1 = wx.GridBagSizer(5, 1)
-        buttonSizer1.Add(item = self.btn['add'], pos = (0,0))
-        buttonSizer1.Add(item = self.btn['minus'], pos = (0,1))
-        buttonSizer1.Add(item = self.btn['mod'], pos = (5,0))
-        buttonSizer1.Add(item = self.btn['mult'], pos = (1,0))
-        buttonSizer1.Add(item = self.btn['div'], pos = (1,1))
-        buttonSizer1.Add(item = self.btn['pow'], pos = (5,1))
-        buttonSizer1.Add(item = self.btn['gt'], pos = (2,0))
-        buttonSizer1.Add(item = self.btn['gteq'], pos = (2,1))
-        buttonSizer1.Add(item = self.btn['eq'], pos = (4,0))
-        buttonSizer1.Add(item = self.btn['lt'], pos = (3,0))
-        buttonSizer1.Add(item = self.btn['lteq'], pos = (3,1))
-        buttonSizer1.Add(item = self.btn['noteq'], pos = (4,1))
-
-        buttonSizer2 = wx.GridBagSizer(5, 1)
-        buttonSizer2.Add(item = self.btn['and'], pos = (0,0))
-        buttonSizer2.Add(item = self.btn['andbit'], pos = (1,0))
-        buttonSizer2.Add(item = self.btn['andnull'], pos = (2,0))
-        buttonSizer2.Add(item = self.btn['or'], pos = (0,1))
-        buttonSizer2.Add(item = self.btn['orbit'], pos = (1,1))
-        buttonSizer2.Add(item = self.btn['ornull'], pos = (2,1))
-        buttonSizer2.Add(item = self.btn['lshift'], pos = (3,0))
-        buttonSizer2.Add(item = self.btn['rshift'], pos = (3,1))
-        buttonSizer2.Add(item = self.btn['rshiftu'], pos = (4,0))
-        buttonSizer2.Add(item = self.btn['cond'], pos = (5,0))
-        buttonSizer2.Add(item = self.btn['compl'], pos = (5,1))
-        buttonSizer2.Add(item = self.btn['not'], pos = (4,1))
-
-        operandSizer = wx.StaticBoxSizer(self.operandBox, wx.HORIZONTAL)
-        
-        buttonSizer3 = wx.GridBagSizer(7, 1)
-        buttonSizer3.Add(item = self.newmaplabel, pos = (0,0),
-                         span = (1, 2), flag = wx.ALIGN_CENTER)
-        buttonSizer3.Add(item = self.newmaptxt, pos = (1,0),
-                         span = (1, 2))
-        buttonSizer3.Add(item = self.functlabel, pos = (2,0),
-                         span = (1,2), flag = wx.ALIGN_CENTER)
-        buttonSizer3.Add(item = self.function, pos = (3,0),
-                         span = (1,2))                         
-        buttonSizer3.Add(item = self.mapsellabel, pos = (4,0),
-                         span = (1,2), flag = wx.ALIGN_CENTER)
-        buttonSizer3.Add(item = self.mapselect, pos = (5,0),
-                         span = (1,2))
-        threebutton = wx.GridBagSizer(1, 2)
-        threebutton.Add(item = self.btn['parenl'], pos = (0,0),
-                         span = (1,1), flag = wx.ALIGN_LEFT)
-        threebutton.Add(item = self.btn['parenr'], pos = (0,1),
-                         span = (1,1), flag = wx.ALIGN_CENTER)
-        threebutton.Add(item = self.btn_clear, pos = (0,2),
-                         span = (1,1), flag = wx.ALIGN_RIGHT)
-        buttonSizer3.Add(item = threebutton, pos = (6,0),
-	                 span = (1,1), flag = wx.ALIGN_CENTER)
-
-        buttonSizer4 = wx.BoxSizer(wx.HORIZONTAL)
-        buttonSizer4.Add(item = self.btn_cmd,
-                         flag = wx.ALL, border = 5)
-        buttonSizer4.AddSpacer(10)
-        buttonSizer4.Add(item = self.btn_load,
-                         flag = wx.ALL, border = 5)
-        buttonSizer4.Add(item = self.btn_save,
-                         flag = wx.ALL, border = 5)                         
-        buttonSizer4.AddSpacer(30)
-        buttonSizer4.Add(item = self.btn_help,
-                         flag = wx.ALL, border = 5)
-        buttonSizer4.Add(item = self.btn_run,
-                         flag = wx.ALL, border = 5)
-        buttonSizer4.Add(item = self.btn_close,
-                         flag = wx.ALL, border = 5)
-        
-        operatorSizer.Add(item = buttonSizer1, proportion = 0,
-                          flag = wx.ALL | wx.EXPAND, border = 5)
-        operatorSizer.Add(item = buttonSizer2, proportion = 0,
-                          flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 5)
-        
-        operandSizer.Add(item = buttonSizer3, proportion = 0,
-                         flag = wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
-        
-        controlSizer.Add(item = operatorSizer, proportion = 1,
-                         flag = wx.RIGHT | wx.EXPAND, border = 5)
-        controlSizer.Add(item = operandSizer, proportion = 0,
-                         flag = wx.EXPAND)
-
-        expressSizer = wx.StaticBoxSizer(self.expressBox, wx.HORIZONTAL)
-        expressSizer.Add(item = self.text_mcalc, proportion = 1,
-                         flag = wx.EXPAND)
-
-        sizer.Add(item = controlSizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALL,
-                  border = 5)        
-        sizer.Add(item = expressSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
-                  border = 5)
-        sizer.Add(item = buttonSizer4, proportion = 0,
-                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
-        
-        sizer.Add(item = self.overwrite, proportion = 0,
-                  flag = wx.LEFT | wx.RIGHT,
-                  border = 5)
-        if self.addbox.IsShown():
-            sizer.Add(item = self.addbox, proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT,
-                      border = 5)
-        
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(sizer)
-        sizer.Fit(self.panel)
-        
-        self.Layout()
-        
-    def AddMark(self,event):
-        """!Sends operators to insertion method
-        """
-        if event.GetId() == self.btn['compl'].GetId(): mark = "~"
-        elif event.GetId() == self.btn['not'].GetId(): mark = "!"
-        elif event.GetId() == self.btn['pow'].GetId(): mark = "^"
-        elif event.GetId() == self.btn['div'].GetId(): mark = "/"
-        elif event.GetId() == self.btn['add'].GetId(): mark = "+"
-        elif event.GetId() == self.btn['minus'].GetId(): mark = "-"
-        elif event.GetId() == self.btn['mod'].GetId(): mark = "%"
-        elif event.GetId() == self.btn['mult'].GetId(): mark = "*"
-        elif event.GetId() == self.btn['lshift'].GetId(): mark = "<<"
-        elif event.GetId() == self.btn['rshift'].GetId(): mark = ">>"
-        elif event.GetId() == self.btn['rshiftu'].GetId(): mark = ">>>"
-        elif event.GetId() == self.btn['gt'].GetId(): mark = ">"
-        elif event.GetId() == self.btn['gteq'].GetId(): mark = ">="
-        elif event.GetId() == self.btn['lt'].GetId(): mark = "<"
-        elif event.GetId() == self.btn['lteq'].GetId(): mark = "<="
-        elif event.GetId() == self.btn['eq'].GetId(): mark = "=="
-        elif event.GetId() == self.btn['noteq'].GetId(): mark = "!="
-        elif event.GetId() == self.btn['andbit'].GetId(): mark = "&"
-        elif event.GetId() == self.btn['orbit'].GetId(): mark = "|"
-        elif event.GetId() == self.btn['or'].GetId(): mark =  "||"
-        elif event.GetId() == self.btn['ornull'].GetId(): mark = "|||"
-        elif event.GetId() == self.btn['and'].GetId(): mark = "&&"
-        elif event.GetId() == self.btn['andnull'].GetId(): mark = "&&&"
-        elif event.GetId() == self.btn['cond'].GetId(): mark = " ? : "
-        elif event.GetId() == self.btn['parenl'].GetId(): mark = "("
-        elif event.GetId() == self.btn['parenr'].GetId(): mark = ")"
-        self._addSomething(mark)
-        
-    def OnSelect(self, event):
-        """!Gets raster map or function selection and send it to
-        insertion method
-        """
-        item = event.GetString()
-        self._addSomething(item)
-
-    def OnUpdateStatusBar(self, event):
-        """!Update statusbar text"""
-        expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
-        self.SetStatusText("r.mapcalc '%s = %s'" % (self.newmaptxt.GetValue(),
-                                                    expr))
-        event.Skip()
-        
-    def _addSomething(self, what):
-        """!Inserts operators, map names, and functions into text area
-        """
-        self.text_mcalc.SetFocus()
-        mcalcstr  = self.text_mcalc.GetValue()
-        position  = self.text_mcalc.GetInsertionPoint()
-        
-        newmcalcstr = mcalcstr[:position]
-        
-        position_offset = 0
-        try:
-            if newmcalcstr[-1] != ' ':
-                newmcalcstr += ' '
-                position_offset += 1
-        except:
-            pass
-        
-        newmcalcstr += what + ' ' + mcalcstr[position:]
-        position_offset += len(what)
-        
-        self.text_mcalc.SetValue(newmcalcstr)
-        if len(what) > 1 and what[-2:] == '()':
-            position_offset -= 1
-        self.text_mcalc.SetInsertionPoint(position + position_offset)
-        self.text_mcalc.Update()
-        
-    def OnMCalcRun(self,event):
-        """!Builds and runs r.mapcalc statement
-        """
-        name = self.newmaptxt.GetValue().strip()
-        if not name:
-            gcmd.GError(parent = self,
-                        message = _("You must enter the name of "
-                                    "a new raster map to create."))
-            return
-        
-        expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
-        if not expr:
-            gcmd.GError(parent = self,
-                        message = _("You must enter an expression "
-                                    "to create a new raster map."))
-            return
-        
-        if self.log:
-            cmd = [self.cmd, str('expression=%s = %s' % (name, expr))]
-            if self.overwrite.IsChecked():
-                cmd.append('--overwrite')
-            self.log.RunCmd(cmd, onDone = self.OnDone)
-            self.parent.Raise()
-        else:
-            if self.overwrite.IsChecked():
-                overwrite = True
-            else:
-                overwrite = False
-            gcmd.RunCommand(self.cmd,
-                            expression = "%s=%s" % (name, expr),
-                            overwrite = overwrite)
-        
-    def OnDone(self, cmd, returncode):
-        """!Add create map to the layer tree"""
-        if not self.addbox.IsChecked():
-            return
-        name = self.newmaptxt.GetValue().strip() + '@' + grass.gisenv()['MAPSET']
-        mapTree = self.parent.GetLayerTree()
-        if not mapTree.GetMap().GetListOfLayers(l_name = name):
-            mapTree.AddLayer(ltype = 'raster',
-                             lname = name,
-                             lcmd = ['d.rast', 'map=%s' % name],
-                             multiple = False)
-        
-        display = self.parent.GetLayerTree().GetMapDisplay()
-        if display and display.IsAutoRendered():
-            display.GetWindow().UpdateMap(render = True)
-        
-    def OnSaveExpression(self, event):
-        """!Saves expression to file
-        """
-        mctxt = self.newmaptxt.GetValue() + ' = ' + self.text_mcalc.GetValue() + os.linesep
-        
-        #dialog
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Choose a file name to save the expression"),
-                            wildcard = _("Expression file (*)|*"),
-                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            if not path:
-                dlg.Destroy()
-                return
-            
-            try:
-                fobj = open(path, 'w')
-                fobj.write(mctxt)
-            finally:
-                fobj.close()
-        
-        dlg.Destroy()
-
-    def OnLoadExpression(self, event):
-        """!Load expression from file
-        """
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Choose a file name to load the expression"),
-                            wildcard = _("Expression file (*)|*"),
-                            style = wx.OPEN)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            if not path:
-                dlg.Destroy()
-                return
-
-            try:
-                fobj = open(path,'r')
-                mctxt = fobj.read()
-            finally:
-                fobj.close()
-            
-            try:
-                result, exp = mctxt.split('=', 1)
-            except ValueError:
-                result = ''
-                exp = mctxt
-            
-            self.newmaptxt.SetValue(result.strip())
-            self.text_mcalc.SetValue(exp.strip())
-            self.text_mcalc.SetFocus()
-            self.text_mcalc.SetInsertionPointEnd()
-        
-        dlg.Destroy()
-                
-    def OnClear(self, event):
-        """!Clears text area
-        """
-        self.text_mcalc.SetValue('')
-        
-    def OnHelp(self, event):
-        """!Launches r.mapcalc help
-        """
-        gcmd.RunCommand('g.manual', parent = self, entry = self.cmd)
-        
-    def OnClose(self,event):
-        """!Close window"""
-        self.Destroy()
-
-    def OnCmdDialog(self, event):
-        """!Shows command dialog"""
-        name = self.newmaptxt.GetValue().strip()
-        mctxt = self.text_mcalc.GetValue().strip().replace("\n"," ")
-        mctxt = mctxt.replace(" " , "")
-        expr = name
-        if expr:
-            expr += '='
-        expr += mctxt
-        
-        menuform.GUI(parent = self).ParseCommand(cmd = [self.cmd, 'expression=' + expr])
-        
-if __name__ == "__main__":
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    app = wx.App(0)
-    frame = MapCalcFrame(parent = None, cmd = 'r.mapcalc')
-    frame.Show()
-    app.MainLoop()

Deleted: grass/trunk/gui/wxpython/gui_modules/menu.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menu.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/menu.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,119 +0,0 @@
-"""!
- at package menu.py
-
- at brief Menu classes for wxGUI
-
-Classes:
- - Menu
-
-(C) 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 Martin Landa <landa.martin gmail.com>
- at author Pawel Netzel (menu customization)
- at author Milena Nowotarska (menu customization)
- at author Robert Szczepanek (menu customization)
- at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
-"""
-
-import wx
-
-import globalvar
-import utils
-
-from preferences import globalSettings as UserSettings
-
-class Menu(wx.MenuBar):
-    def __init__(self, parent, data):
-        """!Creates menubar"""
-        wx.MenuBar.__init__(self)
-        self.parent   = parent
-        self.menudata = data
-        self.menucmd  = dict()
-        
-        self.menustyle = UserSettings.Get(group='appearance', key='menustyle', subkey='selection')
-        
-        for eachMenuData in self.menudata.GetMenu():
-            for eachHeading in eachMenuData:
-                menuLabel = eachHeading[0]
-                menuItems = eachHeading[1]
-                self.Append(self._createMenu(menuItems), menuLabel)
-        
-    def _createMenu(self, menuData):
-        """!Creates menu"""
-        menu = wx.Menu()
-        for eachItem in menuData:
-            if len(eachItem) == 2:
-                label = eachItem[0]
-                subMenu = self._createMenu(eachItem[1])
-                menu.AppendMenu(wx.ID_ANY, label, subMenu)
-            else:
-                self._createMenuItem(menu, self.menustyle, *eachItem)
-        
-        self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
-        
-        return menu
-
-    def _createMenuItem(self, menu, menustyle, label, help, handler, gcmd, keywords,
-                        shortcut = '', wxId = wx.ID_ANY, kind = wx.ITEM_NORMAL):
-        """!Creates menu items
-        There are three menu styles (menu item text styles).
-        1 -- label only, 2 -- label and cmd name, 3 -- cmd name only
-        """
-        if not label:
-            menu.AppendSeparator()
-            return
-        
-        if len(gcmd) > 0:
-            helpString = gcmd + ' -- ' + help
-            if menustyle == 1:
-                label += '   [' + gcmd + ']'
-            elif menustyle == 2:
-                label = '      [' + gcmd + ']'
-        else:
-            helpString = help
-        
-        if shortcut:
-            label += '\t' + shortcut
-        
-        menuItem = menu.Append(wxId, label, helpString, kind)
-        
-        self.menucmd[menuItem.GetId()] = gcmd
-        
-        if gcmd: 
-            try: 
-                cmd = utils.split(str(gcmd)) 
-            except UnicodeError: 
-                cmd = utils.split(utils.EncodeString((gcmd))) 
-            if cmd and cmd[0] not in globalvar.grassCmd['all']: 
-                menuItem.Enable(False)
-        
-        rhandler = eval('self.parent.' + handler)
-        
-        self.parent.Bind(wx.EVT_MENU, rhandler, menuItem)
-
-    def GetData(self):
-        """!Get menu data"""
-        return self.menudata
-    
-    def GetCmd(self):
-        """!Get list of commands
-
-        @return list of commands
-        """
-        return self.menucmd
-        
-    def OnMenuHighlight(self, event):
-        """
-        Default menu help handler
-        """
-         # Show how to get menu item info from this event handler
-        id = event.GetMenuId()
-        item = self.FindItemById(id)
-        if item:
-            text = item.GetText()
-            help = item.GetHelp()
-
-        # but in this case just call Skip so the default is done
-        event.Skip()

Deleted: grass/trunk/gui/wxpython/gui_modules/menudata.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menudata.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/menudata.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,290 +0,0 @@
-"""!
- at package menudata.py
-
- at brief Complex list for menu entries for wxGUI.
-
-Classes:
- - MenuData
- - ManagerData
- - ModelerData
- - PsMapData
-
-Usage:
- at code
-python menudata.py [action] [manager|modeler]
- at endcode
-
-where <i>action</i>:
- - strings (default)
- - tree
- - commands
- - dump
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton (Arizona State University)
- at author Yann Chemin <yann.chemin gmail.com>
- at author Martin Landa <landa.martin gmail.com>
- at author Glynn Clements
- at author Anna Kratochvilova <kratochanna gmail.com>
-"""
-
-import os
-import sys
-import pprint
-try:
-    import xml.etree.ElementTree as etree
-except ImportError:
-    import elementtree.ElementTree as etree # Python <= 2.4
-
-import wx
-
-if not os.getenv("GISBASE"):
-    sys.exit("GRASS is not running. Exiting...")
-
-etcwxdir = os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython")
-
-class MenuData:
-    """!Abstract menu data class"""
-    def __init__(self, filename):
-	self.tree = etree.parse(filename)
-
-    def _getMenuItem(self, mi):
-        """!Get menu item
-
-        @param mi menu item instance
-        """
-	if mi.tag == 'separator':
-	    return ('', '', '', '', '')
-	elif mi.tag == 'menuitem':
-	    label    = _(mi.find('label').text)
-	    help     = _(mi.find('help').text)
-	    handler  = mi.find('handler').text
-	    gcmd     = mi.find('command')  # optional
-            keywords = mi.find('keywords') # optional
-            shortcut = mi.find('shortcut') # optional
-            wxId     = mi.find('id')       # optional
-	    if gcmd != None:
-		gcmd = gcmd.text
-	    else:
-		gcmd = ""
-            if keywords != None:
-                keywords = keywords.text
-            else:
-                keywords = ""
-            if shortcut != None:
-                shortcut = shortcut.text
-            else:
-                shortcut = ""
-            if wxId != None:
-                wxId = eval('wx.' + wxId.text)
-            else:
-                wxId = wx.ID_ANY
-	    return (label, help, handler, gcmd, keywords, shortcut, wxId)
-	elif mi.tag == 'menu':
-	    return self._getMenu(mi)
-	else:
-	    raise Exception(_("Unknow tag"))
-
-    def _getMenu(self, m):
-        """!Get menu
-
-        @param m menu
-
-        @return label, menu items
-        """
-	label = _(m.find('label').text)
-	items = m.find('items')
-	return (label, tuple(map(self._getMenuItem, items)))
-    
-    def _getMenuBar(self, mb):
-        """!Get menu bar
-
-        @param mb menu bar instance
-        
-        @return menu items
-        """
-	return tuple(map(self._getMenu, mb.findall('menu')))
-
-    def _getMenuData(self, md):
-        """!Get menu data
-
-        @param md menu data instace
-        
-        @return menu data
-        """
-	return list(map(self._getMenuBar, md.findall('menubar')))
-
-    def GetMenu(self):
-        """!Get menu
-
-        @return menu data
-        """
-	return self._getMenuData(self.tree.getroot())
-
-    def PrintStrings(self, fh):
-        """!Print menu strings to file (used for localization)
-
-        @param fh file descriptor"""
-        className = str(self.__class__).split('.', 1)[1]
-	fh.write('menustrings_%s = [\n' % className)
-	for node in self.tree.getiterator():
-	    if node.tag in ['label', 'help']:
-		fh.write('     _(%r),\n' % node.text)
-	fh.write('    \'\']\n')
-
-    def PrintTree(self, fh):
-        """!Print menu tree to file
-
-        @param fh file descriptor"""
-        level = 0
-        for eachMenuData in self.GetMenu():
-            for label, items in eachMenuData:
-                fh.write('- %s\n' % label.replace('&', ''))
-                self._PrintTreeItems(fh, level + 1, items)
-        
-    def _PrintTreeItems(self, fh, level, menuData):
-        """!Print menu tree items to file (used by PrintTree)
-
-        @param fh file descriptor
-        @param level menu level
-        @param menuData menu data to print out"""
-        for eachItem in menuData:
-            if len(eachItem) == 2:
-                if eachItem[0]:
-                    fh.write('%s - %s\n' % (' ' * level, eachItem[0]))
-                self._PrintTreeItems(fh, level + 1, eachItem[1])
-            else:
-                if eachItem[0]:
-                    fh.write('%s - %s\n' % (' ' * level, eachItem[0]))
-    
-    def PrintCommands(self, fh, itemSep = ' | ', menuSep = ' > '):
-        """!Print commands list (command | menu item > menu item)
-
-        @param fh file descriptor
-        """
-        level = 0
-        for eachMenuData in self.GetMenu():
-            for label, items in eachMenuData:
-                menuItems = [label, ]
-                self._PrintCommandsItems(fh, level + 1, items,
-                                         menuItems, itemSep, menuSep)
-        
-    def _PrintCommandsItems(self, fh, level, menuData,
-                             menuItems, itemSep, menuSep):
-        """!Print commands item (used by PrintCommands)
-
-        @param fh file descriptor
-        @param menuItems list of menu items
-        """
-        for eachItem in menuData:
-            if len(eachItem) == 2:
-                if eachItem[0]:
-                    try:
-                        menuItems[level] = eachItem[0]
-                    except IndexError:
-                        menuItems.append(eachItem[0])
-                self._PrintCommandsItems(fh, level + 1, eachItem[1],
-                                          menuItems, itemSep, menuSep)
-            else:
-                try:
-                    del menuItems[level]
-                except IndexError:
-                    pass
-                
-                if eachItem[3]:
-                    fh.write('%s%s' % (eachItem[3], itemSep))
-                    fh.write(menuSep.join(map(lambda x: x.replace('&', ''), menuItems)))
-                    fh.write('%s%s' % (menuSep, eachItem[0]))
-                    fh.write('\n')
-
-class ManagerData(MenuData):
-    def __init__(self, filename = None):
-        if not filename:
-            gisbase = os.getenv('GISBASE')
-            global etcwxdir
-	    filename = os.path.join(etcwxdir, 'xml', 'menudata.xml')
-        
-        MenuData.__init__(self, filename)
-        
-    def GetModules(self):
-        """!Create dictionary of modules used to search module by
-        keywords, description, etc."""
-        modules = dict()
-        
-        for node in self.tree.getiterator():
-            if node.tag == 'menuitem':
-                module = description = ''
-                keywords = []
-                for child in node.getchildren():
-                    if child.tag == 'help':
-                        description = child.text
-                    if child.tag == 'command':
-                        module = child.text
-                    if child.tag == 'keywords':
-                        if child.text:
-                            keywords = child.text.split(',')
-                    
-                if module:
-                    modules[module] = { 'desc': description,
-                                        'keywords' : keywords }
-                    if len(keywords) < 1:
-                        print >> sys.stderr, "WARNING: Module <%s> has no keywords" % module
-                
-        return modules
-
-class ModelerData(MenuData):
-    def __init__(self, filename = None):
-        if not filename:
-            gisbase = os.getenv('GISBASE')
-            global etcwxdir
-	    filename = os.path.join(etcwxdir, 'xml', 'menudata_modeler.xml')
-        
-        MenuData.__init__(self, filename)
-
-class PsMapData(MenuData):
-    def __init__(self, path = None):
-        """!Menu for Cartographic Composer (psmap.py)
-        
-        @path path to XML to be read (None for menudata_psmap.xml)
-        """
-        if not path:
-            gisbase = os.getenv('GISBASE')
-            global etcwxdir
-        path = os.path.join(etcwxdir, 'xml', 'menudata_psmap.xml')
-        
-        MenuData.__init__(self, path)
-
-if __name__ == "__main__":
-    import sys
-
-    # i18N
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
-
-    action = 'strings'
-    menu   = 'manager'
-    
-    for arg in sys.argv:
-        if arg in ('strings', 'tree', 'commands', 'dump'):
-            action =  arg
-        elif arg in ('manager', 'modeler'):
-            menu = arg
-    
-    if menu == 'manager':
-        data = ManagerData()
-    else:
-        data = ModelerData()
-    
-    if action == 'strings':
-        data.PrintStrings(sys.stdout)
-    elif action == 'tree':
-        data.PrintTree(sys.stdout)
-    elif action == 'commands':
-        data.PrintCommands(sys.stdout)
-    elif action == 'dump':
-	pprint.pprint(data.GetMenu(), stream = sys.stdout, indent = 2)
-    
-    sys.exit(0)

Deleted: grass/trunk/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menuform.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/menuform.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2318 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
- at brief Construct simple wxPython GUI from a GRASS command interface
-description.
-
-Classes:
- - helpPanel
- - mainFrame
- - cmdPanel
- - GrassGUIApp
- - GUI
- - FloatValidator
- - GNotebook
-
-This program is just a coarse approach to automatically build a GUI
-from a xml-based GRASS user interface description.
-
-You need to have Python 2.4, wxPython 2.8 and python-xml.
-
-The XML stream is read from executing the command given in the
-command line, thus you may call it for instance this way:
-
-python <this file.py> r.basins.fill
-
-Or you set an alias or wrap the call up in a nice shell script, GUI
-environment ... please contribute your idea.
-
-Updated to wxPython 2.8 syntax and contrib widgets.  Methods added to
-make it callable by gui.  Method added to automatically re-run with
-pythonw on a Mac.
-
- at todo
- - verify option value types
-
-Copyright(C) 2000-2011 by the GRASS Development Team
-This program is free software under the GPL(>=v2) Read the file
-COPYING coming with GRASS for details.
-
- at author Jan-Oliver Wagner <jan at intevation.de>
- at author Bernhard Reiter <bernhard at intevation.de>
- at author Michael Barton, Arizona State University
- at author Daniel Calvelo <dca.gis at gmail.com>
- at author Martin Landa <landa.martin at gmail.com>
- at author Luca Delucchi <lucadeluge at gmail.com>
-"""
-
-import sys
-import re
-import string
-import textwrap
-import os
-import time
-import types
-import copy
-import locale
-import types
-from threading import Thread
-import Queue
-import tempfile
-
-import globalvar
-import wx
-import wx.html
-try:
-    import wx.lib.agw.flatnotebook as FN
-except ImportError:
-    import wx.lib.flatnotebook as FN
-import wx.lib.colourselect as csel
-import wx.lib.filebrowsebutton as filebrowse
-import wx.lib.scrolledpanel as scrolled
-from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
-from wx.lib.newevent import NewEvent
-
-try:
-    import xml.etree.ElementTree as etree
-except ImportError:
-    import elementtree.ElementTree as etree # Python <= 2.4
-
-import gdialogs
-from ghelp import HelpPanel
-
-gisbase = os.getenv("GISBASE")
-if gisbase is None:
-    print >>sys.stderr, "We don't seem to be properly installed, or we are being run outside GRASS. Expect glitches."
-    gisbase = os.path.join(os.path.dirname(sys.argv[0]), os.path.pardir)
-    wxbase = gisbase
-else:
-    wxbase = os.path.join(globalvar.ETCWXDIR)
-
-sys.path.append(wxbase)
-
-from grass.script import core as grass
-from grass.script import task as gtask
-
-import gselect
-import gcmd
-import goutput
-import utils
-from preferences import globalSettings as UserSettings
-try:
-    import subprocess
-except:
-    from compat import subprocess
-
-wxUpdateDialog, EVT_DIALOG_UPDATE = NewEvent()
-
-# From lib/gis/col_str.c, except purple which is mentioned
-# there but not given RGB values
-str2rgb = {'aqua': (100, 128, 255),
-           'black': (0, 0, 0),
-           'blue': (0, 0, 255),
-           'brown': (180, 77, 25),
-           'cyan': (0, 255, 255),
-           'gray': (128, 128, 128),
-           'green': (0, 255, 0),
-           'grey': (128, 128, 128),
-           'indigo': (0, 128, 255),
-           'magenta': (255, 0, 255),
-           'orange': (255, 128, 0),
-           'purple': (128, 0, 128),
-           'red': (255, 0, 0),
-           'violet': (128, 0, 255),
-           'white': (255, 255, 255),
-           'yellow': (255, 255, 0)}
-rgb2str = {}
-for (s,r) in str2rgb.items():
-    rgb2str[ r ] = s
-
-"""!Hide some options in the GUI"""
-#_blackList = { 'enabled' : False,
-#               'items'   : { 'r.buffer' : {'params' : ['input', 'output'],
-#                                           'flags' : ['z', 'overwrite']}}}
-_blackList = { 'enabled' : False,
-               'items'   : {} }
-
-def color_resolve(color):
-    if len(color) > 0 and color[0] in "0123456789":
-        rgb = tuple(map(int, color.split(':')))
-        label = color
-    else:
-        # Convert color names to RGB
-        try:
-            rgb = str2rgb[color]
-            label = color
-        except KeyError:
-            rgb = (200, 200, 200)
-            label = _('Select Color')
-    return (rgb, label)
-
-def text_beautify(someString , width = 70):
-    """!Make really long texts shorter, clean up whitespace and remove
-    trailing punctuation.
-    """
-    if width > 0:
-        return escape_ampersand(string.strip(
-                os.linesep.join(textwrap.wrap(utils.normalize_whitespace(someString), width)),
-                ".,;:"))
-    else:
-        return escape_ampersand(string.strip(utils.normalize_whitespace(someString), ".,;:"))
-    
-def escape_ampersand(text):
-    """!Escapes ampersands with additional ampersand for GUI"""
-    return string.replace(text, "&", "&&")
-
-class UpdateThread(Thread):
-    """!Update dialog widgets in the thread"""
-    def __init__(self, parent, event, eventId, task):
-        Thread.__init__(self)
-        
-        self.parent = parent
-        self.event = event
-        self.eventId = eventId
-        self.task = task
-        self.setDaemon(True)
-        
-        # list of functions which updates the dialog
-        self.data = {}
-        
-    def run(self):
-        # get widget id
-        if not self.eventId:
-            for p in self.task.params:
-                if p.get('gisprompt', False) == False:
-                    continue
-                prompt = p.get('element', '')
-                if prompt == 'vector':
-                    name = p.get('name', '')
-                    if name in ('map', 'input'):
-                        self.eventId = p['wxId'][0]
-            if self.eventId is None:
-                return
-        
-        p = self.task.get_param(self.eventId, element = 'wxId', raiseError = False)
-        if not p or 'wxId-bind' not in p:
-            return
-        
-        # get widget prompt
-        pType = p.get('prompt', '')
-        if not pType:
-            return
-        
-        # check for map/input parameter
-        pMap = self.task.get_param('map', raiseError = False)
-        
-        if not pMap:
-            pMap = self.task.get_param('input', raiseError = False)
-        
-        if pMap:
-            map = pMap.get('value', '')
-        else:
-            map = None
-        
-        # avoid running db.describe several times
-        cparams = dict()
-        cparams[map] = { 'dbInfo' : None,
-                         'layers' : None, }
-        
-        # update reference widgets
-        for uid in p['wxId-bind']:
-            win = self.parent.FindWindowById(uid)
-            if not win:
-                continue
-            
-            name = win.GetName()
-            
-            map = layer = None
-            driver = db = table = None
-            if name in ('LayerSelect', 'ColumnSelect'):
-                if p.get('element', '') == 'vector': # -> vector
-                    # get map name
-                    map = p.get('value', '')
-                    
-                    # get layer
-                    for bid in p['wxId-bind']:
-                        p = self.task.get_param(bid, element = 'wxId', raiseError = False)
-                        if not p:
-                            continue
-                        
-                        if p.get('element', '') == 'layer':
-                            layer = p.get('value', '')
-                            if layer != '':
-                                layer = p.get('value', '')
-                            else:
-                                layer = p.get('default', '')
-                            break
-                        
-                elif p.get('element', '') == 'layer': # -> layer
-                    # get layer
-                    layer = p.get('value', '')
-                    if layer != '':
-                        layer = p.get('value', '')
-                    else:
-                        layer = p.get('default', '')
-                    
-                    # get map name
-                    pMapL = self.task.get_param(p['wxId'][0], element = 'wxId-bind', raiseError = False)
-                    if pMapL:
-                        map = pMapL.get('value', '')
-            
-            if name == 'TableSelect' or \
-                    (name == 'ColumnSelect' and not map):
-                pDriver = self.task.get_param('dbdriver', element = 'prompt', raiseError = False)
-                if pDriver:
-                    driver = pDriver.get('value', '')
-                pDb = self.task.get_param('dbname', element = 'prompt', raiseError = False)
-                if pDb:
-                    db = pDb.get('value', '')
-                if name == 'ColumnSelect':
-                    pTable = self.task.get_param('dbtable', element = 'element', raiseError = False)
-                    if pTable:
-                        table = pTable.get('value', '')
-
-            if name == 'LayerSelect':
-                # determine format
-                native = True
-                
-                for id in pMap['wxId']:
-                    winVec  = self.parent.FindWindowById(id)
-                    if winVec.GetName() == 'VectorFormat' and \
-                            winVec.GetSelection() != 0:
-                        native = False
-                        break
-                # TODO: update only if needed
-                if native:
-                    if map:
-                        self.data[win.InsertLayers] = { 'vector' : map }
-                    else:
-                        self.data[win.InsertLayers] = { }
-                else:
-                    if map:
-                        self.data[win.InsertLayers] = { 'dsn' : map.rstrip('@OGR') }
-                    else:
-                        self.data[win.InsertLayers] = { }
-            
-            elif name == 'TableSelect':
-                self.data[win.InsertTables] = { 'driver' : driver,
-                                                'database' : db }
-                
-            elif name == 'ColumnSelect':
-                if map:
-                    if map in cparams:
-                        if not cparams[map]['dbInfo']:
-                            cparams[map]['dbInfo'] = gselect.VectorDBInfo(map)
-                        self.data[win.InsertColumns] = { 'vector' : map, 'layer' : layer,
-                                                         'dbInfo' : cparams[map]['dbInfo'] }
-                else: # table
-                    if driver and db:
-                        self.data[win.InsertTableColumns] = { 'table' : pTable.get('value'),
-                                                              'driver' : driver,
-                                                              'database' : db }
-                    elif pTable:
-                        self.data[win.InsertTableColumns] = { 'table'  : pTable.get('value') }
-            
-            elif name == 'SubGroupSelect':
-                pGroup = self.task.get_param('group', element = 'element', raiseError = False)
-                if pGroup:
-                    self.data[win.Insert] = { 'group' : pGroup.get('value', '')}
-            
-            elif name == 'LocationSelect':
-                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
-                if pDbase:
-                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', '')}
-
-            elif name == 'MapsetSelect':
-                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
-                pLocation = self.task.get_param('location', element = 'element', raiseError = False)
-                if pDbase and pLocation:
-                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', ''),
-                                                   'location' : pLocation.get('value', '')}
-
-            elif name ==  'ProjSelect':
-                pDbase = self.task.get_param('dbase', element = 'element', raiseError = False)
-                pLocation = self.task.get_param('location', element = 'element', raiseError = False)
-                pMapset = self.task.get_param('mapset', element = 'element', raiseError = False)
-                if pDbase and pLocation and pMapset:
-                    self.data[win.UpdateItems] = { 'dbase' : pDbase.get('value', ''),
-                                                   'location' : pLocation.get('value', ''),
-                                                   'mapset' : pMapset.get('value', '')}
-            
-def UpdateDialog(parent, event, eventId, task):
-    return UpdateThread(parent, event, eventId, task)
-
-class UpdateQThread(Thread):
-    """!Update dialog widgets in the thread"""
-    requestId = 0
-    def __init__(self, parent, requestQ, resultQ, **kwds):
-        Thread.__init__(self, **kwds)
-        
-        self.parent = parent # cmdPanel
-        self.setDaemon(True)
-        
-        self.requestQ = requestQ
-        self.resultQ = resultQ
-        
-        self.start()
-        
-    def Update(self, callable, *args, **kwds):
-        UpdateQThread.requestId +=  1
-        
-        self.request = None
-        self.requestQ.put((UpdateQThread.requestId, callable, args, kwds))
-        
-        return UpdateQThread.requestId
-    
-    def run(self):
-        while True:
-            requestId, callable, args, kwds = self.requestQ.get()
-            
-            requestTime = time.time()
-            
-            self.request = callable(*args, **kwds)
-
-            self.resultQ.put((requestId, self.request.run()))
-           
-            if self.request:
-                event = wxUpdateDialog(data = self.request.data)
-                wx.PostEvent(self.parent, event)
-
-class mainFrame(wx.Frame):
-    """!This is the Frame containing the dialog for options input.
-
-    The dialog is organized in a notebook according to the guisections
-    defined by each GRASS command.
-
-    If run with a parent, it may Apply, Ok or Cancel; the latter two
-    close the dialog.  The former two trigger a callback.
-
-    If run standalone, it will allow execution of the command.
-
-    The command is checked and sent to the clipboard when clicking
-    'Copy'.
-    """
-    def __init__(self, parent, ID, task_description,
-                 get_dcmd = None, layer = None):
-        self.get_dcmd = get_dcmd
-        self.layer    = layer
-        self.task     = task_description
-        self.parent   = parent            # LayerTree | Modeler | None | ...
-        if parent and parent.GetName() ==  'Modeler':
-            self.modeler = self.parent
-        else:
-            self.modeler = None
-        
-        # module name + keywords
-        if self.task.name.split('.')[-1] in ('py', 'sh'):
-            title = str(self.task.name.rsplit('.',1)[0])
-        else:
-            title = self.task.name
-        try:
-            if self.task.keywords !=  ['']:
-                title +=   " [" + ', '.join(self.task.keywords) + "]"
-        except ValueError:
-            pass
-        
-        wx.Frame.__init__(self, parent = parent, id = ID, title = title,
-                          pos = wx.DefaultPosition, style = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL,
-                          name = "MainFrame")
-        
-        self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        # statusbar
-        self.CreateStatusBar()
-        
-        # icon
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_dialog.ico'), wx.BITMAP_TYPE_ICO))
-        
-        guisizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # set apropriate output window
-        if self.parent:
-            self.standalone = False
-        else:
-            self.standalone = True
-        
-        # logo + description
-        topsizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        # GRASS logo
-        self.logo = wx.StaticBitmap(parent = self.panel,
-                                    bitmap = wx.Bitmap(name = os.path.join(globalvar.ETCIMGDIR,
-                                                                           'grass_form.png'),
-                                                     type = wx.BITMAP_TYPE_PNG))
-        topsizer.Add(item = self.logo, proportion = 0, border = 3,
-                     flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL)
-        
-        # add module description
-        if self.task.label:
-            module_desc = self.task.label + ' ' + self.task.description
-        else:
-            module_desc = self.task.description
-        self.description = gdialogs.StaticWrapText(parent = self.panel,
-                                                   label = module_desc)
-        topsizer.Add(item = self.description, proportion = 1, border = 5,
-                     flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
-        
-        guisizer.Add(item = topsizer, proportion = 0, flag = wx.EXPAND)
-        
-        self.panel.SetSizerAndFit(guisizer)
-        self.Layout()
-        
-        # notebooks
-        self.notebookpanel = cmdPanel(parent = self.panel, task = self.task,
-                                      mainFrame = self)
-        self.goutput = self.notebookpanel.goutput
-        self.notebookpanel.OnUpdateValues = self.updateValuesHook
-        guisizer.Add(item = self.notebookpanel, proportion = 1, flag = wx.EXPAND)
-        
-        # status bar
-        status_text = _("Enter parameters for '") + self.task.name + "'"
-        try:
-            self.task.get_cmd()
-            self.updateValuesHook()
-        except ValueError:
-            self.SetStatusText(status_text)
-        
-        # buttons
-        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-        # cancel
-        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-        self.btn_cancel.SetToolTipString(_("Close this window without executing the command (Ctrl+Q)"))
-        btnsizer.Add(item = self.btn_cancel, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10)
-        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-
-        if self.get_dcmd is not None: # A callback has been set up
-            btn_apply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
-            btn_ok = wx.Button(parent = self.panel, id = wx.ID_OK)
-            btn_ok.SetDefault()
-
-            btnsizer.Add(item = btn_apply, proportion = 0,
-                         flag = wx.ALL | wx.ALIGN_CENTER,
-                         border = 10)
-            btnsizer.Add(item = btn_ok, proportion = 0,
-                         flag = wx.ALL | wx.ALIGN_CENTER,
-                         border = 10)
-            
-            btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
-            btn_ok.Bind(wx.EVT_BUTTON, self.OnOK)
-        else: # We're standalone
-            # run
-            self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label =  _("&Run"))
-            self.btn_run.SetToolTipString(_("Run the command (Ctrl+R)"))
-            self.btn_run.SetDefault()
-            self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
-            
-            # copy
-            self.btn_clipboard = wx.Button(parent = self.panel, id = wx.ID_COPY)
-            self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
-            
-            btnsizer.Add(item = self.btn_run, proportion = 0,
-                         flag = wx.ALL | wx.ALIGN_CENTER,
-                         border = 10)
-            
-            btnsizer.Add(item = self.btn_clipboard, proportion = 0,
-                         flag = wx.ALL | wx.ALIGN_CENTER,
-                         border = 10)
-            
-            self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
-            self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
-        # help
-        self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
-        self.btn_help.SetToolTipString(_("Show manual page of the command (Ctrl+H)"))
-        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
-        if self.notebookpanel.notebook.GetPageIndexByName('manual') < 0:
-            self.btn_help.Hide()
-        
-        # add help button
-        btnsizer.Add(item = self.btn_help, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 10)
-        
-        guisizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT,
-                     border = 30)
-        
-        if self.parent and not self.modeler:
-            addLayer = False
-            for p in self.task.params:
-                if p.get('age', 'old') ==  'new' and \
-                   p.get('prompt', '') in ('raster', 'vector', '3d-raster'):
-                    addLayer = True
-            
-            if addLayer:
-                # add newly created map into layer tree
-                self.addbox = wx.CheckBox(parent = self.panel,
-                                          label = _('Add created map(s) into layer tree'), style = wx.NO_BORDER)
-                self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
-                guisizer.Add(item = self.addbox, proportion = 0,
-                             flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                             border = 5)
-        
-        hasNew = False
-        for p in self.task.params:
-            if p.get('age', 'old') ==  'new':
-                hasNew = True
-                break
-        
-        if self.get_dcmd is None and hasNew:
-            # close dialog when command is terminated
-            self.closebox = wx.CheckBox(parent = self.panel,
-                                        label = _('Close dialog on finish'), style = wx.NO_BORDER)
-            self.closebox.SetValue(UserSettings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
-            self.closebox.SetToolTipString(_("Close dialog when command is successfully finished. "
-                                             "Change this settings in Preferences dialog ('Command' tab)."))
-            guisizer.Add(item = self.closebox, proportion = 0,
-                         flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                         border = 5)
-        
-        self.Bind(wx.EVT_CLOSE,  self.OnCancel)
-        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
-        
-        # do layout
-        # called automatically by SetSizer()
-        self.panel.SetAutoLayout(True) 
-        self.panel.SetSizerAndFit(guisizer)
-        
-        sizeFrame = self.GetBestSize()
-        self.SetMinSize(sizeFrame)
-        
-        if hasattr(self, "closebox"):
-            scale = 0.33
-        else:
-            scale = 0.50
-        self.SetSize(wx.Size(sizeFrame[0], sizeFrame[1] + scale * max(self.notebookpanel.panelMinHeight,
-                                                                      self.notebookpanel.constrained_size[1])))
-        
-        # thread to update dialog
-        # create queues
-        self.requestQ = Queue.Queue()
-        self.resultQ = Queue.Queue()
-        self.updateThread = UpdateQThread(self.notebookpanel, self.requestQ, self.resultQ)
-        
-        self.Layout()
-        
-        # keep initial window size limited for small screens
-        width, height = self.GetSizeTuple()
-        self.SetSize(wx.Size(min(width, 650),
-                             min(height, 500)))
-        
-        # fix goutput's pane size (required for Mac OSX)
-        if self.goutput:  	 	 
-            self.goutput.SetSashPosition(int(self.GetSize()[1] * .75))
-        
-    def updateValuesHook(self, event = None):
-        """!Update status bar data"""
-        self.SetStatusText(' '.join(self.notebookpanel.createCmd(ignoreErrors = True)))
-        if event:
-            event.Skip()
-        
-    def OnKeyUp(self, event):
-        """!Key released (check hot-keys)"""
-        try:
-            kc = chr(event.GetKeyCode())
-        except ValueError:
-            event.Skip()
-            return
-        
-        if not event.ControlDown():
-            event.Skip()
-            return
-        
-        if kc ==  'Q':
-            self.OnCancel(None)
-        elif kc ==  'S':
-            self.OnAbort(None)
-        elif kc ==  'H':
-            self.OnHelp(None)
-        elif kc ==  'R':
-            self.OnRun(None)
-        elif kc ==  'C':
-            self.OnCopy(None)
-        
-        event.Skip()
-
-    def OnDone(self, cmd, returncode):
-        """!This function is launched from OnRun() when command is
-        finished
-
-        @param returncode command's return code (0 for success)
-        """
-        if not self.parent or returncode !=  0:
-            return
-        if self.parent.GetName() not in ('LayerTree', 'LayerManager'):
-            return
-        
-        if self.parent.GetName() ==  'LayerTree':
-            display = self.parent.GetMapDisplay()
-        else: # Layer Manager
-            display = self.parent.GetLayerTree().GetMapDisplay()
-            
-        if not display or not display.IsAutoRendered():
-            return
-        
-        mapLayers = map(lambda x: x.GetName(),
-                        display.GetMap().GetListOfLayers(l_type = 'raster') +
-                        display.GetMap().GetListOfLayers(l_type = 'vector'))
-        
-        task = GUI(show = None).ParseCommand(cmd)
-        for p in task.get_options()['params']:
-            if p.get('prompt', '') not in ('raster', 'vector'):
-                continue
-            mapName = p.get('value', '')
-            if '@' not in mapName:
-                mapName = mapName + '@' + grass.gisenv()['MAPSET']
-            if mapName in mapLayers:
-                display.GetWindow().UpdateMap(render = True)
-                return
-        
-    def OnOK(self, event):
-        """!OK button pressed"""
-        cmd = self.OnApply(event)
-        if cmd is not None and self.get_dcmd is not None:
-            self.OnCancel(event)
-
-    def OnApply(self, event):
-        """!Apply the command"""
-        if self.modeler:
-            cmd = self.createCmd(ignoreErrors = True, ignoreRequired = True)
-        else:
-            cmd = self.createCmd()
-        
-        if cmd is not None and self.get_dcmd is not None:
-            # return d.* command to layer tree for rendering
-            self.get_dcmd(cmd, self.layer, {"params": self.task.params, 
-                                            "flags" : self.task.flags},
-                          self)
-            # echo d.* command to output console
-            # self.parent.writeDCommand(cmd)
-
-        return cmd
-
-    def OnRun(self, event):
-        """!Run the command"""
-        cmd = self.createCmd()
-        
-        if not cmd or len(cmd) < 1:
-            return
-        
-        ret = 0
-        if self.standalone or cmd[0][0:2] !=  "d.":
-            # Send any non-display command to parent window (probably wxgui.py)
-            # put to parents switch to 'Command output'
-            self.notebookpanel.notebook.SetSelectionByName('output')
-            
-            try:
-                if self.task.path:
-                    cmd[0] = self.task.path # full path
-                
-                ret = self.goutput.RunCmd(cmd, onDone = self.OnDone)
-            except AttributeError, e:
-                print >> sys.stderr, "%s: Probably not running in wxgui.py session?" % (e)
-                print >> sys.stderr, "parent window is: %s" % (str(self.parent))
-        else:
-            gcmd.Command(cmd)
-        
-        if ret != 0:
-            self.notebookpanel.notebook.SetSelection(0)
-            return
-        
-        # update buttons status
-        for btn in (self.btn_run,
-                    self.btn_cancel,
-                    self.btn_clipboard,
-                    self.btn_help):
-            btn.Enable(False)
-        
-    def OnAbort(self, event):
-        """!Abort running command"""
-        event = goutput.wxCmdAbort(aborted = True)
-        wx.PostEvent(self.goutput, event)
-
-    def OnCopy(self, event):
-        """!Copy the command"""
-        cmddata = wx.TextDataObject()
-        # list -> string
-        cmdstring = ' '.join(self.createCmd(ignoreErrors = True))
-        cmddata.SetText(cmdstring)
-        if wx.TheClipboard.Open():
-#            wx.TheClipboard.UsePrimarySelection(True)
-            wx.TheClipboard.SetData(cmddata)
-            wx.TheClipboard.Close()
-            self.SetStatusText(_("'%s' copied to clipboard") % \
-                                    (cmdstring))
-
-    def OnCancel(self, event):
-        """!Cancel button pressed"""
-        self.MakeModal(False)
-        
-        if self.get_dcmd and \
-                self.parent and \
-                self.parent.GetName() in ('LayerTree',
-                                          'MapWindow'):
-            # display decorations and 
-            # pressing OK or cancel after setting layer properties
-            if self.task.name in ['d.barscale','d.legend','d.histogram'] \
-                or len(self.parent.GetPyData(self.layer)[0]['cmd']) >=  1:
-                self.Hide()
-            # canceled layer with nothing set
-            elif len(self.parent.GetPyData(self.layer)[0]['cmd']) < 1:
-                self.parent.Delete(self.layer)
-                self.Destroy()
-        else:
-            # cancel for non-display commands
-            self.Destroy()
-
-    def OnHelp(self, event):
-        """!Show manual page (switch to the 'Manual' notebook page)"""
-        if self.notebookpanel.notebook.GetPageIndexByName('manual') > -1:
-            self.notebookpanel.notebook.SetSelectionByName('manual')
-            self.notebookpanel.OnPageChange(None)
-        
-        if event:    
-            event.Skip()
-        
-    def createCmd(self, ignoreErrors = False, ignoreRequired = False):
-        """!Create command string (python list)"""
-        return self.notebookpanel.createCmd(ignoreErrors = ignoreErrors,
-                                            ignoreRequired = ignoreRequired)
-
-class cmdPanel(wx.Panel):
-    """!A panel containing a notebook dividing in tabs the different
-    guisections of the GRASS cmd.
-    """
-    def __init__(self, parent, task, id = wx.ID_ANY, mainFrame = None, *args, **kwargs):
-        if mainFrame:
-            self.parent = mainFrame
-        else:
-            self.parent = parent
-        self.task = task
-        
-        wx.Panel.__init__(self, parent, id = id, *args, **kwargs)
-        
-        # Determine tab layout
-        sections = []
-        is_section = {}
-        not_hidden = [ p for p in self.task.params + self.task.flags if not p.get('hidden', False) ==  True ]
-
-        self.label_id = [] # wrap titles on resize
-
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        
-        for task in not_hidden:
-            if task.get('required', False):
-                # All required go into Main, even if they had defined another guisection
-                task['guisection'] = _('Required')
-            if task.get('guisection','') ==  '':
-                # Undefined guisections end up into Options
-                task['guisection'] = _('Optional')
-            if task['guisection'] not in is_section:
-                # We do it like this to keep the original order, except for Main which goes first
-                is_section[task['guisection']] = 1
-                sections.append(task['guisection'])
-            else:
-                is_section[ task['guisection'] ] +=  1
-        del is_section
-
-        # 'Required' tab goes first, 'Optional' as the last one
-        for (newidx,content) in [ (0,_('Required')), (len(sections)-1,_('Optional')) ]:
-            if content in sections:
-                idx = sections.index(content)
-                sections[idx:idx+1] = []
-                sections[newidx:newidx] =  [content]
-
-        panelsizer = wx.BoxSizer(orient = wx.VERTICAL)
-
-        # Build notebook
-        self.notebook = GNotebook(self, style = globalvar.FNPageStyle)
-        self.notebook.SetTabAreaColour(globalvar.FNPageColor)
-        self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChange)
-
-        tab = {}
-        tabsizer = {}
-        for section in sections:
-            tab[section] = scrolled.ScrolledPanel(parent = self.notebook)
-            tab[section].SetScrollRate(10, 10)
-            tabsizer[section] = wx.BoxSizer(orient = wx.VERTICAL)
-            self.notebook.AddPage(page = tab[section], text = section)
-
-        # are we running from command line?
-        ### add 'command output' tab regardless standalone dialog
-        if self.parent.GetName() ==  "MainFrame" and self.parent.get_dcmd is None:
-            self.goutput = goutput.GMConsole(parent = self, margin = False)
-            self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
-        else:
-            self.goutput = None
-        
-        self.manual_tab = HelpPanel(parent = self, grass_command = self.task.name)
-        if not self.manual_tab.IsFile():
-            self.manual_tab.Hide()
-        else:
-            self.notebook.AddPage(page = self.manual_tab, text = _("Manual"), name = 'manual')
-        
-        self.notebook.SetSelection(0)
-
-        panelsizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND)
-
-        #
-        # flags
-        #
-        text_style = wx.FONTWEIGHT_NORMAL
-        visible_flags = [ f for f in self.task.flags if not f.get('hidden', False) ==  True ]
-        for f in visible_flags:
-            which_sizer = tabsizer[ f['guisection'] ]
-            which_panel = tab[ f['guisection'] ]
-            # if label is given: description -> tooltip
-            if f.get('label','') !=  '':
-                title = text_beautify(f['label'])
-                tooltip = text_beautify(f['description'], width = -1)
-            else:
-                title = text_beautify(f['description'])
-                tooltip = None
-            title_sizer = wx.BoxSizer(wx.HORIZONTAL)
-            rtitle_txt = wx.StaticText(parent = which_panel,
-                                       label = '(' + f['name'] + ')')
-            chk = wx.CheckBox(parent = which_panel, label = title, style = wx.NO_BORDER)
-            self.label_id.append(chk.GetId())
-            if tooltip:
-                chk.SetToolTipString(tooltip)
-            chk.SetValue(f.get('value', False))
-            title_sizer.Add(item = chk, proportion = 1,
-                            flag = wx.EXPAND)
-            title_sizer.Add(item = rtitle_txt, proportion = 0,
-                            flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
-            which_sizer.Add(item = title_sizer, proportion = 0,
-                            flag = wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border = 5)
-            f['wxId'] = [ chk.GetId(), ]
-            chk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
-            
-            if self.parent.GetName() ==  'MainFrame' and self.parent.modeler:
-                parChk = wx.CheckBox(parent = which_panel, id = wx.ID_ANY,
-                                     label = _("Parameterized in model"))
-                parChk.SetName('ModelParam')
-                parChk.SetValue(f.get('parameterized', False))
-                if 'wxId' in f:
-                    f['wxId'].append(parChk.GetId())
-                else:
-                    f['wxId'] = [ parChk.GetId() ]
-                parChk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
-                which_sizer.Add(item = parChk, proportion = 0,
-                                flag = wx.LEFT, border = 20)
-            
-            if f['name'] in ('verbose', 'quiet'):
-                chk.Bind(wx.EVT_CHECKBOX, self.OnVerbosity)
-                vq = UserSettings.Get(group = 'cmd', key = 'verbosity', subkey = 'selection')
-                if f['name'] ==  vq:
-                    chk.SetValue(True)
-                    f['value'] = True
-            elif f['name'] ==  'overwrite' and 'value' not in f:
-                chk.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
-                f['value'] = UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled')
-                
-        #
-        # parameters
-        #
-        visible_params = [ p for p in self.task.params if not p.get('hidden', False) ==  True ]
-        
-        try:
-            first_param = visible_params[0]
-        except IndexError:
-            first_param = None
-        
-        for p in visible_params:
-            which_sizer = tabsizer[ p['guisection'] ]
-            which_panel = tab[ p['guisection'] ]
-            # if label is given -> label and description -> tooltip
-            # otherwise description -> lavel
-            if p.get('label','') !=  '':
-                title = text_beautify(p['label'])
-                tooltip = text_beautify(p['description'], width = -1)
-            else:
-                title = text_beautify(p['description'])
-                tooltip = None
-            txt = None
-
-            # text style (required -> bold)
-            if not p.get('required', False):
-                text_style = wx.FONTWEIGHT_NORMAL
-            else:
-                text_style = wx.FONTWEIGHT_BOLD
-
-            # title sizer (description, name, type)
-            if (len(p.get('values', [])) > 0) and \
-                    p.get('multiple', False) and \
-                    p.get('gisprompt',False) ==  False and \
-                    p.get('type', '') ==  'string':
-                title_txt = wx.StaticBox(parent = which_panel, id = wx.ID_ANY)
-            else:
-                title_sizer = wx.BoxSizer(wx.HORIZONTAL)
-                title_txt = wx.StaticText(parent = which_panel)
-                if p['key_desc']:
-                    ltype = ','.join(p['key_desc'])
-                else:
-                    ltype = p['type']
-                rtitle_txt = wx.StaticText(parent = which_panel,
-                                           label = '(' + p['name'] + '=' + ltype + ')')
-                title_sizer.Add(item = title_txt, proportion = 1,
-                                flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-                title_sizer.Add(item = rtitle_txt, proportion = 0,
-                                flag = wx.ALIGN_RIGHT | wx.RIGHT | wx.TOP, border = 5)
-                which_sizer.Add(item = title_sizer, proportion = 0,
-                                flag = wx.EXPAND)
-            self.label_id.append(title_txt.GetId())
-
-            # title expansion
-            if p.get('multiple', False) and len(p.get('values','')) ==  0:
-                title = _("[multiple]") + " " + title
-                if p.get('value','') ==   '' :
-                    p['value'] = p.get('default','')
-
-            if (len(p.get('values', [])) > 0):
-                valuelist      = map(str, p.get('values',[]))
-                valuelist_desc = map(unicode, p.get('values_desc',[]))
-
-                if p.get('multiple', False) and \
-                        p.get('gisprompt',False) ==  False and \
-                        p.get('type', '') ==  'string':
-                    title_txt.SetLabel(" %s: (%s, %s) " % (title, p['name'], p['type']))
-                    if valuelist_desc:
-                        hSizer = wx.StaticBoxSizer(box = title_txt, orient = wx.VERTICAL)
-                    else:
-                        hSizer = wx.StaticBoxSizer(box = title_txt, orient = wx.HORIZONTAL)
-                    isEnabled = {}
-                    # copy default values
-                    if p['value'] ==  '':
-                        p['value'] = p.get('default', '')
-                        
-                    for defval in p.get('value', '').split(','):
-                        isEnabled[ defval ] = 'yes'
-                        # for multi checkboxes, this is an array of all wx IDs
-                        # for each individual checkbox
-                        p[ 'wxId' ] = list()
-                    idx = 0
-                    for val in valuelist:
-                        try:
-                            label = valuelist_desc[idx]
-                        except IndexError:
-                            label = val
-                        
-                        chkbox = wx.CheckBox(parent = which_panel,
-                                             label = text_beautify(label))
-                        p[ 'wxId' ].append(chkbox.GetId())
-                        if val in isEnabled:
-                            chkbox.SetValue(True)
-                        hSizer.Add(item = chkbox, proportion = 0,
-                                    flag = wx.ADJUST_MINSIZE | wx.ALL, border = 1)
-                        chkbox.Bind(wx.EVT_CHECKBOX, self.OnCheckBoxMulti)
-                        idx +=  1
-                        
-                    which_sizer.Add(item = hSizer, proportion = 0,
-                                    flag = wx.EXPAND | wx.TOP | wx.RIGHT | wx.LEFT, border = 5)
-                elif p.get('gisprompt', False) ==  False:
-                    if len(valuelist) ==  1: # -> textctrl
-                        title_txt.SetLabel("%s (%s %s):" % (title, _('valid range'),
-                                                            str(valuelist[0])))
-                        
-                        if p.get('type', '') ==  'integer' and \
-                                not p.get('multiple', False):
-
-                            # for multiple integers use textctrl instead of spinsctrl
-                            try:
-                                minValue, maxValue = map(int, valuelist[0].split('-'))
-                            except ValueError:
-                                minValue = -1e6
-                                maxValue = 1e6
-                            txt2 = wx.SpinCtrl(parent = which_panel, id = wx.ID_ANY, size = globalvar.DIALOG_SPIN_SIZE,
-                                               min = minValue, max = maxValue)
-                            txt2.SetName("SpinCtrl")
-                            style = wx.BOTTOM | wx.LEFT
-                        else:
-                            txt2 = wx.TextCtrl(parent = which_panel, value = p.get('default',''))
-                            txt2.SetName("TextCtrl")
-                            style = wx.EXPAND | wx.BOTTOM | wx.LEFT
-                        
-                        value = self._getValue(p)
-                        # parameter previously set
-                        if value:
-                            if txt2.GetName() ==  "SpinCtrl":
-                                txt2.SetValue(int(value))
-                            else:
-                                txt2.SetValue(value)
-                        
-                        which_sizer.Add(item = txt2, proportion = 0,
-                                        flag = style, border = 5)
-
-                        p['wxId'] = [ txt2.GetId(), ]
-                        txt2.Bind(wx.EVT_TEXT, self.OnSetValue)
-                    else:
-                        # list of values (combo)
-                        title_txt.SetLabel(title + ':')
-                        cb = wx.ComboBox(parent = which_panel, id = wx.ID_ANY, value = p.get('default',''),
-                                         size = globalvar.DIALOG_COMBOBOX_SIZE,
-                                         choices = valuelist, style = wx.CB_DROPDOWN)
-                        value = self._getValue(p)
-                        if value:
-                            cb.SetValue(value) # parameter previously set
-                        which_sizer.Add(item = cb, proportion = 0,
-                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
-                        p['wxId'] = [cb.GetId(),]
-                        cb.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                        cb.Bind(wx.EVT_TEXT, self.OnSetValue)
-            
-            # text entry
-            if (p.get('type','string') in ('string','integer','float')
-                and len(p.get('values',[])) ==  0
-                and p.get('gisprompt',False) ==  False
-                and p.get('prompt','') !=  'color'):
-
-                title_txt.SetLabel(title + ':')
-                if p.get('multiple', False) or \
-                        p.get('type', 'string') ==  'string' or \
-                        len(p.get('key_desc', [])) > 1:
-                    txt3 = wx.TextCtrl(parent = which_panel, value = p.get('default',''))
-                    
-                    value = self._getValue(p)
-                    if value:
-                        # parameter previously set
-                        txt3.SetValue(str(value))
-                    
-                    txt3.Bind(wx.EVT_TEXT, self.OnSetValue)
-                    style = wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT
-                else:
-                    minValue = -1e9
-                    maxValue = 1e9
-                    if p.get('type', '') ==  'integer':
-                        txt3 = wx.SpinCtrl(parent = which_panel, value = p.get('default',''),
-                                           size = globalvar.DIALOG_SPIN_SIZE,
-                                           min = minValue, max = maxValue)
-                        style = wx.BOTTOM | wx.LEFT | wx.RIGHT
-                        
-                        value = self._getValue(p)
-                        if value:
-                            txt3.SetValue(int(value)) # parameter previously set
-                        
-                        txt3.Bind(wx.EVT_SPINCTRL, self.OnSetValue)
-                    else:
-                        txt3 = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
-                                           validator = FloatValidator())
-                        style = wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT
-                        
-                        value = self._getValue(p)
-                        if value:
-                            txt3.SetValue(str(value)) # parameter previously set
-                    
-                txt3.Bind(wx.EVT_TEXT, self.OnSetValue)
-                
-                which_sizer.Add(item = txt3, proportion = 0,
-                                flag = style, border = 5)
-                p['wxId'] = [ txt3.GetId(), ]
-
-            #
-            # element selection tree combobox (maps, icons, regions, etc.)
-            #
-            if p.get('gisprompt', False) ==  True:
-                title_txt.SetLabel(title + ':')
-                # GIS element entry
-                if p.get('prompt','') not in ('color',
-                                              'color_none',
-                                              'subgroup',
-                                              'dbdriver',
-                                              'dbname',
-                                              'dbtable',
-                                              'dbcolumn',
-                                              'layer',
-                                              'layer_all',
-                                              'location',
-                                              'mapset',
-                                              'dbase') and \
-                                              p.get('element', '') not in ('file', 'dir'):
-                    multiple = p.get('multiple', False)
-                    if p.get('age', '') ==  'new':
-                        mapsets = [grass.gisenv()['MAPSET'],]
-                    else:
-                        mapsets = None
-                    if self.task.name in ('r.proj', 'v.proj') \
-                            and p.get('name', '') ==  'input':
-                        if self.task.name ==  'r.proj':
-                            isRaster = True
-                        else:
-                            isRaster = False
-                        selection = gselect.ProjSelect(parent = which_panel,
-                                                       isRaster = isRaster)
-                        p['wxId'] = [ selection.GetId(), ]
-                        selection.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                        formatSelector = False
-                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                    else:
-                        selection = gselect.Select(parent = which_panel, id = wx.ID_ANY,
-                                                   size = globalvar.DIALOG_GSELECT_SIZE,
-                                                   type = p.get('element', ''),
-                                                   multiple = multiple, mapsets = mapsets,
-                                                   fullyQualified = p.get('age', 'old') == 'old')
-                        
-                        value = self._getValue(p)
-                        if value:
-                            selection.SetValue(value)
-                        
-                        formatSelector = True
-                        # A select.Select is a combobox with two children: a textctl and a popupwindow;
-                        # we target the textctl here
-                        textWin = selection.GetTextCtrl()
-                        p['wxId'] = [ textWin.GetId(), ]
-                        textWin.Bind(wx.EVT_TEXT, self.OnSetValue)
-                    
-                    if p.get('prompt', '') ==  'vector':
-                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                        
-                        # if formatSelector and p.get('age', 'old') ==  'old':
-                        #     # OGR supported (read-only)
-                        #     self.hsizer = wx.BoxSizer(wx.HORIZONTAL)
-                            
-                        #     self.hsizer.Add(item = selection,
-                        #                     flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
-                        #                     border = 5)
-                            
-                        #     # format (native / ogr)
-                        #     rbox = wx.RadioBox(parent = which_panel, id = wx.ID_ANY,
-                        #                        label = " %s " % _("Format"),
-                        #                        style = wx.RA_SPECIFY_ROWS,
-                        #                        choices = [_("Native / Linked OGR"), _("Direct OGR")])
-                        #     if p.get('value', '').lower().rfind('@ogr') > -1:
-                        #         rbox.SetSelection(1)
-                        #     rbox.SetName('VectorFormat')
-                        #     rbox.Bind(wx.EVT_RADIOBOX, self.OnVectorFormat)
-                            
-                        #     self.hsizer.Add(item = rbox,
-                        #                     flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT |
-                        #                     wx.RIGHT | wx.ALIGN_TOP,
-                        #                     border = 5)
-                            
-                        #     ogrSelection = gselect.GdalSelect(parent = self, panel = which_panel, ogr = True,
-                        #                                       default = 'dir',
-                        #                                       exclude = ['file'])
-                        #     self.Bind(gselect.EVT_GDALSELECT, self.OnUpdateSelection)
-                        #     self.Bind(gselect.EVT_GDALSELECT, self.OnSetValue)
-                            
-                        #     ogrSelection.SetName('OgrSelect')
-                        #     ogrSelection.Hide()
-                            
-                        #     which_sizer.Add(item = self.hsizer, proportion = 0)
-                            
-                        #     p['wxId'].append(rbox.GetId())
-                        #     p['wxId'].append(ogrSelection.GetId())
-                        #     for win in ogrSelection.GetDsnWin():
-                        #         p['wxId'].append(win.GetId())
-                        # else:
-                        which_sizer.Add(item = selection, proportion = 0,
-                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
-                                        border = 5)
-                    elif p.get('prompt', '') ==  'group':
-                        selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                        which_sizer.Add(item = selection, proportion = 0,
-                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
-                                        border = 5)
-                    else:
-                        which_sizer.Add(item = selection, proportion = 0,
-                                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
-                                        border = 5)
-                # subgroup
-                elif p.get('prompt', '') ==  'subgroup':
-                    selection = gselect.SubGroupSelect(parent = which_panel)
-                    p['wxId'] = [ selection.GetId() ]
-                    selection.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                    which_sizer.Add(item = selection, proportion = 0,
-                                    flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_VERTICAL,
-                                    border = 5)
-
-                # layer, dbdriver, dbname, dbcolumn, dbtable entry
-                elif p.get('prompt', '') in ('dbdriver',
-                                             'dbname',
-                                             'dbtable',
-                                             'dbcolumn',
-                                             'layer',
-                                             'layer_all',
-                                             'location',
-                                             'mapset',
-                                             'dbase'):
-                    if p.get('multiple', 'no') ==  'yes':
-                        win = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
-                                          size = globalvar.DIALOG_TEXTCTRL_SIZE)
-                        win.Bind(wx.EVT_TEXT, self.OnSetValue)
-                    else:
-                        value = self._getValue(p)
-                        
-                        if p.get('prompt', '') in ('layer',
-                                                   'layer_all'):
-                            if p.get('prompt', '') ==  'layer_all':
-                                all = True
-                            else:
-                                all = False
-                            if p.get('age', 'old') ==  'old':
-                                win = gselect.LayerSelect(parent = which_panel,
-                                                          all = all,
-                                                          default = p['default'])
-                                win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                                win.Bind(wx.EVT_TEXT, self.OnSetValue)
-                                win.SetValue(str(value))    # default or previously set value
-                            else:
-                                win = wx.SpinCtrl(parent = which_panel, id = wx.ID_ANY,
-                                                  min = 1, max = 100, initial = int(p['default']))
-                                win.Bind(wx.EVT_SPINCTRL, self.OnSetValue)
-                                win.SetValue(int(value))    # default or previously set value
-
-                            p['wxId'] = [ win.GetId() ]
-
-                        elif p.get('prompt', '') ==  'dbdriver':
-                            win = gselect.DriverSelect(parent = which_panel,
-                                                       choices = p.get('values', []),
-                                                       value = value)
-                            win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
-                            win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                        elif p.get('prompt', '') ==  'dbname':
-                            win = gselect.DatabaseSelect(parent = which_panel,
-                                                         value = value)
-                            win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                            win.Bind(wx.EVT_TEXT, self.OnSetValue)
-                        elif p.get('prompt', '') ==  'dbtable':
-                            if p.get('age', 'old') ==  'old':
-                                win = gselect.TableSelect(parent = which_panel)
-                                win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
-                                win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                            else:
-                                win = wx.TextCtrl(parent = which_panel, value = p.get('default',''),
-                                                  size = globalvar.DIALOG_TEXTCTRL_SIZE)
-                                win.Bind(wx.EVT_TEXT, self.OnSetValue)
-                        elif p.get('prompt', '') ==  'dbcolumn':
-                            win = gselect.ColumnSelect(parent = which_panel,
-                                                       value = value,
-                                                       param = p)
-                            win.Bind(wx.EVT_COMBOBOX, self.OnSetValue)
-                            win.Bind(wx.EVT_TEXT,     self.OnSetValue)
-
-                        elif p.get('prompt', '') ==  'location':
-                            win = gselect.LocationSelect(parent = which_panel,
-                                                         value = value)
-                            win.Bind(wx.EVT_COMBOBOX,     self.OnUpdateSelection)
-                            win.Bind(wx.EVT_COMBOBOX,     self.OnSetValue)
-                        
-                        elif p.get('prompt', '') == 'mapset':
-                            if p.get('age', 'old') == 'old':
-                                new = False
-                            else:
-                                new = True
-                            win = gselect.MapsetSelect(parent = which_panel,
-                                                       value = value, new = new)
-                            win.Bind(wx.EVT_COMBOBOX,     self.OnUpdateSelection)
-                            win.Bind(wx.EVT_COMBOBOX,     self.OnSetValue) 
-                            win.Bind(wx.EVT_TEXT,         self.OnSetValue)
-                            
-                        elif p.get('prompt', '') ==  'dbase':
-                            win = gselect.DbaseSelect(parent = which_panel,
-                                                      changeCallback = self.OnSetValue)
-                            win.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
-                            p['wxId'] = [ win.GetChildren()[1].GetId() ]
-                            
-                    if 'wxId' not in p:
-                        try:
-                            p['wxId'] = [ win.GetId(), ]
-                        except AttributeError:
-                            pass
-                    
-                    which_sizer.Add(item = win, proportion = 0,
-                                    flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
-                # color entry
-                elif p.get('prompt', '') in ('color',
-                                             'color_none'):
-                    default_color = (200,200,200)
-                    label_color = _("Select Color")
-                    if p.get('default','') !=  '':
-                        default_color, label_color = color_resolve(p['default'])
-                    if p.get('value','') !=  '': # parameter previously set
-                        default_color, label_color = color_resolve(p['value'])
-                    if p.get('prompt', '') ==  'color_none':
-                        this_sizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-                    else:
-                        this_sizer = which_sizer
-                    btn_colour = csel.ColourSelect(parent = which_panel, id = wx.ID_ANY,
-                                                   label = label_color, colour = default_color,
-                                                   pos = wx.DefaultPosition, size = (150,-1))
-                    this_sizer.Add(item = btn_colour, proportion = 0,
-                                   flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
-                    # For color selectors, this is a two-member array, holding the IDs of
-                    # the selector proper and either a "transparent" button or None
-                    p['wxId'] = [btn_colour.GetId(),]
-                    btn_colour.Bind(csel.EVT_COLOURSELECT,  self.OnColorChange)
-                    if p.get('prompt', '') ==  'color_none':
-                        none_check = wx.CheckBox(which_panel, wx.ID_ANY, _("Transparent"))
-                        if p.get('value','') !=  '' and p.get('value',[''])[0] ==  "none":
-                            none_check.SetValue(True)
-                        else:
-                            none_check.SetValue(False)
-                        this_sizer.Add(item = none_check, proportion = 0,
-                                       flag = wx.ADJUST_MINSIZE | wx.LEFT | wx.RIGHT | wx.TOP, border = 5)
-                        which_sizer.Add(this_sizer)
-                        none_check.Bind(wx.EVT_CHECKBOX, self.OnColorChange)
-                        p['wxId'].append(none_check.GetId())
-                    else:
-                        p['wxId'].append(None)
-                # file selector
-                elif p.get('prompt','') !=  'color' and p.get('element', '') ==  'file':
-                    if p.get('age', 'new') == 'new':
-                        fmode = wx.SAVE
-                    else:
-                        fmode = wx.OPEN
-                    fbb = filebrowse.FileBrowseButton(parent = which_panel, id = wx.ID_ANY, fileMask = '*',
-                                                      size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
-                                                      dialogTitle = _('Choose %s') % \
-                                                          p.get('description',_('File')),
-                                                      buttonText = _('Browse'),
-                                                      startDirectory = os.getcwd(), fileMode = fmode,
-                                                      changeCallback = self.OnSetValue)
-                    value = self._getValue(p)
-                    if value:
-                        fbb.SetValue(value) # parameter previously set
-                    which_sizer.Add(item = fbb, proportion = 0,
-                                    flag = wx.EXPAND | wx.RIGHT, border = 5)
-                    
-                    # A file browse button is a combobox with two children:
-                    # a textctl and a button;
-                    # we have to target the button here
-                    p['wxId'] = [ fbb.GetChildren()[1].GetId() ]
-                    if p.get('age', 'new') == 'old' and \
-                            UserSettings.Get(group = 'cmd', key = 'interactiveInput', subkey = 'enabled'):
-                        # widget for interactive input
-                        ifbb = wx.TextCtrl(parent = which_panel, id = wx.ID_ANY,
-                                           style = wx.TE_MULTILINE,
-                                           size = (-1, 75))
-                        if p.get('value', '') and os.path.isfile(p['value']):
-                            f = open(p['value'])
-                            ifbb.SetValue(''.join(f.readlines()))
-                            f.close()
-                        
-                        ifbb.Bind(wx.EVT_TEXT, self.OnFileText)
-                        
-                        btnLoad = wx.Button(parent = which_panel, id = wx.ID_ANY, label = _("&Load"))
-                        btnLoad.Bind(wx.EVT_BUTTON, self.OnFileLoad)
-                        btnSave = wx.Button(parent = which_panel, id = wx.ID_SAVEAS)
-                        btnSave.Bind(wx.EVT_BUTTON, self.OnFileSave)
-                        
-                        which_sizer.Add(item = wx.StaticText(parent = which_panel, id = wx.ID_ANY,
-                                                             label = _('or enter values interactively')),
-                                        proportion = 0,
-                                        flag = wx.EXPAND | wx.RIGHT | wx.LEFT | wx.BOTTOM, border = 5)
-                        which_sizer.Add(item = ifbb, proportion = 1,
-                                        flag = wx.EXPAND | wx.RIGHT | wx.LEFT, border = 5)
-                        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-                        btnSizer.Add(item = btnLoad, proportion = 0,
-                                     flag = wx.ALIGN_RIGHT | wx.RIGHT, border = 10)
-                        btnSizer.Add(item = btnSave, proportion = 0,
-                                     flag = wx.ALIGN_RIGHT)
-                        which_sizer.Add(item = btnSizer, proportion = 0,
-                                        flag = wx.ALIGN_RIGHT | wx.RIGHT | wx.TOP, border = 5)
-                        
-                        p['wxId'].append(ifbb.GetId())
-                        p['wxId'].append(btnLoad.GetId())
-                        p['wxId'].append(btnSave.GetId())
-                
-                # directory selector
-                elif p.get('prompt','') != 'color' and p.get('element', '') ==  'dir':
-                    fbb = filebrowse.DirBrowseButton(parent = which_panel, id = wx.ID_ANY,
-                                                     size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
-                                                     dialogTitle = _('Choose %s') % \
-                                                         p.get('description', _('Directory')),
-                                                     buttonText = _('Browse'),
-                                                     startDirectory = os.getcwd(),
-                                                     changeCallback = self.OnSetValue)
-                    value = self._getValue(p)
-                    if value:
-                        fbb.SetValue(value) # parameter previously set
-                    which_sizer.Add(item = fbb, proportion = 0,
-                                    flag = wx.EXPAND | wx.RIGHT, border = 5)
-                    
-                    # A file browse button is a combobox with two children:
-                    # a textctl and a button;
-                    # we have to target the button here
-                    p['wxId'] = [ fbb.GetChildren()[1].GetId() ]
-
-            if self.parent.GetName() == 'MainFrame' and self.parent.modeler:
-                parChk = wx.CheckBox(parent = which_panel, id = wx.ID_ANY,
-                                     label = _("Parameterized in model"))
-                parChk.SetName('ModelParam')
-                parChk.SetValue(p.get('parameterized', False))
-                if 'wxId' in p:
-                    p['wxId'].append(parChk.GetId())
-                else:
-                    p['wxId'] = [ parChk.GetId() ]
-                parChk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
-                which_sizer.Add(item = parChk, proportion = 0,
-                                flag = wx.LEFT, border = 20)
-                
-            if title_txt is not None:
-                # create tooltip if given
-                if len(p['values_desc']) > 0:
-                    if tooltip:
-                        tooltip +=  2 * os.linesep
-                    else:
-                        tooltip = ''
-                    if len(p['values']) ==  len(p['values_desc']):
-                        for i in range(len(p['values'])):
-                            tooltip +=  p['values'][i] + ': ' + p['values_desc'][i] + os.linesep
-                    tooltip.strip(os.linesep)
-                if tooltip:
-                    title_txt.SetToolTipString(tooltip)
-
-            if p ==  first_param:
-                if 'wxId' in p and len(p['wxId']) > 0:
-                    win = self.FindWindowById(p['wxId'][0])
-                    win.SetFocus()
-        
-        #
-        # set widget relations for OnUpdateSelection
-        #
-        pMap = None
-        pLayer = []
-        pDriver = None
-        pDatabase = None
-        pTable = None
-        pColumn = []
-        pGroup = None
-        pSubGroup = None
-        pDbase = None
-        pLocation = None
-        pMapset = None
-        for p in self.task.params:
-            if p.get('gisprompt', False) ==  False:
-                continue
-            
-            guidep = p.get('guidependency', '')
-            
-            if guidep:
-                # fixed options dependency defined
-                options = guidep.split(',')
-                for opt in options:
-                    pOpt = self.task.get_param(opt, element = 'name', raiseError = False)
-                    if id:
-                        if 'wxId-bind' not in p:
-                            p['wxId-bind'] = list()
-                        p['wxId-bind'] +=  pOpt['wxId']
-                continue
-            
-            prompt = p.get('element', '')
-            if prompt in ('cell', 'vector'):
-                name = p.get('name', '')
-                if name in ('map', 'input'):
-                    pMap = p
-            elif prompt ==  'layer':
-                pLayer.append(p)
-            elif prompt ==  'dbcolumn':
-                pColumn.append(p)
-            elif prompt ==  'dbdriver':
-                pDriver = p
-            elif prompt ==  'dbname':
-                pDatabase = p
-            elif prompt ==  'dbtable':
-                pTable = p
-            elif prompt ==  'group':
-                pGroup = p
-            elif prompt ==  'subgroup':
-                pSubGroup = p
-            elif prompt ==  'dbase':
-                pDbase = p
-            elif prompt ==  'location':
-                pLocation = p
-            elif prompt ==  'mapset':
-                pMapset = p
-        
-        # collect ids
-        pColumnIds = []
-        for p in pColumn:
-            pColumnIds +=  p['wxId']
-        pLayerIds = []
-        for p in pLayer:
-            pLayerIds +=  p['wxId']
-        
-        # set wxId-bindings
-        if pMap:
-            pMap['wxId-bind'] = copy.copy(pColumnIds)
-            if pLayer:
-                pMap['wxId-bind'] +=  pLayerIds
-        if pLayer:
-            for p in pLayer:
-                p['wxId-bind'] = copy.copy(pColumnIds)
-        
-        if pDriver and pTable:
-            pDriver['wxId-bind'] = pTable['wxId']
-
-        if pDatabase and pTable:
-            pDatabase['wxId-bind'] = pTable['wxId']
-
-        if pTable and pColumnIds:
-            pTable['wxId-bind'] = pColumnIds
-        
-        if pGroup and pSubGroup:
-            pGroup['wxId-bind'] = pSubGroup['wxId']
-
-        if pDbase and pLocation:
-            pDbase['wxId-bind'] = pLocation['wxId']
-
-        if pLocation and pMapset:
-            pLocation['wxId-bind'] = pMapset['wxId']
-        
-        if pLocation and pMapset and pMap:
-            pLocation['wxId-bind'] +=  pMap['wxId']
-            pMapset['wxId-bind'] = pMap['wxId']
-        
-	#
-	# determine panel size
-	#
-        maxsizes = (0, 0)
-        for section in sections:
-            tab[section].SetSizer(tabsizer[section])
-            tabsizer[section].Fit(tab[section])
-            tab[section].Layout()
-            minsecsizes = tabsizer[section].GetSize()
-            maxsizes = map(lambda x: max(maxsizes[x], minsecsizes[x]), (0, 1))
-
-        # TODO: be less arbitrary with these 600
-        self.panelMinHeight = 100
-        self.constrained_size = (min(600, maxsizes[0]) + 25, min(400, maxsizes[1]) + 25)
-        for section in sections:
-            tab[section].SetMinSize((self.constrained_size[0], self.panelMinHeight))
-        
-        if self.manual_tab.IsLoaded():
-            self.manual_tab.SetMinSize((self.constrained_size[0], self.panelMinHeight))
-        
-        self.SetSizer(panelsizer)
-        panelsizer.Fit(self.notebook)
-        
-        self.Bind(EVT_DIALOG_UPDATE, self.OnUpdateDialog)
-
-    def _getValue(self, p):
-        """!Get value or default value of given parameter
-
-        @param p parameter directory
-        """
-        if p.get('value', '') !=  '':
-            return p['value']
-        return p.get('default', '')
-        
-    def OnFileLoad(self, event):
-        """!Load file to interactive input"""
-        me = event.GetId()
-        win = dict()
-        for p in self.task.params:
-            if 'wxId' in p and me in p['wxId']:
-                win['file'] = self.FindWindowById(p['wxId'][0])
-                win['text'] = self.FindWindowById(p['wxId'][1])
-                break
-        
-        if not win:
-            return
-        
-        path = win['file'].GetValue()
-        if not path:
-            gcmd.GMessage(parent = self,
-                          message = _("Nothing to load."))
-            return
-        
-        data = ''
-        f = open(path, "r")
-        try:
-            data = f.read()
-        finally:
-            f.close()
-        
-        win['text'].SetValue(data)
-        
-    def OnFileSave(self, event):
-        """!Save interactive input to the file"""
-        wId = event.GetId()
-        win = {}
-        for p in self.task.params:
-            if wId in p.get('wxId', []):
-                win['file'] = self.FindWindowById(p['wxId'][0])
-                win['text'] = self.FindWindowById(p['wxId'][1])
-                break
-        
-        if not win:
-            return
-
-        text = win['text'].GetValue()
-        if not text:
-            gcmd.GMessage(parent = self,
-                          message = _("Nothing to save."))
-            return
-        
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Save input as..."),
-                            defaultDir = os.getcwd(),
-                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            f = open(path, "w")
-            try:
-                f.write(text + os.linesep)
-            finally:
-                f.close()
-            
-            win['file'].SetValue(path)
-        
-        dlg.Destroy()
-        
-    def OnFileText(self, event):
-        """File input interactively entered"""
-        text = event.GetString()
-        p = self.task.get_param(value = event.GetId(), element = 'wxId', raiseError = False)
-        if not p:
-            return # should not happen
-        win = self.FindWindowById(p['wxId'][0])
-        if text:
-            filename = win.GetValue()
-            if not filename:
-                # outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
-                filename = grass.tempfile()
-                win.SetValue(filename)
-                
-            f = open(filename, "w")
-            try:
-                f.write(text)
-                if text[-1] != os.linesep:
-                    f.write(os.linesep)
-            finally:
-                f.close()
-        else:
-            win.SetValue('')
-        
-    def OnVectorFormat(self, event):
-        """!Change vector format (native / ogr)"""
-        sel = event.GetSelection()
-        idEvent = event.GetId()
-        p = self.task.get_param(value = idEvent, element = 'wxId', raiseError = False)
-        if not p:
-            return # should not happen
-        
-        # detect windows
-        winNative = None
-        winOgr = None
-        for id in p['wxId']:
-            if id ==  idEvent:
-                continue
-            name = self.FindWindowById(id).GetName()
-            if name ==  'Select':
-                winNative = self.FindWindowById(id + 1)  # fix the mystery (also in nviz_tools.py)
-            elif name ==  'OgrSelect':
-                winOgr = self.FindWindowById(id)
-        
-        # enable / disable widgets & update values
-        rbox = self.FindWindowByName('VectorFormat')
-        self.hsizer.Remove(rbox)
-        if sel ==  0:   # -> native
-            winOgr.Hide()
-            self.hsizer.Remove(winOgr)
-            
-            self.hsizer.Add(item = winNative,
-                            flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
-                            border = 5)
-            winNative.Show()
-            p['value'] = winNative.GetValue()
-        
-        elif sel ==  1: # -> OGR
-            sizer = wx.BoxSizer(wx.VERTICAL)
-            
-            winNative.Hide()
-            self.hsizer.Remove(winNative)
-
-            sizer.Add(item = winOgr)
-            winOgr.Show()
-            p['value'] = winOgr.GetDsn()
-            
-            self.hsizer.Add(item = sizer,
-                            flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP,
-                            border = 5)
-        
-        self.hsizer.Add(item = rbox,
-                        flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT |
-                        wx.RIGHT | wx.ALIGN_TOP,
-                        border = 5)
-        
-        self.hsizer.Layout()
-        self.Layout()
-        self.OnUpdateValues()
-        self.OnUpdateSelection(event)
-        
-    def OnUpdateDialog(self, event):
-        for fn, kwargs in event.data.iteritems():
-            fn(**kwargs)
-        
-        self.parent.updateValuesHook()
-        
-    def OnVerbosity(self, event):
-        """!Verbosity level changed"""
-        verbose = self.FindWindowById(self.task.get_flag('verbose')['wxId'][0])
-        quiet = self.FindWindowById(self.task.get_flag('quiet')['wxId'][0])
-        if event.IsChecked():
-            if event.GetId() ==  verbose.GetId():
-                if quiet.IsChecked():
-                    quiet.SetValue(False)
-                    self.task.get_flag('quiet')['value'] = False
-            else:
-                if verbose.IsChecked():
-                    verbose.SetValue(False)
-                    self.task.get_flag('verbose')['value'] = False
-
-        event.Skip()
-
-    def OnPageChange(self, event):
-        if not event:
-            sel = self.notebook.GetSelection()
-        else:
-            sel = event.GetSelection()
-        
-        idx = self.notebook.GetPageIndexByName('manual')
-        if idx > -1 and sel ==  idx:
-            # calling LoadPage() is strangely time-consuming (only first call)
-            # FIXME: move to helpPage.__init__()
-            if not self.manual_tab.IsLoaded():
-                wx.Yield()
-                self.manual_tab.LoadPage()
-
-        self.Layout()
-
-    def OnColorChange(self, event):
-        myId = event.GetId()
-        for p in self.task.params:
-            if 'wxId' in p and myId in p['wxId']:
-                has_button = p['wxId'][1] is not None
-                if has_button and wx.FindWindowById(p['wxId'][1]).GetValue() ==  True:
-                    p[ 'value' ] = 'none'
-                else:
-                    colorchooser = wx.FindWindowById(p['wxId'][0])
-                    new_color = colorchooser.GetValue()[:]
-                    # This is weird: new_color is a 4-tuple and new_color[:] is a 3-tuple
-                    # under wx2.8.1
-                    new_label = rgb2str.get(new_color, ':'.join(map(str,new_color)))
-                    colorchooser.SetLabel(new_label)
-                    colorchooser.SetColour(new_color)
-                    colorchooser.Refresh()
-                    p[ 'value' ] = colorchooser.GetLabel()
-        self.OnUpdateValues()
-
-    def OnUpdateValues(self, event = None):
-        """!If we were part of a richer interface, report back the
-        current command being built.
-
-        This method should be set by the parent of this panel if
-        needed. It's a hook, actually.  Beware of what is 'self' in
-        the method def, though. It will be called with no arguments.
-        """
-        pass
-
-    def OnCheckBoxMulti(self, event):
-        """!Fill the values as a ','-separated string according to
-        current status of the checkboxes.
-        """
-        me = event.GetId()
-        theParam = None
-        for p in self.task.params:
-            if 'wxId' in p and me in p['wxId']:
-                theParam = p
-                myIndex = p['wxId'].index(me)
-
-        # Unpack current value list
-        currentValues = {}
-        for isThere in theParam.get('value', '').split(','):
-            currentValues[isThere] = 1
-        theValue = theParam['values'][myIndex]
-
-        if event.Checked():
-            currentValues[ theValue ] = 1
-        else:
-            del currentValues[ theValue ]
-
-        # Keep the original order, so that some defaults may be recovered
-        currentValueList = [] 
-        for v in theParam['values']:
-            if v in currentValues:
-                currentValueList.append(v)
-
-        # Pack it back
-        theParam['value'] = ','.join(currentValueList)
-
-        self.OnUpdateValues()
-
-    def OnSetValue(self, event):
-        """!Retrieve the widget value and set the task value field
-        accordingly.
-
-        Use for widgets that have a proper GetValue() method, i.e. not
-        for selectors.
-        """
-        myId = event.GetId()
-        me = wx.FindWindowById(myId)
-        name = me.GetName()
-
-        found = False
-        for porf in self.task.params + self.task.flags:
-            if 'wxId' not in porf:
-                continue
-            if myId in porf['wxId']:
-                found = True
-                break
-        
-        if not found:
-            return
-        
-        if name ==  'GdalSelect':
-            porf['value'] = event.dsn
-        elif name ==  'ModelParam':
-            porf['parameterized'] = me.IsChecked()
-        else:
-            porf['value'] = me.GetValue()
-
-        self.OnUpdateValues(event)
-        
-        event.Skip()
-        
-    def OnUpdateSelection(self, event):
-        """!Update dialog (layers, tables, columns, etc.)
-        """
-        if not hasattr(self.parent, "updateThread"):
-            if event:
-                event.Skip()
-            return
-        if event:
-            self.parent.updateThread.Update(UpdateDialog,
-                                            self,
-                                            event,
-                                            event.GetId(),
-                                            self.task)
-        else:
-            self.parent.updateThread.Update(UpdateDialog,
-                                            self,
-                                            None,
-                                            None,
-                                            self.task)
-            
-    def createCmd(self, ignoreErrors = False, ignoreRequired = False):
-        """!Produce a command line string (list) or feeding into GRASS.
-
-        @param ignoreErrors True then it will return whatever has been
-        built so far, even though it would not be a correct command
-        for GRASS
-        """
-        try:
-            cmd = self.task.get_cmd(ignoreErrors = ignoreErrors,
-                                   ignoreRequired = ignoreRequired)
-        except ValueError, err:
-            dlg = wx.MessageDialog(parent = self,
-                                   message = unicode(err),
-                                   caption = _("Error in %s") % self.task.name,
-                                   style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            dlg.ShowModal()
-            dlg.Destroy()
-            cmd = None
-        
-        return cmd
-    
-    def OnSize(self, event):
-        width = event.GetSize()[0]
-        fontsize = self.GetFont().GetPointSize()
-        text_width = max(width / (fontsize - 3), 70)
-        
-        for id in self.label_id:
-            win = self.FindWindowById(id)
-            label = win.GetLabel()
-            label_new = '\n'.join(textwrap.wrap(label, text_width))
-            win.SetLabel(label_new)
-            
-        event.Skip()
-        
-class GrassGUIApp(wx.App):
-    """!Stand-alone GRASS command GUI
-    """
-    def __init__(self, grass_task):
-        self.grass_task = grass_task
-        wx.App.__init__(self, False)
-        
-    def OnInit(self):
-        msg = self.grass_task.get_error_msg()
-        if msg:
-            gcmd.GError(msg + '\n\nTry to set up GRASS_ADDON_PATH variable.')
-            return True
-        
-        self.mf = mainFrame(parent = None, ID = wx.ID_ANY, task_description = self.grass_task)
-        self.mf.CentreOnScreen()
-        self.mf.Show(True)
-        self.SetTopWindow(self.mf)
-        
-        return True
-
-class GUI:
-    def __init__(self, parent = None, show = True, modal = False,
-                 centreOnParent = False, checkError = False):
-        """!Parses GRASS commands when module is imported and used from
-        Layer Manager.
-        """
-        self.parent = parent
-        self.show   = show
-        self.modal  = modal
-        self.centreOnParent = centreOnParent
-        self.checkError     = checkError
-        
-        self.grass_task = None
-        self.cmd = list()
-        
-        global _blackList
-        if self.parent:
-            _blackList['enabled'] = True
-        else:
-            _blackList['enabled'] = False
-        
-    def GetCmd(self):
-        """!Get validated command"""
-        return self.cmd
-    
-    def ParseCommand(self, cmd, gmpath = None, completed = None):
-        """!Parse command
-        
-        Note: cmd is given as list
-        
-        If command is given with options, return validated cmd list:
-         - add key name for first parameter if not given
-         - change mapname to mapname at mapset
-        """
-        start = time.time()
-        dcmd_params = {}
-        if completed == None:
-            get_dcmd = None
-            layer = None
-            dcmd_params = None
-        else:
-            get_dcmd = completed[0]
-            layer = completed[1]
-            if completed[2]:
-                dcmd_params.update(completed[2])
-        
-        # parse the interface decription
-        try:
-            global _blackList
-            self.grass_task = gtask.parse_interface(cmd[0],
-                                                    blackList = _blackList)
-        except ValueError, e: #grass.ScriptError, e:
-            gcmd.GError(e.value)
-            return
-        
-        # if layer parameters previously set, re-insert them into dialog
-        if completed is not None:
-            if 'params' in dcmd_params:
-                self.grass_task.params = dcmd_params['params']
-            if 'flags' in dcmd_params:
-                self.grass_task.flags = dcmd_params['flags']
-        
-        err = list()
-        # update parameters if needed && validate command
-        if len(cmd) > 1:
-            i = 0
-            cmd_validated = [cmd[0]]
-            for option in cmd[1:]:
-                if option[0] ==  '-': # flag
-                    if option[1] ==  '-':
-                        self.grass_task.set_flag(option[2:], True)
-                    else:
-                        self.grass_task.set_flag(option[1], True)
-                    cmd_validated.append(option)
-                else: # parameter
-                    try:
-                        key, value = option.split('=', 1)
-                    except:
-                        if self.grass_task.firstParam:
-                            if i == 0: # add key name of first parameter if not given
-                                key = self.grass_task.firstParam
-                                value = option
-                            else:
-                                raise gcmd.GException, _("Unable to parse command '%s'") % ' '.join(cmd)
-                        else:
-                            continue
-                    
-                    element = self.grass_task.get_param(key, raiseError = False)
-                    if not element:
-                        err.append(_("%(cmd)s: parameter '%(key)s' not available") % \
-                                       { 'cmd' : cmd[0],
-                                         'key' : key })
-                        continue
-                    element = element['element']
-                    
-                    if element in ['cell', 'vector']:
-                        # mapname -> mapname at mapset
-                        try:
-                            name, mapset = value.split('@')
-                        except ValueError:
-                            mapset = grass.find_file(value, element)['mapset']
-                            curr_mapset = grass.gisenv()['MAPSET']
-                            if mapset and mapset !=  curr_mapset:
-                                value = value + '@' + mapset
-                    
-                    self.grass_task.set_param(key, value)
-                    cmd_validated.append(key + '=' + value)
-                    i += 1
-            
-            # update original command list
-            cmd = cmd_validated
-        
-        if self.show is not None:
-            self.mf = mainFrame(parent = self.parent, ID = wx.ID_ANY,
-                                task_description = self.grass_task,
-                                get_dcmd = get_dcmd, layer = layer)
-        else:
-            self.mf = None
-        
-        if get_dcmd is not None:
-            # update only propwin reference
-            get_dcmd(dcmd = None, layer = layer, params = None,
-                     propwin = self.mf)
-        
-        if self.show is not None:
-            self.mf.notebookpanel.OnUpdateSelection(None)
-            if self.show is True:
-                if self.parent and self.centreOnParent:
-                    self.mf.CentreOnParent()
-                else:
-                    self.mf.CenterOnScreen()
-                self.mf.Show(self.show)
-                self.mf.MakeModal(self.modal)
-            else:
-                self.mf.OnApply(None)
-        
-        self.cmd = cmd
-        
-        if self.checkError:
-            return self.grass_task, err
-        else:
-            return self.grass_task
-    
-    def GetCommandInputMapParamKey(self, cmd):
-        """!Get parameter key for input raster/vector map
-        
-        @param cmd module name
-        
-        @return parameter key
-        @return None on failure
-        """
-        # parse the interface decription
-        if not self.grass_task:
-            enc = locale.getdefaultlocale()[1]
-            if enc and enc.lower() == "cp932":
-                p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
-                tree = etree.fromstring(p.sub('encoding="utf-8"',
-                                              gtask.get_interface_description(cmd).decode(enc).encode('utf-8')))
-            else:
-                tree = etree.fromstring(gtask.get_interface_description(cmd))
-            self.grass_task = gtask.processTask(tree).get_task()
-            
-            for p in self.grass_task.params:
-                if p.get('name', '') in ('input', 'map'):
-                    age = p.get('age', '')
-                    prompt = p.get('prompt', '')
-                    element = p.get('element', '') 
-                    if age ==  'old' and \
-                            element in ('cell', 'grid3', 'vector') and \
-                            prompt in ('raster', '3d-raster', 'vector'):
-                        return p.get('name', None)
-        return None
-
-class FloatValidator(wx.PyValidator):
-    """!Validator for floating-point input"""
-    def __init__(self):
-        wx.PyValidator.__init__(self)
-        
-        self.Bind(wx.EVT_TEXT, self.OnText) 
-        
-    def Clone(self):
-        """!Clone validator"""
-        return FloatValidator()
-
-    def Validate(self):
-        """Validate input"""
-        textCtrl = self.GetWindow()
-        text = textCtrl.GetValue()
-
-        if text:
-            try:
-                float(text)
-            except ValueError:
-                textCtrl.SetBackgroundColour("grey")
-                textCtrl.SetFocus()
-                textCtrl.Refresh()
-                return False
-        
-        sysColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
-        textCtrl.SetBackgroundColour(sysColor)
-        
-        textCtrl.Refresh()
-        
-        return True
-
-    def OnText(self, event):
-        """!Do validation"""
-        self.Validate()
-        
-        event.Skip()
-        
-    def TransferToWindow(self):
-        return True # Prevent wxDialog from complaining.
-    
-    def TransferFromWindow(self):
-        return True # Prevent wxDialog from complaining.
-
-class GNotebook(FN.FlatNotebook):
-    """!Generic notebook widget
-    """
-    def __init__(self, parent, style, **kwargs):
-        if globalvar.hasAgw:
-            FN.FlatNotebook.__init__(self, parent, id = wx.ID_ANY, agwStyle = style, **kwargs)
-        else:
-            FN.FlatNotebook.__init__(self, parent, id = wx.ID_ANY, style = style, **kwargs)
-        
-        self.notebookPages = {}
-            
-    def AddPage(self, **kwargs):
-        """!Add a new page
-        """
-        if 'name' in kwargs:
-            self.notebookPages[kwargs['name']] = kwargs['page']
-            del kwargs['name']
-        super(GNotebook, self).AddPage(**kwargs)
-
-    def InsertPage(self, **kwargs):
-        """!Insert a new page
-        """
-        if 'name' in kwargs:
-            self.notebookPages[kwargs['name']] = kwargs['page']
-            del kwargs['name']
-        super(GNotebook, self).InsertPage(**kwargs)
-
-    def SetSelectionByName(self, page):
-        """!Set notebook
-        
-        @param page names, eg. 'layers', 'output', 'search', 'pyshell', 'nviz'
-        """
-        idx = self.GetPageIndexByName(page)
-        if self.GetSelection() != idx:
-            self.SetSelection(idx)
-        
-    def GetPageIndexByName(self, page):
-        """!Get notebook page index
-        
-        @param page name
-        """
-        if page not in self.notebookPages:
-            return -1
-        
-        return self.GetPageIndex(self.notebookPages[page])
-    
-if __name__ ==  "__main__":
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    if len(sys.argv) ==  1:
-        sys.exit(_("usage: %s <grass command>") % sys.argv[0])
-    
-    if sys.argv[1] !=  'test':
-        q = wx.LogNull()
-        cmd = utils.split(sys.argv[1])
-        task = gtask.grassTask(cmd[0], blackList = _blackList)
-        task.set_options(cmd[1:])
-        app = GrassGUIApp(task)
-        app.MainLoop()
-    else: #Test
-        # Test grassTask from within a GRASS session
-        if os.getenv("GISBASE") is not None:
-            task = gtask.grassTask("d.vect")
-            task.get_param('map')['value'] = "map_name"
-            task.get_flag('v')['value'] = True
-            task.get_param('layer')['value'] = 1
-            task.get_param('bcolor')['value'] = "red"
-            assert ' '.join(task.get_cmd()) ==  "d.vect -v map = map_name layer = 1 bcolor = red"
-        # Test interface building with handmade grassTask,
-        # possibly outside of a GRASS session.
-        task = gtask.grassTask()
-        task.name = "TestTask"
-        task.description = "This is an artificial grassTask() object intended for testing purposes."
-        task.keywords = ["grass","test","task"]
-        task.params = [
-            {
-            "name" : "text",
-            "description" : "Descriptions go into tooltips if labels are present, like this one",
-            "label" : "Enter some text",
-            },{
-            "name" : "hidden_text",
-            "description" : "This text should not appear in the form",
-            "hidden" : True
-            },{
-            "name" : "text_default",
-            "description" : "Enter text to override the default",
-            "default" : "default text"
-            },{
-            "name" : "text_prefilled",
-            "description" : "You should see a friendly welcome message here",
-            "value" : "hello, world"
-            },{
-            "name" : "plain_color",
-            "description" : "This is a plain color, and it is a compulsory parameter",
-            "required" : False,
-            "gisprompt" : True,
-            "prompt" : "color"
-            },{
-            "name" : "transparent_color",
-            "description" : "This color becomes transparent when set to none",
-            "guisection" : "tab",
-            "gisprompt" : True,
-            "prompt" : "color"
-            },{
-            "name" : "multi",
-            "description" : "A multiple selection",
-            'default': u'red,green,blue',
-            'gisprompt': False,
-            'guisection': 'tab',
-            'multiple': u'yes',
-            'type': u'string',
-            'value': '',
-            'values': ['red', 'green', u'yellow', u'blue', u'purple', u'other']
-            },{
-            "name" : "single",
-            "description" : "A single multiple-choice selection",
-            'values': ['red', 'green', u'yellow', u'blue', u'purple', u'other'],
-            "guisection" : "tab"
-            },{
-            "name" : "large_multi",
-            "description" : "A large multiple selection",
-            "gisprompt" : False,
-            "multiple" : "yes",
-            # values must be an array of strings
-            "values" : str2rgb.keys() + map(str, str2rgb.values())
-            },{
-            "name" : "a_file",
-            "description" : "A file selector",
-            "gisprompt" : True,
-            "element" : "file"
-            }
-            ]
-        task.flags = [
-            {
-            "name" : "a",
-            "description" : "Some flag, will appear in Main since it is required",
-            "required" : True
-            },{
-            "name" : "b",
-            "description" : "pre-filled flag, will appear in options since it is not required",
-            "value" : True
-            },{
-            "name" : "hidden_flag",
-            "description" : "hidden flag, should not be changeable",
-            "hidden" : "yes",
-            "value" : True
-            }
-            ]
-        q = wx.LogNull()
-        GrassGUIApp(task).MainLoop()
-

Deleted: grass/trunk/gui/wxpython/gui_modules/nviz.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/nviz.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,43 +0,0 @@
-"""!
- at package nviz.py
-
- at brief Nviz (3D view) module
-
-This module implements 3D visualization mode for map display.
-
-Map Display supports standard 2D view mode ('mapdisp' module) and
-2.5/3D mode ('nviz_mapdisp' module).
-
-(C) 2008, 2010-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
- at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
-"""
-
-errorMsg = ''
-
-import os
-import sys
-
-import wx
-import globalvar
-try:
-    from wx import glcanvas
-    import nviz_mapdisp
-    import nviz_tools
-    import wxnviz
-    haveNviz = True
-except ImportError, err:
-    haveNviz = False
-    errorMsg = err
-
-if haveNviz:
-    GLWindow = nviz_mapdisp.GLWindow
-    NvizToolWindow = nviz_tools.NvizToolWindow
-else:
-    GLWindow = None
-    NvizToolWindow = None

Deleted: grass/trunk/gui/wxpython/gui_modules/nviz_animation.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_animation.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_animation.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,208 +0,0 @@
-"""!
- at package nviz_animation.py
-
- at brief Nviz (3D view) animation
-
-Classes:
- - Animation
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Anna Kratochvilova <kratochanna gmail.com> 
-"""
-import os
-import copy
-
-import wx
-from wx.lib.newevent import NewEvent
-
-wxAnimationFinished, EVT_ANIM_FIN = NewEvent()
-wxAnimationUpdateIndex, EVT_ANIM_UPDATE_IDX = NewEvent()
-
-
-class Animation:
-    """!Class represents animation as a sequence of states (views).
-    It enables to record, replay the sequence and finally generate
-    all image files. Recording and replaying is based on timer events.
-    There is no frame interpolation like in the Tcl/Tk based Nviz.
-    """
-    def __init__(self, mapWindow, timer):
-        """!Animation constructor
-        
-        @param mapWindow glWindow where rendering takes place
-        @param timer timer for recording and replaying
-        """
-        
-        self.animationList = []         # view states
-        self.timer = timer
-        self.mapWindow = mapWindow
-        self.actions = {'record': self.Record,
-                        'play': self.Play}
-        self.formats = ['ppm', 'tif']   # currently supported formats
-        self.mode = 'record'            # current mode (record, play, save)
-        self.paused = False             # recording/replaying paused
-        self.currentFrame = 0           # index of current frame
-        self.fps = 24 # user settings   # Frames per second
-        
-        self.stopSaving = False         # stop during saving images
-        self.animationSaved = False     # current animation saved or not
-        
-    def Start(self):
-        """!Start recording/playing"""
-        self.timer.Start(self.GetInterval())
-        
-    def Pause(self):
-        """!Pause recording/playing"""
-        self.timer.Stop()
-        
-    def Stop(self):
-        """!Stop recording/playing"""
-        self.timer.Stop()
-        self.PostFinishedEvent()
-        
-    def Update(self):
-        """!Record/play next view state (on timer event)"""
-        self.actions[self.mode]()
-    
-    def Record(self):
-        """!Record new view state"""
-        self.animationList.append({'view' : copy.deepcopy(self.mapWindow.view),
-                                   'iview': copy.deepcopy(self.mapWindow.iview)})
-        self.currentFrame += 1
-        self.PostUpdateIndexEvent(index = self.currentFrame)
-        self.animationSaved = False
-        
-    def Play(self):
-        """!Render next frame"""
-        if not self.animationList:
-            self.Stop()
-            return
-        try:
-            self.IterAnimation()
-        except IndexError:
-            # no more frames
-            self.Stop()
-            
-    def IterAnimation(self):
-        params = self.animationList[self.currentFrame]
-        self.UpdateView(params)
-        self.currentFrame += 1
-        
-        self.PostUpdateIndexEvent(index = self.currentFrame)
-        
-    def UpdateView(self, params):
-        """!Update view data in map window and render"""
-        toolWin = self.mapWindow.GetToolWin()
-        toolWin.UpdateState(view = params['view'], iview = params['iview'])
-        
-        self.mapWindow.UpdateView()
-        
-        self.mapWindow.render['quick'] = True
-        self.mapWindow.Refresh(False)
-        
-    def IsRunning(self):
-        """!Test if timer is running"""
-        return self.timer.IsRunning()
-        
-    def SetMode(self, mode):
-        """!Start animation mode
-        
-        @param mode animation mode (record, play, save)
-        """
-        self.mode = mode
-        
-    def GetMode(self):
-        """!Get animation mode (record, play, save)"""
-        return self.mode
-        
-    def IsPaused(self):
-        """!Test if animation is paused"""
-        return self.paused
-        
-    def SetPause(self, pause):
-        self.paused = pause
-        
-    def Exists(self):
-        """!Returns if an animation has been recorded"""
-        return bool(self.animationList)
-        
-    def GetFrameCount(self):
-        """!Return number of recorded frames"""
-        return len(self.animationList)
-        
-    def Clear(self):
-        """!Clear all records"""
-        self.animationList = []
-        self.currentFrame = 0
-        
-    def GoToFrame(self, index):
-        """!Render frame of given index"""
-        if index >= len(self.animationList):
-            return
-            
-        self.currentFrame = index
-        params = self.animationList[self.currentFrame]
-        self.UpdateView(params)
-        
-    def PostFinishedEvent(self):
-        """!Animation ends"""
-        toolWin = self.mapWindow.GetToolWin()
-        event = wxAnimationFinished(mode = self.mode)
-        wx.PostEvent(toolWin, event)
-        
-    def PostUpdateIndexEvent(self, index):
-        """!Frame index changed, update tool window"""
-        toolWin = self.mapWindow.GetToolWin()
-        event = wxAnimationUpdateIndex(index = index, mode = self.mode)
-        wx.PostEvent(toolWin, event)
-        
-    def StopSaving(self):
-        """!Abort image files generation"""
-        self.stopSaving = True
-        
-    def IsSaved(self):
-        """"!Test if animation has been saved (to images)"""
-        return self.animationSaved
-        
-    def SaveAnimationFile(self, path, prefix, format):
-        """!Generate image files
-        
-        @param path path to direcory
-        @param prefix file prefix
-        @param format index of image file format
-        """
-        w, h = self.mapWindow.GetClientSizeTuple()
-        toolWin = self.mapWindow.GetToolWin()
-        
-        self.currentFrame = 0
-        self.mode = 'save'
-        for params in self.animationList:
-            if not self.stopSaving:
-                self.UpdateView(params)
-                filename = prefix + "_" + str(self.currentFrame) + '.' + self.formats[format]
-                filepath = os.path.join(path, filename)
-                self.mapWindow.SaveToFile(FileName = filepath, FileType = self.formats[format],
-                                                  width = w, height = h)
-                self.currentFrame += 1
-                
-                wx.Yield()
-                toolWin.UpdateFrameIndex(index = self.currentFrame, goToFrame = False)
-            else:
-                self.stopSaving = False
-                break
-        self.animationSaved = True
-        self.PostFinishedEvent()
-
-    def SetFPS(self, fps):
-        """!Set Frames Per Second value
-        @param fps frames per second
-        """
-        self.fps = fps
-    
-    def GetInterval(self):
-        """!Return timer interval in ms"""
-        return 1000. / self.fps

Deleted: grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2516 +0,0 @@
-"""!
- at package nviz_mapdisp.py
-
- at brief wxGUI 3D view mode (map canvas)
-
-This module implements 3D visualization mode for map display.
-
-List of classes:
- - NvizThread
- - GLWindow
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
- at author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
-"""
-
-import os
-import sys
-import time
-import copy
-import math
-import types
-import tempfile
-
-from threading import Thread
-
-import wx
-import wx.lib.scrolledpanel as scrolled
-from wx.lib.newevent import NewEvent
-from wx import glcanvas
-
-import gcmd
-import globalvar
-import grass.script as grass
-from debug          import Debug
-from mapdisp_window import MapWindow
-from goutput        import wxCmdOutput
-from preferences    import globalSettings as UserSettings
-from workspace      import Nviz as NvizDefault
-from nviz_animation import Animation
-
-import wxnviz
-
-wxUpdateProperties, EVT_UPDATE_PROP  = NewEvent()
-wxUpdateView,       EVT_UPDATE_VIEW  = NewEvent()
-wxUpdateLight,      EVT_UPDATE_LIGHT = NewEvent()
-wxUpdateCPlane,     EVT_UPDATE_CPLANE = NewEvent()
-
-class NvizThread(Thread):
-    def __init__(self, log, progressbar, window):
-        Thread.__init__(self)
-        Debug.msg(5, "NvizThread.__init__():")
-        self.log = log
-        self.progressbar = progressbar
-        self.window = window
-        
-        self._display = None
-        
-        self.setDaemon(True)
-
-    def run(self):
-        self._display = wxnviz.Nviz(self.log, self.progressbar)
-        
-    def GetDisplay(self):
-        """!Get display instance"""
-        return self._display
-
-class GLWindow(MapWindow, glcanvas.GLCanvas):
-    """!OpenGL canvas for Map Display Window"""
-    def __init__(self, parent, id = wx.ID_ANY,
-                 Map = None, tree = None, lmgr = None):
-        self.parent = parent # MapFrame
-        
-        glcanvas.GLCanvas.__init__(self, parent, id)
-        MapWindow.__init__(self, parent, id, 
-                           Map, tree, lmgr)
-        self.Hide()
-        
-        self.init = False
-        self.initView = False
-        
-        # render mode 
-        self.render = { 'quick' : False,
-                        # do not render vector lines in quick mode
-                        'vlines' : False,
-                        'vpoints' : False,
-                        'overlays': False }
-        self.mouse = {
-            'use': 'pointer'
-            }
-        self.cursors = {
-            'default' : wx.StockCursor(wx.CURSOR_ARROW),
-            'cross'   : wx.StockCursor(wx.CURSOR_CROSS),
-            }
-        # list of loaded map layers (layer tree items)
-        self.layers  = list()
-        # list of constant surfaces
-        self.constants = list()
-        # id of base surface (when vector is loaded and no surface exist)
-        self.baseId = -1
-        # list of cutting planes
-        self.cplanes = list()
-        # list of query points
-        self.qpoints = list()
-        # list of past views
-        self.viewhistory  = []
-        self.saveHistory = False
-        # offset for dialog (e.g. DisplayAttributesDialog)
-        self.dialogOffset = 5
-        # overlays
-        self.overlays = {}
-        self.imagelist = []
-        self.overlay = wx.Overlay()
-        #self.pdc = wx.PseudoDC()
-        self.textdict = {}
-        self.dragid = -1
-        self.hitradius = 5
-        # layer manager toolwindow
-        self.toolWin = None
-        
-        if self.lmgr:
-            self.log = self.lmgr.goutput
-            logerr = self.lmgr.goutput.GetLog(err = True)
-            logmsg = self.lmgr.goutput.GetLog()
-        else:
-            self.log = logmsg = sys.stdout
-            logerr = sys.stderr
-        
-        # create nviz instance - use display region instead of computational
-        os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
-        
-        self.nvizThread = NvizThread(logerr,
-                                     self.parent.GetProgressBar(),
-                                     logmsg)
-        self.nvizThread.start()
-        time.sleep(.1)
-        self._display = self.nvizThread.GetDisplay()
-        
-        # GRASS_REGION needed only for initialization
-        del os.environ['GRASS_REGION']
-        
-        self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
-        
-        # size of MapWindow, to avoid resizing if size is the same
-        self.size = (0, 0)
-        
-        # default values
-        self.nvizDefault = NvizDefault()
-        self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
-        self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True)
-        self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
-        self.decoration = self.nvizDefault.SetDecorDefaultProp(type = 'arrow')
-        self.decoration['scalebar'] = []
-        self.decoration['arrow']['size'] = self._getDecorationSize()
-        self.fly = self.InitFly()
-        
-        # timer for flythrough
-        self.timerFly = wx.Timer(self, id = wx.NewId())
-        # timer for animations
-        self.timerAnim = wx.Timer(self, id = wx.NewId())
-        self.animation = Animation(mapWindow = self, timer = self.timerAnim)        
-        
-        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
-        self.Bind(wx.EVT_SIZE,             self.OnSize)
-        self.Bind(wx.EVT_PAINT,            self.OnPaint)
-        self._bindMouseEvents()
-        
-        self.Bind(EVT_UPDATE_PROP,   self.UpdateMapObjProperties)
-        self.Bind(EVT_UPDATE_VIEW,   self.OnUpdateView)
-        self.Bind(EVT_UPDATE_LIGHT,  self.UpdateLight)
-        self.Bind(EVT_UPDATE_CPLANE, self.UpdateCPlane)
-        
-        self.Bind(wx.EVT_TIMER, self.OnTimerAnim, self.timerAnim)
-        self.Bind(wx.EVT_TIMER, self.OnTimerFly, self.timerFly)
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
-        
-        self.Bind(wx.EVT_CLOSE, self.OnClose)
-        
-        # cplanes cannot be initialized now
-        wx.CallAfter(self.InitCPlanes)
-
-    def InitFly(self):
-        """!Initialize fly through dictionary"""
-        fly = {'interval' : 10,             # interval for timerFly
-               'value': [0, 0, 0],          # calculated values for navigation
-               'mode' : 0,                  # fly through mode (0, 1)
-               'exag' : {                   # sensitivity
-                    'move' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'move']),
-                    'turn' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'turn'])},
-               'exagMultiplier' : 3,        # speed up by Shift
-               'flySpeed' : 4,              # speed of flying
-               'mouseControl' : None,       # if mouse or keys are used
-               'pos' : {'x' : 0, 'y' : 0},  # virtual mouse position when using arrows
-               'arrowStep' : 50,            # step in pixels (when using arrows)
-               'flySpeedStep' : 2,
-            }
-            
-        return fly
-        
-    def OnTimerFly(self, event):
-        """!Fly event was emitted, move the scene"""
-        if self.mouse['use'] != 'fly':
-            return
-        
-        if self.fly['mouseControl']:
-            mx, my = self.ComputeMxMy(*self.mouse['tmp'])
-        else:
-            mx, my = self.ComputeMxMy(self.fly['pos']['x'], self.fly['pos']['y'])
-            
-        self.ComputeFlyValues(mx = mx, my = my)
-        self._display.FlyThrough(flyInfo = self.fly['value'], mode = self.fly['mode'],
-                                 exagInfo = self.fly['exag'])
-        self.ChangeInnerView()                                 
-        self.render['quick'] = True
-        self.Refresh(False)
-        
-    def ComputeMxMy(self, x, y):
-        """!Compute values for flythrough navigation 
-        (ComputeFlyValues should follow). 
-        
-        Based on visualization/nviz/src/togl_flythrough.c.
-        @param x,y screen coordinates
-        """
-        sx, sy = self.GetClientSizeTuple()
-        dx = dy = 0.01
-        
-        mx = 2 * (float(x) / sx) - 1
-        my = 2 * (float(y) / sy) - 1
-    
-        if mx < - dx:
-            mx += dx
-        elif mx > dx:
-            mx -= dx
-        else:
-            mx = 0.0 # ?
-        if my < - dy:
-            my += dy
-        elif my > dy:
-            my -= dy
-        else:
-            my = 0.0
-    
-        mx = mx / (1.0 - dx)
-        my = my / (1.0 - dy)
-    
-        # Quadratic seems smoother 
-        mx *= abs(mx)
-        my *= abs(my)
-        
-        return mx, my
-        
-    def ComputeFlyValues(self, mx, my):
-        """!Compute parameters for fly-through navigation
-        
-        @params mx,my results from ComputeMxMy method
-        """
-        self.fly['value'] = [0, 0, 0]
-        
-        if self.fly['mode'] == 0:
-            self.fly['value'][0] = self.fly['flySpeed'] * self.fly['interval'] / 1000. # forward */
-            self.fly['value'][1] = mx * 0.1 * self.fly['interval'] / 1000. # heading 
-            self.fly['value'][2] = my * 0.1 * self.fly['interval'] / 1000. # pitch 
-        else:
-            self.fly['value'][0] = mx * 100.0 * self.fly['interval'] /1000.
-            self.fly['value'][2] = - my * 100.0 * self.fly['interval'] /1000.
-    
-    def ChangeFlySpeed(self, increase):
-        """!Increase/decrease flight spped"""
-        if increase:
-            self.fly['flySpeed'] += self.fly['flySpeedStep']
-        else:
-            self.fly['flySpeed'] -= self.fly['flySpeedStep']
-        
-    def __del__(self):
-        """!Stop timers if running, unload data"""
-        self.StopTimer(self.timerAnim)
-        self.StopTimer(self.timerFly)
-        self.UnloadDataLayers(force = True)
-    
-    def StopTimer(self, timer):
-        """!Stop timer if running"""
-        if timer.IsRunning():
-            timer.Stop()
-            
-    def _bindMouseEvents(self):
-        self.Bind(wx.EVT_MOUSE_EVENTS,     self.OnMouseAction)
-        self.Bind(wx.EVT_MOTION,           self.OnMotion)
-        
-    def InitCPlanes(self):
-        """!Initialize cutting planes list"""
-        for i in range(self._display.GetCPlanesCount()):
-            cplane = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'cplane'))
-            cplane['on'] = False
-            self.cplanes.append(cplane)
-        
-    def SetToolWin(self, toolWin):
-        """!Sets reference to nviz toolwindow in layer manager"""
-        self.toolWin = toolWin
-        
-    def GetToolWin(self):
-        """!Returns reference to nviz toolwindow in layer manager"""
-        return self.toolWin
-            
-    def OnClose(self, event):
-        self.StopTimer(self.timerAnim)
-        self.StopTimer(self.timerFly)
-        # cleanup when window actually closes (on quit) and not just is hidden
-        self.UnloadDataLayers(force = True)
-        
-    def OnEraseBackground(self, event):
-        pass # do nothing, to avoid flashing on MSW
-    
-    def OnSize(self, event):
-        size = self.GetClientSize()
-        if self.size != size \
-            and self.GetContext():
-            Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \
-                      (size.width, size.height))
-            self.SetCurrent()
-            self._display.ResizeWindow(size.width,
-                                       size.height)
-        
-            # reposition checkbox in statusbar
-            self.parent.StatusbarReposition()
-            
-            # update statusbar
-            self.parent.StatusbarUpdate()
-            
-        self.size = size
-        
-        event.Skip()
-       
-    def OnPaint(self, event):
-        Debug.msg(1, "GLCanvas.OnPaint()")
-        
-        self.render['overlays'] = True
-        dc = wx.PaintDC(self)
-        self.DoPaint()
-        
-
-    def DoPaint(self):
-        self.SetCurrent()
-        
-        if not self.initView:
-            self._display.InitView()
-            self.initView = True
-        
-        self.LoadDataLayers()
-        self.UnloadDataLayers()
-        
-        if not self.init:
-            self.ResetView()
-            
-            if hasattr(self.lmgr, "nviz"):
-                self.lmgr.nviz.UpdatePage('view')
-                self.lmgr.nviz.UpdatePage('light')
-                self.lmgr.nviz.UpdatePage('cplane')
-                self.lmgr.nviz.UpdatePage('decoration')
-                self.lmgr.nviz.UpdatePage('animation')
-                layer = self.GetSelectedLayer()
-                if layer:
-                    if layer.type ==  'raster':
-                        self.lmgr.nviz.UpdatePage('surface')
-                        self.lmgr.nviz.UpdatePage('fringe')
-                    elif layer.type ==  'vector':
-                        self.lmgr.nviz.UpdatePage('vector')
-                
-                self.lmgr.nviz.UpdateSettings()
-                
-                # update widgets
-                win = self.lmgr.nviz.FindWindowById( \
-                    self.lmgr.nviz.win['vector']['lines']['surface'])
-                win.SetItems(self.GetLayerNames('raster'))
-            
-            self.init = True
-        
-        self.UpdateMap()
-        
-    def DrawImages(self):
-        """!Draw overlay image"""
-        for texture in self.imagelist:
-            if texture.IsActive():
-                texture.Draw()
-            
-    def GetLegendRect(self):
-        """!Estimates legend size for dragging"""
-        size = None
-        if 1 in self.overlays:
-            for param in self.overlays[1]['cmd'][1:]:
-                if param.startswith("at="):
-                    size = map(int, param.split("=")[-1].split(','))
-                    break
-        if size:
-            wSize = self.GetClientSizeTuple()
-            x, y = size[2]/100. * wSize[0], wSize[1] - (size[1]/100. * wSize[1])
-            x += self.overlays[1]['coords'][0]
-            y += self.overlays[1]['coords'][1]
-            w = (size[3] - size[2])/100. * wSize[0]
-            h = (size[1] - size[0])/100. * wSize[1]
-            
-            rect = wx.Rect(x, y, w, h)
-            return rect
-        
-        return wx.Rect()        
-        
-    def DrawTextImage(self, textDict, relCoords):
-        """!Draw overlay text"""
-        bmp = wx.EmptyBitmap(textDict['bbox'][2], textDict['bbox'][3])
-        memDC = wx.MemoryDC()
-        memDC.SelectObject(bmp)
-        
-        mask = self.view['background']['color']
-        if mask == textDict['color']:
-            mask = wx.WHITE
-        memDC.SetBackground(wx.Brush(mask))
-        memDC.Clear()
-        memDC.SetFont(textDict['font'])
-        memDC.SetTextForeground(textDict['color'])
-        if textDict['rotation'] == 0:
-            memDC.DrawText(textDict['text'], 0, 0)
-        else:
-            memDC.DrawRotatedText(textDict['text'], relCoords[0], relCoords[1],
-                                  textDict['rotation'])
-        bmp.SetMaskColour(mask)
-        memDC.DrawBitmap(bmp, 0, 0, 1)
-        
-        filename = grass.tempfile(create = False) + '.png'
-        bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
-        memDC.SelectObject(wx.NullBitmap)
-        
-        return filename
-        
-    def UpdateOverlays(self):
-        """!Converts rendered overlay files and text labels to wx.Image
-            and then to textures so that they can be rendered by OpenGL.
-            Updates self.imagelist"""
-        self.Map.ChangeMapSize(self.GetClientSize())
-        self.Map.RenderOverlays(force = True)
-        
-        # delete textures
-        for texture in self.imagelist:
-            # inactive overlays, remove text labels
-            if texture.GetId() < 100:
-                if not self.overlays[texture.GetId()]['layer'].IsActive():
-                    texture.SetActive(False)
-                else:
-                    texture.SetActive(True)
-            else: # text label
-                if texture.GetId() not in self.textdict:
-                    self.imagelist.remove(texture)
-                    
-        # update images (only legend so far)
-        for oid, overlay in self.overlays.iteritems():
-            layer = overlay['layer']
-            if not layer.IsActive() or oid == 0: # 0 for barscale
-                continue
-            if oid not in [t.GetId() for t in self.imagelist]: # new
-                self.CreateTexture(overlay = layer)
-            else:
-                for t in self.imagelist:
-                    if t.GetId() == oid: # check if it is the same
-                        if not t.Corresponds(layer):
-                            self.imagelist.remove(t)
-                            t = self.CreateTexture(overlay = layer)
-                        # always set coordinates, needed for synchr. 2D and 3D modes
-                        t.SetCoords(overlay['coords'])
-
-                    
-        # update text labels
-        for textId in self.textdict.keys():
-            if textId not in [t.GetId() for t in self.imagelist]:# new
-                self.CreateTexture(textId = textId)
-            else:
-                for t in self.imagelist:
-                    if t.GetId() == textId: # check if it is the same
-                        self.textdict[textId]['bbox'] = t.textDict['bbox']
-                        if not t.Corresponds(self.textdict[textId]):
-                            self.imagelist.remove(t)
-                            t = self.CreateTexture(textId = textId)
-                        # always set coordinates, needed for synchr. 2D and 3D modes
-                        t.SetCoords(self.textdict[textId]['coords'])
-            
-    def CreateTexture(self, overlay = None, textId = None):
-        """!Create texture from overlay image or from textdict"""
-        if overlay: # legend  
-            texture = wxnviz.ImageTexture(filepath = overlay.mapfile, overlayId = overlay.id,
-                                          coords = list(self.overlays[overlay.id]['coords']),
-                                          cmd = overlay.GetCmd())
-            if overlay.id == 1: # legend
-                texture.SetBounds(self.GetLegendRect())
-        else: # text
-            coords, bbox, relCoords = self.TextBounds(self.textdict[textId])
-            self.textdict[textId]['coords'] = coords
-            self.textdict[textId]['bbox'] = bbox
-            file = self.DrawTextImage(self.textdict[textId], relCoords)
-            texture = wxnviz.TextTexture(filepath = file, overlayId = textId,
-                                         coords = coords, textDict = self.textdict[textId])
-            bbox.OffsetXY(*relCoords)
-            texture.SetBounds(bbox)
-            
-        if not texture.textureId: # texture too big
-            gcmd.GMessage(parent = self, message = 
-                          _("Image is too large, your OpenGL implementation "
-                            "supports maximum texture size %d px.") % texture.maxSize)
-            return texture
-            
-        self.imagelist.append(texture)
-        
-        return texture
-        
-    def FindObjects(self, mouseX, mouseY, radius):
-        """Find object which was clicked on"""
-        for texture in self.imagelist:
-            if texture.HitTest(mouseX, mouseY, radius):
-                return texture.id
-        return -1
-        
-    def OnTimerAnim(self, event):
-         self.animation.Update()
-         
-    def GetAnimation(self):
-         return self.animation
-         
-    def OnKeyDown(self, event):
-        """!Key was pressed.
-        
-        Used for fly-through mode.
-        """
-        if not self.mouse['use'] == 'fly':
-            return
-            
-        key = event.GetKeyCode()
-        if key == wx.WXK_CONTROL: # Mac ?
-            self.fly['mode'] = 1
-            
-        elif key == wx.WXK_SHIFT: 
-            self.fly['exag']['move'] *= self.fly['exagMultiplier']
-            self.fly['exag']['turn'] *= self.fly['exagMultiplier']
-            
-        elif key == wx.WXK_ESCAPE and self.timerFly.IsRunning() and not self.fly['mouseControl']:
-            self.StopTimer(self.timerFly)
-            self.fly['mouseControl'] = None
-            self.render['quick'] = False
-            self.Refresh(False)
-            
-        elif key in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
-            if not self.fly['mouseControl']:
-                if not self.timerFly.IsRunning():
-                    sx, sy = self.GetClientSizeTuple()
-                    self.fly['pos']['x'] = sx / 2
-                    self.fly['pos']['y'] = sy / 2
-                    self.fly['mouseControl'] = False # controlled by keyboard
-                    self.timerFly.Start(self.fly['interval'])
-    
-                self.ProcessFlyByArrows(keyCode = key)
-                
-            # change speed of flight when using mouse
-            else:
-                if key == wx.WXK_UP:
-                    self.ChangeFlySpeed(increase = True)
-                elif key == wx.WXK_DOWN:
-                    self.ChangeFlySpeed(increase = False)
-        
-        elif key in (wx.WXK_HOME, wx.WXK_PAGEUP) and self.timerFly.IsRunning():
-            self.ChangeFlySpeed(increase = True)
-        elif key in (wx.WXK_END, wx.WXK_PAGEDOWN) and self.timerFly.IsRunning():
-            self.ChangeFlySpeed(increase = False)
-            
-        event.Skip()
-        
-    def ProcessFlyByArrows(self, keyCode):
-        """!Process arrow key during fly-through"""
-        step = self.fly['arrowStep']
-        if keyCode == wx.WXK_UP:
-            self.fly['pos']['y'] -= step
-        elif keyCode == wx.WXK_DOWN:
-            self.fly['pos']['y'] += step
-        elif keyCode == wx.WXK_LEFT:
-            self.fly['pos']['x'] -= step
-        elif keyCode == wx.WXK_RIGHT:
-            self.fly['pos']['x'] += step
-            
-    def OnKeyUp(self, event):
-        """!Key was released.
-        
-        Used for fly-through mode.
-        """
-        if not self.mouse['use'] == 'fly':
-            return
-            
-        key = event.GetKeyCode()
-        if key == wx.WXK_CONTROL: # Mac ?
-            self.fly['mode'] = 0
-        elif key == wx.WXK_SHIFT: 
-            self.fly['exag']['move'] = math.floor(self.fly['exag']['move'] / self.fly['exagMultiplier'])
-            self.fly['exag']['turn'] = math.floor(self.fly['exag']['turn'] / self.fly['exagMultiplier'])
-        
-        event.Skip()
-        
-    def OnMouseAction(self, event):
-        """!Handle mouse events"""
-        # zoom with mouse wheel
-        if event.GetWheelRotation() != 0:
-            self.OnMouseWheel(event)
-            
-        # left mouse button pressed
-        elif event.LeftDown():
-            self.OnLeftDown(event)
-        
-        # left mouse button released
-        elif event.LeftUp():
-            self.OnLeftUp(event)
-        
-        # dragging
-        elif event.Dragging():
-            self.OnDragging(event)
-            
-        # double click    
-        elif event.ButtonDClick():
-            self.OnDClick(event)
-        
-        event.Skip()
-
-    def OnMouseWheel(self, event):
-        """!Change perspective"""
-        wheel = event.GetWheelRotation()
-        Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel)
-        if self.timerFly.IsRunning() and self.fly['mouseControl']:
-            if wheel > 0:
-                self.ChangeFlySpeed(increase = True)
-            else:
-                self.ChangeFlySpeed(increase = False)
-        else:
-            self.DoZoom(zoomtype = wheel, pos = event.GetPositionTuple())
-            
-        # update statusbar
-        ### self.parent.StatusbarUpdate()
-            
-    def OnLeftDown(self, event):
-        """!On left mouse down"""
-        self.mouse['begin'] = event.GetPositionTuple()
-        self.mouse['tmp'] = event.GetPositionTuple()
-        if self.mouse['use'] == "lookHere":
-            size = self.GetClientSize()
-            self._display.LookHere(self.mouse['begin'][0], size[1] - self.mouse['begin'][1])
-            focus = self._display.GetFocus()
-            for i, coord in enumerate(('x', 'y', 'z')):
-                self.iview['focus'][coord] = focus[i]
-            self.saveHistory = True
-            self.Refresh(False)
-            toggle = self.lmgr.nviz.FindWindowByName('here')
-            toggle.SetValue(False)
-            self.mouse['use'] = 'pointer'
-            self.SetCursor(self.cursors['default'])
-                
-        if self.mouse['use'] == 'arrow':
-            pos = event.GetPosition()
-            size = self.GetClientSize()
-            self.SetDrawArrow((pos[0], size[1] - pos[1]))
-                
-        if self.mouse['use'] == 'scalebar':
-            pos = event.GetPosition()
-            size = self.GetClientSize()
-            self.SetDrawScalebar((pos[0], size[1] - pos[1]))
-        
-        if self.mouse['use'] == 'pointer':
-            # get decoration or text id
-            self.dragid = self.FindObjects(self.mouse['tmp'][0], self.mouse['tmp'][1],
-                                          self.hitradius)   
-                
-        if self.mouse['use'] == 'fly':
-            if not self.timerFly.IsRunning():
-                self.timerFly.Start(self.fly['interval'])
-                self.fly['mouseControl'] = True
-            
-        event.Skip()    
-        
-    def OnDragging(self, event):
-                
-        if self.mouse['use'] == 'pointer':
-            if self.dragid > 0:
-                self.DragItem(self.dragid, event)
-            
-        if self.mouse['use'] == 'rotate':    
-            dx, dy = event.GetX() - self.mouse['tmp'][0], event.GetY() - self.mouse['tmp'][1]
-            
-            angle, x, y, z = self._display.GetRotationParameters(dx, dy)
-            self._display.Rotate(angle, x, y, z)
-            
-            self.render['quick'] = True
-            self.Refresh(False)
-            
-        if self.mouse['use'] == 'pan':
-            self.FocusPanning(event)
-            
-        self.mouse['tmp'] = event.GetPositionTuple()
-                
-        event.Skip()
-            
-    def Pixel2Cell(self, (x, y)):
-        """!Convert image coordinates to real word coordinates
-
-        @param x, y image coordinates
-        
-        @return easting, northing
-        @return None on error
-        """
-        size = self.GetClientSize()
-        # UL -> LL
-        sid, x, y, z = self._display.GetPointOnSurface(x, size[1] - y)
-        
-        if not sid:
-            return None
-        
-        return (x, y)
-    
-    def DoZoom(self, zoomtype, pos):
-        """!Change perspective and focus"""
-        
-        prev_value = self.view['persp']['value']
-        if zoomtype > 0:
-            value = -1 * self.view['persp']['step']
-        else:
-            value = self.view['persp']['step']
-        self.view['persp']['value'] +=  value
-        if self.view['persp']['value'] < 1:
-            self.view['persp']['value'] = 1
-        elif self.view['persp']['value'] > 180:
-            self.view['persp']['value'] = 180
-        
-        if prev_value !=  self.view['persp']['value']:
-            if hasattr(self.lmgr, "nviz"):
-                self.lmgr.nviz.UpdateSettings()
-                x, y = pos[0], self.GetClientSize()[1] - pos[1]
-                result = self._display.GetPointOnSurface(x, y)
-                if result[0]:
-                    self._display.LookHere(x, y)
-                    focus = self._display.GetFocus()
-                    for i, coord in enumerate(('x', 'y', 'z')):
-                        self.iview['focus'][coord] = focus[i]
-                self._display.SetView(self.view['position']['x'], self.view['position']['y'],
-                                      self.iview['height']['value'],
-                                      self.view['persp']['value'],
-                                      self.view['twist']['value'])
-                self.saveHistory = True
-            # redraw map
-            self.DoPaint()
-            
-    def OnLeftUp(self, event):
-        self.mouse['end'] = event.GetPositionTuple()
-        if self.mouse["use"] == "query":
-            # querying
-            layers = self.GetSelectedLayer(multi = True)
-            isRaster = False
-            nVectors = 0
-            for l in layers:
-                if l.GetType() == 'raster':
-                    isRaster = True
-                    break
-                if l.GetType() == 'vector':
-                    nVectors += 1
-            
-            if isRaster or nVectors > 1:
-                self.OnQueryMap(event)
-            else:
-                self.OnQueryVector(event)
-                    
-        elif self.mouse["use"] in ('arrow', 'scalebar'):
-            self.lmgr.nviz.FindWindowById(
-                    self.lmgr.nviz.win['decoration'][self.mouse["use"]]['place']).SetValue(False)
-            self.mouse['use'] = 'pointer'
-            self.SetCursor(self.cursors['default'])
-        elif self.mouse['use'] == 'pointer':
-            if self.dragid > 0:
-                dx = self.mouse['end'][0] - self.mouse['begin'][0]
-                dy = self.mouse['end'][1] - self.mouse['begin'][1]
-                if self.dragid < 99:
-                    coords = self.overlays[self.dragid]['coords']
-                    self.overlays[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
-                else: # text
-                    coords = self.textdict[self.dragid]['coords']
-                    self.textdict[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
-                self.dragid = -1
-                self.render['quick'] = False
-                self.Refresh(False)
-            
-        elif self.mouse['use'] == 'rotate':
-            self._display.UnsetRotation()
-            self.iview['rotation'] = self._display.GetRotationMatrix()
-            self.saveHistory = True
-            self.render['quick'] = False
-            self.Refresh(False)
-            
-        elif self.mouse['use'] == 'pan':
-            self.saveHistory = True
-            self.render['quick'] = False
-            self.Refresh(False)
-            
-        elif self.mouse['use'] == 'fly':
-            if self.fly['mouseControl']:
-                self.StopTimer(self.timerFly)
-                self.fly['mouseControl'] = None
-                #for key in self.iview['dir'].keys():
-                    #self.iview[''][key] = -1
-                # this causes sudden change, but it should be there
-                #if hasattr(self.lmgr, "nviz"):
-                    #self.lmgr.nviz.UpdateSettings()
-                    
-                self.render['quick'] = False
-                self.Refresh(False)
-            
-        elif self.mouse['use'] == 'zoom':
-            self.DoZoom(zoomtype = self.zoomtype, pos = self.mouse['end'])
-        event.Skip()
-            
-    def OnDClick(self, event):
-        """!On mouse double click"""
-        if self.mouse['use'] != 'pointer': return
-        pos = event.GetPositionTuple()
-        self.dragid = self.FindObjects(pos[0], pos[1], self.hitradius)
-        
-        if self.dragid == 1:
-            self.parent.OnAddLegend(None)
-        elif self.dragid > 100:
-            self.parent.OnAddText(None)
-        else:
-            return
-    
-    def FocusPanning(self, event):
-        """!Simulation of panning using focus"""
-        size = self.GetClientSizeTuple()
-        id1, x1, y1, z1 = self._display.GetPointOnSurface(
-                      self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
-        id2, x2, y2, z2 = self._display.GetPointOnSurface(
-                      event.GetX(), size[1] - event.GetY())
-        if id1 and id1 == id2:
-            dx, dy, dz = x2 - x1, y2 - y1, z2 - z1
-            focus = self.iview['focus']
-            focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
-            focus['x'] -= dx
-            focus['y'] -= dy
-            focus['z'] -= dz
-            
-            #update properties
-            self.PostViewEvent()
-            
-            self.mouse['tmp'] = event.GetPositionTuple()
-            self.render['quick'] = True
-            self.Refresh(False)
-            
-    def HorizontalPanning(self, event):
-        """!Move all layers in horizontal (x, y) direction.
-        Currently not used.
-        """
-        size = self.GetClientSizeTuple()
-        id1, x1, y1, z1 = self._display.GetPointOnSurface(
-                      self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
-        id2, x2, y2, z2 = self._display.GetPointOnSurface(
-                      event.GetX(), size[1] - event.GetY())
-        
-        if id1 and id1 == id2:
-            dx, dy = x2 - x1, y2 - y1
-            # find raster and volume
-            for item in self.layers:
-                mapLayer = self.tree.GetPyData(item)[0]['maplayer']
-                  
-                data = self.tree.GetPyData(item)[0]['nviz']
-                if mapLayer.GetType() == 'raster':
-                    data['surface']['position']['x'] += dx
-                    data['surface']['position']['y'] += dy
-                    data['surface']['position']['update'] = None
-                    
-                    #update properties
-                    evt = wxUpdateProperties(data = data)
-                    wx.PostEvent(self, evt)
-                    
-                    if event.CmdDown() and id1 == data['surface']['object']['id']:
-                        break
-                    
-                elif mapLayer.GetType() == '3d-raster':
-                    if 'x' not in data['volume']['position']:
-                        data['volume']['position']['x'] = 0
-                        data['volume']['position']['y'] = 0
-                        data['volume']['position']['z'] = 0
-                    data['volume']['position']['x'] += dx
-                    data['volume']['position']['y'] += dy
-                    data['volume']['position']['update'] = None
-                    
-                    #update properties
-                    evt = wxUpdateProperties(data = data)
-                    wx.PostEvent(self, evt)
-                
-            self.mouse['tmp'] = event.GetPositionTuple()
-            self.render['quick'] = True
-            self.Refresh(False)
-            
-    def DragItem(self, id, event):
-        """!Drag an overlay decoration item
-        """
-        if not id: return
-        Debug.msg (5, "GLWindow.DragItem(): id=%d" % id)
-        x, y = self.mouse['tmp']
-        dx = event.GetX() - x
-        dy = event.GetY() - y
-        for texture in self.imagelist:
-            if texture.id == id:
-                texture.MoveTexture(dx, dy)
-
-
-        self.render['quick'] = True
-        self.Refresh(False)
-        
-        self.mouse['tmp'] = (event.GetX(), event.GetY()) 
-        
-    def ZoomBack(self):
-        """!Set previous view in history list
-        """
-        view = {}
-        if len(self.viewhistory) > 1:
-            self.viewhistory.pop()
-            view = copy.deepcopy(self.viewhistory[-1])
-        
-        # disable tool if stack is empty
-        if len(self.viewhistory) < 2: # disable tool
-            toolbar = self.parent.GetMapToolbar()
-            toolbar.Enable('zoomback', enable = False)
-            
-        # set view and update nviz view page
-        self.lmgr.nviz.UpdateState(view = view[0], iview = view[1])
-        self.lmgr.nviz.UpdatePage('view')
-        # update map
-        self.Refresh(False)
-
-    def ViewHistory(self, view, iview):
-        """!Manages a list of last 10 views
-        
-        @param view view dictionary
-        @param iview view dictionary (internal)
-        
-        @return removed history item if exists (or None)
-        """
-        removed = None
-        hview = copy.deepcopy(view)
-        hiview = copy.deepcopy(iview)
-        
-        if not (self.viewhistory and self.viewhistory[-1] == (hview, hiview)):  
-            self.viewhistory.append((hview, hiview))
-            
-        if len(self.viewhistory) > 10:
-            removed = self.viewhistory.pop(0)
-        
-        if removed:
-            Debug.msg(4, "GLWindow.ViewHistory(): hist=%s, removed=%s" %
-                      (self.viewhistory, removed))
-        else:
-            Debug.msg(4, "GLWindow.ViewHistory(): hist=%s" %
-                      (self.viewhistory))
-        
-        # update toolbar
-        if len(self.viewhistory) > 1:
-            enable = True
-        else:
-            enable = False
-        
-        toolbar = self.parent.GetMapToolbar()
-        toolbar.Enable('zoomback', enable)
-        
-        return removed     
-    
-    def ResetViewHistory(self):
-        """!Reset view history"""
-        self.viewhistory = list()
-    
-    def GoTo(self, e, n):
-        """!Focus on given point"""
-        w = self.Map.region['w']
-        s = self.Map.region['s']
-        e -= w
-        n -= s
-        focus = self.iview['focus']
-        focus['x'], focus['y'] = e, n
-        self.saveHistory = True
-        #update properties
-        self.PostViewEvent()
-        
-        self.render['quick'] = False
-        self.Refresh(False)
-    
-    def OnQueryMap(self, event):
-        """!Query raster and vector maps"""
-        self.OnQuerySurface(event)
-        self.parent.QueryMap(event.GetX(), event.GetY())
-        
-    def OnQuerySurface(self, event):
-        """!Query surface on given position"""
-        size = self.GetClientSizeTuple()
-        result = self._display.QueryMap(event.GetX(), size[1] - event.GetY())
-        if result:
-            self.qpoints.append((result['x'], result['y'], result['z']))
-            self.log.WriteLog("%-30s: %.3f" % (_("Easting"),   result['x']))
-            self.log.WriteLog("%-30s: %.3f" % (_("Northing"),  result['y']))
-            self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z']))
-            name = ''
-            for item in self.layers:
-                self.tree.GetPyData(item)[0]['nviz']
-                if self.tree.GetPyData(item)[0]['maplayer'].type == 'raster' and\
-                    self.tree.GetPyData(item)[0]['nviz']['surface']['object']['id'] == result['id']:
-                    name = self.tree.GetPyData(item)[0]['maplayer'].name
-            self.log.WriteLog("%-30s: %s" % (_("Surface map name"), name))
-            self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation']))
-            self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color']))
-            if len(self.qpoints) > 1:
-                prev = self.qpoints[-2]
-                curr = self.qpoints[-1]
-                dxy = math.sqrt(pow(prev[0]-curr[0], 2) +
-                                pow(prev[1]-curr[1], 2))
-                dxyz = math.sqrt(pow(prev[0]-curr[0], 2) +
-                                 pow(prev[1]-curr[1], 2) +
-                                 pow(prev[2]-curr[2], 2))
-                self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy))
-                self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz))
-                self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"),
-                                              self._display.GetDistanceAlongSurface(result['id'],
-                                                                                    (curr[0], curr[1]),
-                                                                                    (prev[0], prev[1]),
-                                                                                    useExag = False)))
-                self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"),
-                                              self._display.GetDistanceAlongSurface(result['id'],
-                                                                                    (curr[0], curr[1]),
-                                                                                    (prev[0], prev[1]),
-                                                                                      useExag = True)))
-            self.log.WriteCmdLog('-' * 80)
-        else:
-            self.log.WriteLog(_("No point on surface"))
-            self.log.WriteCmdLog('-' * 80)
-    
-    def PostViewEvent(self, zExag = False):
-        """!Change view settings"""
-        event = wxUpdateView(zExag = zExag)
-        wx.PostEvent(self, event)
-        
-    def OnQueryVector(self, event):
-        """!Query vector on given position"""
-        self.parent.QueryVector(*event.GetPosition())
-
-    def ChangeInnerView(self):
-        """!Get current viewdir and viewpoint and set view"""
-        view = self.view
-        iview = self.iview
-        (view['position']['x'], view['position']['y'],
-        iview['height']['value']) = self._display.GetViewpointPosition()
-        for key, val in zip(('x', 'y', 'z'), self._display.GetViewdir()):
-            iview['dir'][key] = val
-        
-        iview['dir']['use'] = True
-        
-    def OnUpdateView(self, event):
-        """!Change view settings"""
-        if event:
-                self.UpdateView(zexag = event.zExag)
-                
-        self.saveHistory = True
-        if event:
-            event.Skip()
-            
-            
-    def UpdateView(self, zexag = False):
-        """!Change view settings"""
-        view = self.view
-        iview = self.iview
-        if zexag and 'value' in view['z-exag']:
-            self._display.SetZExag(self.iview['z-exag']['original'] * view['z-exag']['value'])
-        
-        
-        self._display.SetView(view['position']['x'], view['position']['y'],
-                              iview['height']['value'],
-                              view['persp']['value'],
-                              view['twist']['value'])
-        
-        if iview['dir']['use']:
-            self._display.SetViewdir(iview['dir']['x'], iview['dir']['y'], iview['dir']['z'])
-        
-        elif iview['focus']['x'] != -1:
-            self._display.SetFocus(self.iview['focus']['x'], self.iview['focus']['y'],
-                                   self.iview['focus']['z'])
-                                       
-        if 'rotation' in iview:
-            if iview['rotation']:
-                self._display.SetRotationMatrix(iview['rotation'])
-            else:
-                self._display.ResetRotation()
-        
-    def UpdateLight(self, event):
-        """!Change light settings"""
-        data = self.light
-        self._display.SetLight(x = data['position']['x'], y = data['position']['y'],
-                               z = data['position']['z'] / 100., color = data['color'],
-                               bright = data['bright'] / 100.,
-                               ambient = data['ambient'] / 100.)
-        self._display.DrawLightingModel()
-        if event.refresh:
-            self.Refresh(False)
-        
-    def UpdateMap(self, render = True):
-        """!Updates the canvas anytime there is a change to the
-        underlaying images or to the geometry of the canvas.
-        
-        @param render re-render map composition
-        """
-        start = time.clock()
-        
-        self.resize = False
-        
-        if self.render['quick'] is False:
-            self.parent.GetProgressBar().Show()
-            self.parent.GetProgressBar().SetRange(2)
-            self.parent.GetProgressBar().SetValue(0)
-        
-        if self.render['quick'] is False:
-            self.parent.GetProgressBar().SetValue(1)
-            self._display.Draw(False, -1)
-            if self.saveHistory:
-                self.ViewHistory(view = self.view, iview = self.iview)
-                self.saveHistory = False
-        elif self.render['quick'] is True:
-            # quick
-            mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
-            if self.render['vlines']:
-                mode |=  wxnviz.DRAW_QUICK_VLINES
-            if self.render['vpoints']:
-                mode |=  wxnviz.DRAW_QUICK_VPOINTS
-            self._display.Draw(True, mode)
-        else: # None -> reuse last rendered image
-            pass # TODO
-            
-        self.SwapBuffers()
-        # draw fringe after SwapBuffers, otherwise it don't have to be visible
-        # on some computers
-        if self.render['quick'] is False:
-            self._display.DrawFringe()
-            if self.decoration['arrow']['show']:
-                self._display.DrawArrow()
-            if self.decoration['scalebar']:
-                self._display.DrawScalebar()
-        if self.imagelist:
-            if ((self.render['quick'] and self.dragid > -1) or # during dragging
-                (not self.render['quick'] and self.dragid < 0)): # redraw
-                self._display.Start2D()
-                self.DrawImages()
-                
-            
-            
-        stop = time.clock()
-        
-        if self.render['quick'] is False:
-            self.parent.GetProgressBar().SetValue(2)
-            # hide process bar
-            self.parent.GetProgressBar().Hide()
-        
-        Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \
-                      (self.render['quick'], (stop-start)))
-        
-    def EraseMap(self):
-        """!Erase the canvas
-        """
-        self._display.EraseMap()
-        self.SwapBuffers()
-    
-    def _getDecorationSize(self):
-        """!Get initial size of north arrow/scalebar"""
-        size = self._display.GetLongDim() / 8.
-        coef = 0.01
-        if size < 1:
-            coef = 100.
-        return int(size * coef)/coef
-    
-    def SetDrawArrow(self, pos):
-        
-        if self._display.SetArrow(pos[0], pos[1], 
-                                 self.decoration['arrow']['size'],
-                                 self.decoration['arrow']['color']):
-            self._display.DrawArrow()
-            # update
-            self.decoration['arrow']['show'] = True
-            self.decoration['arrow']['position']['x'] = pos[0]
-            self.decoration['arrow']['position']['y'] = pos[1]
-            self.Refresh(False)
-    
-    def SetDrawScalebar(self, pos):
-        """!Add scale bar, sets properties and draw"""
-        if len(self.decoration['scalebar']) == 0:
-            self.decoration['scalebar'].append(
-                    self.nvizDefault.SetDecorDefaultProp(type = 'scalebar')['scalebar'])
-            self.decoration['scalebar'][0]['size'] = self._getDecorationSize()
-        else:
-            self.decoration['scalebar'].append(copy.deepcopy(self.decoration['scalebar'][-1]))
-            self.decoration['scalebar'][-1]['id'] += 1
-        
-        ret = self._display.SetScalebar(self.decoration['scalebar'][-1]['id'], pos[0], pos[1], 
-                                 self.decoration['scalebar'][-1]['size'],
-                                 self.decoration['scalebar'][-1]['color'])
-        if ret:
-            self._display.DrawScalebar()
-            # update
-            self.decoration['scalebar'][-1]['position']['x'] = pos[0]
-            self.decoration['scalebar'][-1]['position']['y'] = pos[1]
-            self.Refresh(False)
-        
-    def IsLoaded(self, item):
-        """!Check if layer (item) is already loaded
-        
-        @param item layer item
-        """
-        layer = self.tree.GetPyData(item)[0]['maplayer']
-        data = self.tree.GetPyData(item)[0]['nviz']
-        
-        if not data:
-            return 0
-        
-        if layer.type ==  'raster':
-            if 'object' not in data['surface']:
-                return 0
-        elif layer.type ==  'vector':
-            if 'object' not in data['vlines'] and \
-                    'object' not in data['points']:
-                return 0
-        
-        return 1
-
-    def _GetDataLayers(self, item, litems):
-        """!Return get list of enabled map layers"""
-        # load raster & vector maps
-        while item and item.IsOk():
-            type = self.tree.GetPyData(item)[0]['type']
-            if type ==  'group':
-                subItem = self.tree.GetFirstChild(item)[0]
-                self._GetDataLayers(subItem, litems)
-                item = self.tree.GetNextSibling(item)
-                
-            if not item.IsChecked() or \
-                    type not in ('raster', 'vector', '3d-raster'):
-                item = self.tree.GetNextSibling(item)
-                continue
-            
-            litems.append(item)
-            
-            item = self.tree.GetNextSibling(item)
-        
-    def LoadDataLayers(self):
-        """!Load raster/vector from current layer tree
-        
-        @todo volumes
-        """
-        if not self.tree:
-            return
-        
-        listOfItems = []
-        item = self.tree.GetFirstChild(self.tree.root)[0]
-        self._GetDataLayers(item, listOfItems)
-        
-        start = time.time()
-        
-        while(len(listOfItems) > 0):
-            item = listOfItems.pop()
-            type = self.tree.GetPyData(item)[0]['type']
-            if item in self.layers:
-                continue
-            # "raster (double click to set properties)" - tries to load this 
-            # layer - no idea how to fix it
-            if ' ' in self.tree.GetPyData(item)[0]['maplayer'].name:
-                return
-            try:
-                if type ==  'raster':
-                    self.LoadRaster(item)
-                elif type ==  '3d-raster':
-                    self.LoadRaster3d(item)
-                elif type ==  'vector':
-                    # data = self.tree.GetPyData(item)[0]['nviz']
-                    # vecType = []
-                    # if data and 'vector' in data:
-                    #     for v in ('lines', 'points'):
-                    #         if data['vector'][v]:
-                    #             vecType.append(v)
-                    layer = self.tree.GetPyData(item)[0]['maplayer']
-                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
-                    if npoints > 0:
-                        self.LoadVector(item, points = True)
-                    if nlines > 0:
-                        self.LoadVector(item, points = False)
-            except gcmd.GException, e:
-                GError(parent = self,
-                       message = e.value)
-            self.init = False
-        
-        stop = time.time()
-        
-        Debug.msg(1, "GLWindow.LoadDataLayers(): time = %f" % (stop-start))
-                
-    def UnloadDataLayers(self, force = False):
-        """!Unload any layers that have been deleted from layer tree
-
-        @param force True to unload all data layers
-        """
-        if not self.tree:
-            return
-        
-        listOfItems = []
-        if not force:
-            item = self.tree.GetFirstChild(self.tree.root)[0]
-            self._GetDataLayers(item, listOfItems)
-        
-        start = time.time()
-        
-        update = False
-        layersTmp = self.layers[:]
-        for layer in layersTmp:
-            if layer in listOfItems:
-                continue
-            ltype = self.tree.GetPyData(layer)[0]['type']
-            try:
-                if ltype ==  'raster':
-                    self.UnloadRaster(layer)
-                elif ltype ==  '3d-raster':
-                    self.UnloadRaster3d(layer) 
-                elif ltype ==  'vector':
-                    maplayer = self.tree.GetPyData(layer)[0]['maplayer']
-                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(maplayer)
-                    if npoints > 0:
-                        self.UnloadVector(layer, points = True)
-                    if nlines > 0:
-                        self.UnloadVector(layer, points = False)
-                        
-            except gcmd.GException, e:
-                gcmd.GError(parent = self,
-                            message = e.value)
-        
-        if force and self.baseId > 0: # unload base surface when quitting
-            ret = self._display.UnloadSurface(self.baseId)
-            self.baseId = -1
-        if update:
-            self.lmgr.nviz.UpdateSettings()        
-            self.UpdateView(None)
-        
-        stop = time.time()
-        
-        Debug.msg(1, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start))        
-        
-    def SetVectorSurface(self, data):
-        """!Set reference surfaces of vector"""
-        data['mode']['surface'] = {}
-        data['mode']['surface']['value'] = list()
-        data['mode']['surface']['show'] = list()
-        for name in self.GetLayerNames('raster'):
-            data['mode']['surface']['value'].append(name)
-            data['mode']['surface']['show'].append(True)
-        
-    def SetVectorFromCmd(self, item, data):
-        """!Set 3D view properties from cmd (d.vect)
-
-        @param item Layer Tree item
-        @param nviz data
-        """
-        cmd = self.tree.GetPyData(item)[0]['cmd']
-        if cmd[0] != 'd.vect':
-            return
-        for opt in cmd[1:]:
-            try:
-                key, value = opt.split('=')
-            except ValueError:
-                continue
-            if key == 'color':
-                data['lines']['color']['value'] = value
-                data['points']['color']['value'] = value
-
-    def SetMapObjProperties(self, item, id, nvizType):
-        """!Set map object properties
-        
-        Properties must be afterwards updated by
-        UpdateMapObjProperties().
-        
-        @param item layer item
-        @param id nviz layer id (or -1)
-        @param nvizType nviz data type (surface, points, vector)
-        """
-        if nvizType != 'constant':
-            mapType = self.tree.GetPyData(item)[0]['maplayer'].type
-            # reference to original layer properties (can be None)
-            data = self.tree.GetPyData(item)[0]['nviz']
-        else:
-            mapType = nvizType
-            data = self.constants[item]
-        
-        if not data:
-            # init data structure
-            if nvizType != 'constant':
-                self.tree.GetPyData(item)[0]['nviz'] = {}
-                data = self.tree.GetPyData(item)[0]['nviz']
-            
-            if mapType ==  'raster':
-                # reset to default properties
-                data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp()
-                        
-            elif mapType ==  'vector':
-                # reset to default properties (lines/points)
-                data['vector'] = self.nvizDefault.SetVectorDefaultProp()
-                self.SetVectorFromCmd(item, data['vector'])
-                self.SetVectorSurface(data['vector']['points'])
-                self.SetVectorSurface(data['vector']['lines'])
-                
-            elif mapType ==  '3d-raster':
-                # reset to default properties 
-                data[nvizType] = self.nvizDefault.SetVolumeDefaultProp()
-                
-            elif mapType == 'constant':
-                data['constant'] = self.nvizDefault.SetConstantDefaultProp()
-        
-        else:
-            # complete data (use default values), not sure if this is necessary
-            if mapType ==  'raster':
-                if not data['surface']:
-                    data['surface'] = self.nvizDefault.SetSurfaceDefaultProp()
-            if mapType ==  'vector':
-                if not data['vector']['lines']:
-                    self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
-                if not data['vector']['points']:
-                    self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])     
-            # set updates
-            for sec in data.keys():
-                for sec1 in data[sec].keys():
-                    if sec1 == 'position':
-                        data[sec][sec1]['update'] = None
-                        continue
-                    if type(data[sec][sec1]) == types.DictType:
-                        for sec2 in data[sec][sec1].keys():
-                            if sec2 not in ('all', 'init', 'id'):
-                                data[sec][sec1][sec2]['update'] = None
-                    elif type(data[sec][sec1]) == types.ListType:
-                        for i in range(len(data[sec][sec1])):
-                            for sec2 in data[sec][sec1][i].keys():
-                                data[sec][sec1][i][sec2]['update'] = None
-            event = wxUpdateProperties(data = data)
-            wx.PostEvent(self, event)
-        
-        # set id
-        if id > 0:
-            if mapType in ('raster', '3d-raster'):
-                data[nvizType]['object'] = { 'id' : id,
-                                            'init' : False }
-            elif mapType ==  'vector':
-                data['vector'][nvizType]['object'] = { 'id' : id,
-                                                       'init' : False }
-            elif mapType ==  'constant':
-                data[nvizType]['object'] = { 'id' : id,
-                                             'init' : False }
-        
-        return data
-
-    def LoadRaster(self, item):
-        """!Load 2d raster map and set surface attributes
-        
-        @param layer item
-        """
-        return self._loadRaster(item)
-    
-    def LoadRaster3d(self, item):
-        """!Load 3d raster map and set surface attributes
-        
-        @param layer item
-        """
-        return self._loadRaster(item)
-    
-    def _loadRaster(self, item):
-        """!Load 2d/3d raster map and set its attributes
-        
-        @param layer item
-        """
-        layer = self.tree.GetPyData(item)[0]['maplayer']
-        
-        if layer.type not in ('raster', '3d-raster'):
-            return
-        
-        if layer.type ==  'raster':
-            id = self._display.LoadSurface(str(layer.name), None, None)
-            nvizType = 'surface'
-            errorMsg = _("Loading raster map")
-        elif layer.type ==  '3d-raster':
-            id = self._display.LoadVolume(str(layer.name), None, None)
-            nvizType = 'volume'
-            errorMsg = _("Loading 3d raster map")
-        else:
-            id = -1
-        
-        if id < 0:
-            if layer.type in ('raster', '3d-raster'):
-                self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed")))
-            else:
-                self.log.WriteError(_("Unsupported layer type '%s'") % layer.type)
-        
-        self.layers.append(item)
-        
-        # set default/workspace layer properties
-        data = self.SetMapObjProperties(item, id, nvizType)
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self, event)
-        
-        # update tools window
-        if hasattr(self.lmgr, "nviz") and \
-                item ==  self.GetSelectedLayer(type = 'item'):
-            toolWin = self.lmgr.nviz
-            if layer.type ==  'raster':
-                win = toolWin.FindWindowById( \
-                    toolWin.win['vector']['lines']['surface'])
-                win.SetItems(self.GetLayerNames(layer.type))
-            
-            #toolWin.UpdatePage(nvizType)
-            #toolWin.SetPage(nvizType)
-        
-        return id
-    
-    def NewConstant(self):
-        """!Create new constant"""
-        index = len(self.constants)
-        try:
-            name = self.constants[-1]['constant']['object']['name'] + 1
-        except IndexError:
-            name = 1
-        data = dict()
-        self.constants.append(data)
-        data = self.SetMapObjProperties(item = index, id = -1, nvizType = 'constant')
-        self.AddConstant(data, name)
-        return name
-        
-    def AddConstant(self, data, name):
-        """!Add new constant"""
-        id = self._display.AddConstant(value = data['constant']['value'], color = data['constant']['color'])
-        self._display.SetSurfaceRes(id, data['constant']['resolution'], data['constant']['resolution'])
-        data['constant']['object'] = { 'id' : id,
-                                       'name': name,
-                                       'init' : False }
-    
-    def DeleteConstant(self, index):
-        """!Delete constant layer"""
-        id = self.constants[index]['constant']['object']['id']
-        self._display.UnloadSurface(id)
-        del self.constants[index]
-    
-    def SelectCPlane(self, index):
-        """!Select cutting plane"""
-        for plane in range (self._display.GetCPlanesCount()):
-            if plane == index:
-                self._display.SelectCPlane(plane)
-                self.cplanes[plane]['on'] = True
-                self._display.SetFenceColor(self.cplanes[plane]['shading'])
-            else:
-                self._display.UnselectCPlane(plane)
-                try:
-                    self.cplanes[plane]['on'] = False
-                except IndexError:
-                    pass
-                    
-    def UpdateCPlane(self, event):
-        """!Change cutting plane settings"""
-        current = event.current
-        for each in event.update:
-            if each == 'rotation':
-                self._display.SetCPlaneRotation(0, self.cplanes[current]['rotation']['tilt'],
-                                                   self.cplanes[current]['rotation']['rot'])
-            if each == 'position':
-                self._display.SetCPlaneTranslation(self.cplanes[current]['position']['x'],
-                                                   self.cplanes[current]['position']['y'],
-                                                   self.cplanes[current]['position']['z'])
-            if each == 'shading':
-                self._display.SetFenceColor(self.cplanes[current]['shading'])
-            
-    def UnloadRaster(self, item):
-        """!Unload 2d raster map
-        
-        @param layer item
-        """
-        return self._unloadRaster(item)
-    
-    def UnloadRaster3d(self, item):
-        """!Unload 3d raster map
-        
-        @param layer item
-        """
-        return self._unloadRaster(item)
-    
-    def _unloadRaster(self, item):
-        """!Unload 2d/3d raster map
-        
-        @param item layer item
-        """
-        layer = self.tree.GetPyData(item)[0]['maplayer']
-        
-        if layer.type not in ('raster', '3d-raster'):
-            return
-        
-        data = self.tree.GetPyData(item)[0]['nviz']
-        
-        if layer.type ==  'raster':
-            nvizType = 'surface'
-            unloadFn = self._display.UnloadSurface
-            errorMsg = _("Unable to unload raster map")
-            successMsg = _("Raster map")
-        else:
-            nvizType = 'volume'
-            unloadFn = self._display.UnloadVolume
-            errorMsg = _("Unable to unload 3d raster map")
-            successMsg = _("3d raster map")
-        
-        try:
-            id = data[nvizType]['object']['id']
-        except KeyError:
-            return
-        
-        if unloadFn(id) ==  0:
-            self.log.WriteError("%s <%s>" % (errorMsg, layer.name))
-        else:
-            self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully")))
-        
-        data[nvizType].pop('object')
-        
-        self.layers.remove(item)
-        
-        # update tools window
-        if hasattr(self.lmgr, "nviz"):
-            toolWin = self.lmgr.nviz
-            if layer.type ==  'raster':
-                win = toolWin.FindWindowById(toolWin.win['vector']['lines']['surface'])
-                win.SetItems(self.GetLayerNames(layer.type))
-                win = toolWin.FindWindowById(toolWin.win['surface']['map'])
-                win.SetValue('')
-            if layer.type ==  '3d-raster':
-                win = toolWin.FindWindowById(toolWin.win['volume']['map'])
-                win.SetValue('')
-            if layer.type ==  'vector':
-                win = toolWin.FindWindowById(toolWin.win['vector']['map'])
-                win.SetValue('')
-        
-    def LoadVector(self, item, points = None, append = True):
-        """!Load 2D or 3D vector map overlay
-        
-        @param item layer item
-        @param points True to load points, False to load lines, None
-        to load both
-        @param append append vector to layer list
-        """
-        layer = self.tree.GetPyData(item)[0]['maplayer']
-        if layer.type !=  'vector':
-            return
-        
-        # set default properties
-        if points is None:
-            self.SetMapObjProperties(item, -1, 'lines')
-            self.SetMapObjProperties(item, -1, 'points')
-            vecTypes = ('points', 'lines')
-        elif points:
-            self.SetMapObjProperties(item, -1, 'points')
-            vecTypes = ('points', )
-        else:
-            self.SetMapObjProperties(item, -1, 'lines')
-            vecTypes = ('lines', )
-        
-        id = -1
-        for vecType in vecTypes:
-            if vecType == 'lines':
-                id, baseId = self._display.LoadVector(str(layer.GetName()), False)
-            else:
-                id, baseId = self._display.LoadVector(str(layer.GetName()), True)
-            if id < 0:
-                self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \
-                    { 'name' : layer.name, 'type' : vecType })
-            # update layer properties
-            self.SetMapObjProperties(item, id, vecType)
-        if baseId > 0:
-            self.baseId = baseId # id of base surface (when no surface is loaded)
-        if append:
-            self.layers.append(item)
-        
-        # update properties
-        data = self.tree.GetPyData(item)[0]['nviz']
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self, event)
-        
-        # update tools window
-        if hasattr(self.lmgr, "nviz") and \
-                item ==  self.GetSelectedLayer(type = 'item'):
-            toolWin = self.lmgr.nviz
-            
-            toolWin.UpdatePage('vector')
-            ### toolWin.SetPage('vector')
-        
-        return id
-
-    def UnloadVector(self, item, points = None, remove = True):
-        """!Unload vector map overlay
-        
-        @param item layer item
-        @param points,lines True to unload given feature type
-        @param remove remove layer from list
-        """
-        layer = self.tree.GetPyData(item)[0]['maplayer']
-        data = self.tree.GetPyData(item)[0]['nviz']['vector']
-        
-        # if vecType is None:
-        #     vecType = []
-        #     for v in ('lines', 'points'):
-        #         if UserSettings.Get(group = 'nviz', key = 'vector',
-        #                             subkey = [v, 'show']):
-        #             vecType.append(v)
-        
-        if points is None:
-            vecTypes = ('points', 'lines')
-        elif points:
-            vecTypes = ('points', )
-        else:
-            vecTypes = ('lines', )
-        
-        for vecType in vecTypes:
-            if 'object' not in data[vecType]:
-                continue
-
-            id = data[vecType]['object']['id']
-            
-            if vecType ==  'lines':
-                ret = self._display.UnloadVector(id, False)
-            else:
-                ret = self._display.UnloadVector(id, True)
-            if ret ==  0:
-                self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \
-                    { 'name': layer.name, 'type' : vecType })
-            else:
-                self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
-                    { 'name' : layer.name, 'type' : vecType })
-            
-            data[vecType].pop('object')
-            
-        if remove and item in self.layers:
-            self.layers.remove(item)
-
-    def ResetView(self):
-        """!Reset to default view"""
-        self.iview['z-exag']['original'], \
-            self.iview['height']['value'], \
-            self.iview['height']['min'], \
-            self.iview['height']['max'] = self._display.SetViewDefault()
-            
-        ## set initial z-exag value at 1X    
-        self.view['z-exag']['value'] = 1.0
-        
-        self.view['z-exag']['min'] = UserSettings.Get(group = 'nviz', key = 'view',
-                                                      subkey = ('z-exag', 'min'))        
-        zexagMax = UserSettings.Get(group = 'nviz', key = 'view',
-                                    subkey = ('z-exag', 'max'))        
-        
-        self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view',
-                                                 subkey = ('position', 'x'))
-        self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view',
-                                                 subkey = ('position', 'y'))
-        self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
-                                                       subkey = ('persp', 'value'))
-        
-        self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
-                                                       subkey = ('twist', 'value'))
-        self._display.ResetRotation()
-        self.iview['rotation'] = None
-        self._display.LookAtCenter()
-        focus = self.iview['focus']
-        focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
-        
-        self.PostViewEvent()
-        
-    def UpdateMapObjProperties(self, event):
-        """!Generic method to update data layer properties"""
-        data = event.data
-        
-        if 'surface' in data:
-            try:
-                id = data['surface']['object']['id']
-            except KeyError:
-                return
-            self.UpdateSurfaceProperties(id, data['surface'])
-            # -> initialized
-            data['surface']['object']['init'] = True
-            
-        elif 'constant' in data:
-            id = data['constant']['object']['id']
-            self.UpdateConstantProperties(id, data['constant'])
-            # -> initialized
-            data['constant']['object']['init'] = True  
-              
-        elif 'volume' in data:
-            id = data['volume']['object']['id']
-            self.UpdateVolumeProperties(id, data['volume'])
-            # -> initialized
-            data['volume']['object']['init'] = True
-            
-        elif 'vector' in data:
-            for type in ('lines', 'points'):
-                if 'object' in data['vector'][type]:
-                    id = data['vector'][type]['object']['id']
-                    self.UpdateVectorProperties(id, data['vector'], type)
-                    # -> initialized
-                    data['vector'][type]['object']['init'] = True
-    
-    def UpdateConstantProperties(self, id, data):
-        """!Update surface map object properties"""
-        self._display.SetSurfaceColor(id = id, map = False, value = data['color'])
-        self._display.SetSurfaceTopo(id = id, map = False, value = data['value'])
-        self._display.SetSurfaceRes(id, data['resolution'], data['resolution'])
-        if data['transp'] == 0:
-            self._display.UnsetSurfaceTransp(id)
-        else:
-            self._display.SetSurfaceTransp(id, map = False, value = data['transp'])
-            
-    def UpdateSurfaceProperties(self, id, data):
-        """!Update surface map object properties"""
-        # surface attributes
-        for attrb in ('color', 'mask',
-                     'transp', 'shine'):
-            if attrb not in data['attribute'] or \
-                    'update' not in data['attribute'][attrb]:
-                continue
-            
-            map = data['attribute'][attrb]['map']
-            value = data['attribute'][attrb]['value']
-            
-            if map is None: # unset
-                # only optional attributes
-                if attrb ==  'mask':
-                    # TODO: invert mask
-                    # TODO: broken in NVIZ
-                    self._display.UnsetSurfaceMask(id)
-                elif attrb ==  'transp':
-                    self._display.UnsetSurfaceTransp(id) 
-            else:
-                if type(value) == types.StringType and \
-                        len(value) <=  0: # ignore empty values (TODO: warning)
-                    continue
-                if attrb ==  'color':
-                    self._display.SetSurfaceColor(id, map, str(value))
-                elif attrb ==  'mask':
-                    # TODO: invert mask
-                    # TODO: broken in NVIZ
-                    self._display.SetSurfaceMask(id, False, str(value))
-                elif attrb ==  'transp':
-                    self._display.SetSurfaceTransp(id, map, str(value)) 
-                elif attrb ==  'shine':
-                    self._display.SetSurfaceShine(id, map, str(value)) 
-            data['attribute'][attrb].pop('update')
-        
-        # draw res
-        if 'update' in data['draw']['resolution']:
-            coarse = data['draw']['resolution']['coarse']
-            fine   = data['draw']['resolution']['fine']
-            
-            if data['draw']['all']:
-                self._display.SetSurfaceRes(-1, fine, coarse)
-            else:
-                self._display.SetSurfaceRes(id, fine, coarse)
-            data['draw']['resolution'].pop('update')
-        
-        # draw style
-        if 'update' in data['draw']['mode']:
-            if data['draw']['mode']['value'] < 0: # need to calculate
-                data['draw']['mode']['value'] = \
-                    self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'],
-                                                 style = data['draw']['mode']['desc']['style'],
-                                                 shade = data['draw']['mode']['desc']['shading'],
-                                                 string = True)
-            style = data['draw']['mode']['value']
-            if data['draw']['all']:
-                self._display.SetSurfaceStyle(-1, style)
-            else:
-                self._display.SetSurfaceStyle(id, style)
-            data['draw']['mode'].pop('update')
-        
-        # wire color
-        if 'update' in data['draw']['wire-color']:
-            color = data['draw']['wire-color']['value']
-            if data['draw']['all']:
-                self._display.SetWireColor(-1, str(color))
-            else:
-                self._display.SetWireColor(id, str(color))
-            data['draw']['wire-color'].pop('update')
-        
-        # position
-        if 'update' in data['position']:
-            x = data['position']['x']
-            y = data['position']['y']
-            z = data['position']['z']
-            self._display.SetSurfacePosition(id, x, y, z)
-            data['position'].pop('update')
-        data['draw']['all'] = False
-        
-    def UpdateVolumeProperties(self, id, data, isosurfId = None):
-        """!Update volume (isosurface/slice) map object properties"""
-        if 'update' in data['draw']['resolution']:
-            if data['draw']['mode']['value'] == 0:
-                self._display.SetIsosurfaceRes(id, data['draw']['resolution']['isosurface']['value'])
-            else:
-                self._display.SetSliceRes(id, data['draw']['resolution']['slice']['value'])                
-            data['draw']['resolution'].pop('update')
-        
-        if 'update' in data['draw']['shading']:
-            if data['draw']['mode']['value'] == 0:
-                if data['draw']['shading']['isosurface']['value'] < 0: # need to calculate
-                    mode = data['draw']['shading']['isosurface']['value'] = \
-                        self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['isosurface'],
-                                                     string = False)
-                    self._display.SetIsosurfaceMode(id, mode)
-            else:
-                if data['draw']['shading']['slice']['value'] < 0: # need to calculate
-                    mode = data['draw']['shading']['slice']['value'] = \
-                        self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['slice'],
-                                                     string = False)
-                    self._display.SetSliceMode(id, mode)
-            data['draw']['shading'].pop('update')
-        
-        #
-        # isosurface attributes
-        #
-        isosurfId = 0
-        for isosurf in data['isosurface']:
-            self._display.AddIsosurface(id, 0, isosurf_id = isosurfId)
-            for attrb in ('topo', 'color', 'mask',
-                          'transp', 'shine'):
-                if attrb not in isosurf or \
-                        'update' not in isosurf[attrb]:
-                    continue
-                map = isosurf[attrb]['map']
-                value = isosurf[attrb]['value']
-                
-                if map is None: # unset
-                    # only optional attributes
-                    if attrb == 'topo' :
-                        self._display.SetIsosurfaceTopo(id, isosurfId, map, str(value))
-                    elif attrb ==  'mask':
-                        # TODO: invert mask
-                        # TODO: broken in NVIZ
-                        self._display.UnsetIsosurfaceMask(id, isosurfId)
-                    elif attrb ==  'transp':
-                        self._display.UnsetIsosurfaceTransp(id, isosurfId) 
-                else:
-                    if type(value) == types.StringType and \
-                            len(value) <=  0: # ignore empty values (TODO: warning)
-                        continue
-                    elif attrb ==  'color':
-                        self._display.SetIsosurfaceColor(id, isosurfId, map, str(value))
-                    elif attrb ==  'mask':
-                        # TODO: invert mask
-                        # TODO: broken in NVIZ
-                        self._display.SetIsosurfaceMask(id, isosurfId, False, str(value))
-                    elif attrb ==  'transp':
-                        self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value)) 
-                    elif attrb ==  'shine':
-                        self._display.SetIsosurfaceShine(id, isosurfId, map, str(value))  
-                isosurf[attrb].pop('update')
-            isosurfId +=  1
-        #
-        # slice attributes
-        #
-        sliceId = 0
-        for slice in data['slice']:
-            ret = self._display.AddSlice(id, slice_id = sliceId)
-            if 'update' in slice['position']:
-                pos = slice['position']
-                ret = self._display.SetSlicePosition(id, sliceId, pos['x1'], pos['x2'],
-                                               pos['y1'], pos['y2'], pos['z1'], pos['z2'], pos['axis'])
-                
-                slice['position'].pop('update')
-            if 'update' in slice['transp']:
-                tr = slice['transp']['value']
-                self._display.SetSliceTransp(id, sliceId, tr)
-            sliceId += 1
-                
-        # position
-        if 'update' in data['position']:
-            x = data['position']['x']
-            y = data['position']['y']
-            z = data['position']['z']
-            self._display.SetVolumePosition(id, x, y, z)
-            data['position'].pop('update')
-            
-    def UpdateVectorProperties(self, id, data, type):
-        """!Update vector layer properties
-        
-        @param id layer id
-        @param data properties
-        @param type lines/points
-        """
-        if type ==  'points':
-            self.UpdateVectorPointsProperties(id, data[type])
-        else:
-            self.UpdateVectorLinesProperties(id, data[type])
-        
-    def UpdateVectorLinesProperties(self, id, data):
-        """!Update vector line map object properties"""
-        # mode
-        if 'update' in data['color'] or \
-                'update' in data['width'] or \
-                'update' in data['mode']:
-            width = data['width']['value']
-            color = data['color']['value']
-            if data['mode']['type'] ==  'flat':
-                flat = True
-                if 'surface' in data['mode']:
-                    data['mode'].pop('surface')
-            else:
-                flat = False
-            
-            self._display.SetVectorLineMode(id, color,
-                                            width, flat)
-            
-            if 'update' in data['color']:
-                data['color'].pop('update')
-            if 'update' in data['width']:
-                data['width'].pop('update')
-        
-        # height
-        if 'update' in data['height']:
-            self._display.SetVectorLineHeight(id,
-                                              data['height']['value'])
-            data['height'].pop('update')
-            
-        # thematic
-        if 'update' in data['thematic']:
-            color = width = None
-            colorTable = False
-            if data['thematic']['usecolor'] or data['thematic']['usewidth']:
-                if data['thematic']['usecolor']:
-                    color = data['thematic']['rgbcolumn']
-                    if self._display.CheckColorTable(id = id, type = 'lines'):
-                        colorTable = True
-                if data['thematic']['usewidth']:
-                    width = data['thematic']['sizecolumn']
-                self._display.SetLinesStyleThematic(id = id, layer = data['thematic']['layer'],
-                                                     color = color,
-                                                     colorTable = colorTable, 
-                                                     width = width)
-            else:
-                self._display.UnsetLinesStyleThematic(id = id)
-            data['thematic'].pop('update')
-        # surface
-        if 'surface' in data['mode'] and 'update' in data['mode']:
-            for item in range(len(data['mode']['surface']['value'])):
-                for type in ('raster', 'constant'):
-                    sid = self.GetLayerId(type = type,
-                                          name = data['mode']['surface']['value'][item])
-                    if sid > -1:
-                        if data['mode']['surface']['show'][item]:
-                            self._display.SetVectorLineSurface(id, sid)
-                        else:
-                            self._display.UnsetVectorLineSurface(id, sid)
-                        break
-                
-        if 'update' in data['mode']:
-                data['mode'].pop('update')
-        
-    def UpdateVectorPointsProperties(self, id, data):
-        """!Update vector point map object properties"""
-        if 'update' in data['size'] or \
-                'update' in data['width'] or \
-                'update' in data['marker'] or \
-                'update' in data['color']:
-                
-            ret = self._display.SetVectorPointMode(id, data['color']['value'],
-                                                   data['width']['value'], float(data['size']['value']),
-                                                   data['marker']['value'] + 1)
-            
-            error = None
-            if ret ==  -1:
-                error = _("Vector point layer not found (id = %d)") % id
-            elif ret ==  -2:
-                error = _("Unable to set data layer properties (id = %d)") % id
-
-            if error:
-                raise gcmd.GException(_("Setting data layer properties failed.\n\n%s") % error)
-            
-            for prop in ('size', 'width', 'marker', 'color'):
-                if 'update' in data[prop]:
-                    data[prop].pop('update')
-        
-        # height
-        if 'update' in data['height']:
-            self._display.SetVectorPointHeight(id,
-                                               data['height']['value'])
-            data['height'].pop('update')
-        
-        # thematic
-        if 'update' in data['thematic']:
-            color = size = None
-            colorTable = False
-            if data['thematic']['usecolor'] or data['thematic']['usesize']:
-                if data['thematic']['usecolor']:
-                    color = data['thematic']['rgbcolumn']
-                    if self._display.CheckColorTable(id = id, type = 'points'):
-                        colorTable = True
-                if data['thematic']['usesize']:
-                    size = data['thematic']['sizecolumn']
-                self._display.SetPointsStyleThematic(id = id, layer = data['thematic']['layer'],
-                                                     color = color,
-                                                     colorTable = colorTable, 
-                                                     size = size)
-            else:
-                self._display.UnsetPointsStyleThematic(id = id)
-            data['thematic'].pop('update')
-            
-        # surface
-        if 'update' in data['mode'] and 'surface' in data['mode']:
-            for item in range(len(data['mode']['surface']['value'])):
-                for type in ('raster', 'constant'):
-                    sid = self.GetLayerId(type = type,
-                                          name = data['mode']['surface']['value'][item])
-                    if sid > -1:
-                        if data['mode']['surface']['show'][item]:
-                            self._display.SetVectorPointSurface(id, sid)
-                        else:
-                            self._display.UnsetVectorPointSurface(id, sid)   
-                        break
-            data['mode'].pop('update')
-            
-    def GetLayerNames(self, type):
-        """!Return list of map layer names of given type"""
-        layerName = []
-        
-        if type == 'constant':
-            for item in self.constants:
-                layerName.append(_("constant#") + str(item['constant']['object']['name']))
-        else:    
-            for item in self.layers:
-                mapLayer = self.tree.GetPyData(item)[0]['maplayer']
-                if type !=  mapLayer.GetType():
-                    continue
-                
-                layerName.append(mapLayer.GetName())
-        
-        return layerName
-    
-    def GetLayerId(self, type, name, vsubtyp = None):
-        """!Get layer object id or -1"""
-        if len(name) < 1:
-            return -1
-        
-        if type == 'constant':
-            for item in self.constants:
-                if _("constant#") + str(item['constant']['object']['name']) == name:
-                    return item['constant']['object']['id']
-                
-        
-        for item in self.layers:
-            mapLayer = self.tree.GetPyData(item)[0]['maplayer']
-            if type !=  mapLayer.GetType() or \
-                    name !=  mapLayer.GetName():
-                continue
-            
-            data = self.tree.GetPyData(item)[0]['nviz']
-            
-            try:
-                if type ==  'raster':
-                    return data['surface']['object']['id']
-                elif type ==  'vector':
-                    if vsubtyp == 'vpoint':
-                        return data['vector']['points']['object']['id']
-                    elif vsubtyp ==  'vline':
-                        return data['vector']['lines']['object']['id']
-                elif type ==  '3d-raster':
-                    return data['volume']['object']['id']
-            except KeyError:
-                return -1
-        return -1
-    
-    def ReloadLayersData(self):
-        """!Delete nviz data of all loaded layers and reload them from current settings"""
-        for item in self.layers:
-            type = self.tree.GetPyData(item)[0]['type']
-            layer = self.tree.GetPyData(item)[0]['maplayer']
-            data = self.tree.GetPyData(item)[0]['nviz']
-            
-            if type == 'raster':
-                self.nvizDefault.SetSurfaceDefaultProp(data['surface'])
-            if type == 'vector':
-                npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
-                if npoints > 0:
-                    self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
-                if nlines > 0:
-                    self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
-            
-    def NvizCmdCommand(self):
-        """!Generate command for m.nviz.image according to current state"""
-        cmd = 'm.nviz.image '
-        
-        rasters = []
-        vectors = []
-        volumes = []
-        for item in self.layers:
-            if self.tree.GetPyData(item)[0]['type'] == 'raster':
-                rasters.append(item)
-            elif self.tree.GetPyData(item)[0]['type'] == '3d-raster':
-                volumes.append(item)
-            elif self.tree.GetPyData(item)[0]['type'] == 'vector':
-                vectors.append(item)
-        if not rasters and not self.constants:
-            return _("At least one raster map required")
-        # elevation_map/elevation_value
-        if self.constants:
-            subcmd = "elevation_value="
-            for constant in self.constants:
-                subcmd += "%d," % constant['constant']['value']
-            subcmd = subcmd.strip(', ') + ' '
-            cmd += subcmd
-        if rasters:
-            subcmd = "elevation_map="
-            for item in rasters:
-                subcmd += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
-            subcmd = subcmd.strip(', ') + ' '
-            cmd += subcmd
-            #
-            # draw mode
-            #
-            cmdMode = "mode="
-            cmdFine = "resolution_fine="
-            cmdCoarse = "resolution_coarse="
-            cmdShading = "shading="
-            cmdStyle = "style="
-            cmdWire = "wire_color="
-            # test -a flag
-            flag_a = "-a "
-            nvizDataFirst = self.tree.GetPyData(rasters[0])[0]['nviz']['surface']['draw']
-            for item in rasters:
-                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
-                if nvizDataFirst != nvizData:
-                    flag_a = ""
-            cmd += flag_a
-            for item in rasters:
-                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
-                
-                cmdMode += "%s," % nvizData['mode']['desc']['mode']
-                cmdFine += "%s," % nvizData['resolution']['fine']
-                cmdCoarse += "%s," % nvizData['resolution']['coarse']
-                cmdShading += "%s," % nvizData['mode']['desc']['shading']
-                cmdStyle += "%s," % nvizData['mode']['desc']['style']
-                cmdWire += "%s," % nvizData['wire-color']['value']
-            for item in self.constants:
-                cmdMode += "fine,"
-                cmdFine += "%s," % item['constant']['resolution']
-                cmdCoarse += "%s," % item['constant']['resolution']
-                cmdShading += "gouraud,"
-                cmdStyle += "surface,"
-                cmdWire += "0:0:0,"
-            mode = []
-            for subcmd in (cmdMode, cmdFine, cmdCoarse, cmdShading, cmdStyle, cmdWire):
-                if flag_a:
-                    mode.append(subcmd.split(',')[0] + ' ')
-                else:
-                    subcmd = subcmd.strip(', ') + ' '
-                    cmd += subcmd
-            if flag_a:# write only meaningful possibilities
-                cmd += mode[0]
-                if 'fine' in mode[0]:
-                    cmd += mode[1]
-                elif 'coarse' in mode[0]:
-                    cmd += mode[2]            
-                elif 'both' in mode[0]:
-                    cmd += mode[2]
-                    cmd += mode[1]
-                if 'flat' in mode[3]:
-                    cmd += mode[3]
-                if 'wire' in mode[4]:
-                    cmd += mode[4]
-                if 'coarse' in mode[0] or 'both' in mode[0] and 'wire' in mode[3]:
-                    cmd += mode[5]
-            #
-            # attributes
-            #
-            cmdColorMap = "color_map="
-            cmdColorVal = "color="
-            for item in rasters:
-                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['attribute']
-                if 'color' not in nvizData:
-                    cmdColorMap += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
-                else:
-                    if nvizData['color']['map']:
-                        cmdColorMap += "%s," % nvizData['color']['value']
-                    else:
-                        cmdColorVal += "%s," % nvizData['color']['value']
-                        #TODO
-                        # transparency, shine, mask
-            for item in self.constants:
-                cmdColorVal += "%s," % item['constant']['color']
-            if cmdColorMap.split("=")[1]:
-                cmd += cmdColorMap.strip(', ') + ' '
-            if cmdColorVal.split("=")[1]:
-                cmd += cmdColorVal.strip(', ') + ' '
-            cmd += "\\\n"
-        #
-        # vlines
-        #
-        if vectors:
-            cmdLines = cmdLWidth = cmdLHeight = cmdLColor = cmdLMode = cmdLPos = \
-            cmdPoints = cmdPWidth = cmdPSize = cmdPColor = cmdPMarker = cmdPPos = cmdPLayer = ""
-            markers = ['x', 'box', 'sphere', 'cube', 'diamond',
-                       'dec_tree', 'con_tree', 'aster', 'gyro', 'histogram']
-            for vector in vectors:
-                npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(
-                                                      self.tree.GetPyData(vector)[0]['maplayer'])
-                nvizData = self.tree.GetPyData(vector)[0]['nviz']['vector']
-                if nlines > 0:
-                    cmdLines += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
-                    cmdLWidth += "%d," % nvizData['lines']['width']['value']
-                    cmdLHeight += "%d," % nvizData['lines']['height']['value']
-                    cmdLColor += "%s," % nvizData['lines']['color']['value']
-                    cmdLMode += "%s," % nvizData['lines']['mode']['type']
-                    cmdLPos += "0,0,%d," % nvizData['lines']['height']['value']
-                if npoints > 0:    
-                    cmdPoints += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
-                    cmdPWidth += "%d," % nvizData['points']['width']['value']
-                    cmdPSize += "%d," % nvizData['points']['size']['value']
-                    cmdPColor += "%s," % nvizData['points']['color']['value']
-                    cmdPMarker += "%s," % markers[nvizData['points']['marker']['value']]
-                    cmdPPos += "0,0,%d," % nvizData['points']['height']['value']
-                    cmdPLayer += "1,1,"
-            if cmdLines:
-                cmd += "vline=" + cmdLines.strip(',') + ' '
-                cmd += "vline_width=" + cmdLWidth.strip(',') + ' '
-                cmd += "vline_color=" + cmdLColor.strip(',') + ' '
-                cmd += "vline_height=" + cmdLHeight.strip(',') + ' '
-                cmd += "vline_mode=" + cmdLMode.strip(',') + ' '
-                cmd += "vline_position=" + cmdLPos.strip(',') + ' '
-            if cmdPoints:
-                cmd += "vpoint=" + cmdPoints.strip(',') + ' '
-                cmd += "vpoint_width=" + cmdPWidth.strip(',') + ' '
-                cmd += "vpoint_color=" + cmdPColor.strip(',') + ' '
-                cmd += "vpoint_size=" + cmdPSize.strip(',') + ' '
-                cmd += "vpoint_marker=" + cmdPMarker.strip(',') + ' '
-                cmd += "vpoint_position=" + cmdPPos.strip(',') + ' '
-                cmd += "vpoint_layer=" + cmdPLayer.strip(',') + ' '
-            cmd += "\\\n"
-            
-        #
-        # volumes
-        #
-        if volumes:
-            cmdName = cmdShade = cmdRes = cmdPos = cmdIso = ""
-            cmdIsoColorMap = cmdIsoColorVal = cmdIsoTrMap = cmdIsoTrVal = ""
-            cmdSlice = cmdSliceTransp = cmdSlicePos = ""
-            for i, volume in enumerate(volumes):
-                nvizData = self.tree.GetPyData(volume)[0]['nviz']['volume']
-                cmdName += "%s," % self.tree.GetPyData(volume)[0]['maplayer'].GetName()
-                cmdShade += "%s," % nvizData['draw']['shading']['isosurface']['desc']
-                cmdRes += "%d," % nvizData['draw']['resolution']['isosurface']['value']
-                if nvizData['position']:
-                    cmdPos += "%d,%d,%d," % (nvizData['position']['x'], nvizData['position']['y'],
-                                            nvizData['position']['z'])
-                for iso in nvizData['isosurface']:
-                    level = iso['topo']['value']
-                    cmdIso += "%d:%s," % (i + 1, level)
-                    if iso['color']['map']:
-                        cmdIsoColorMap += "%s," % iso['color']['value']
-                    else:
-                        cmdIsoColorVal += "%s," % iso['color']['value']
-                    if 'transp' in iso:
-                        if iso['transp']['map']:
-                            cmdIsoTrMap += "%s," % iso['transp']['value']
-                        else:
-                            cmdIsoTrVal += "%s," % iso['transp']['value']     
-                            
-                for slice in nvizData['slice']:
-                    axis = ('x','y','z')[slice['position']['axis']]
-                    cmdSlice += "%d:%s," % (i + 1, axis)
-                    for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
-                        cmdSlicePos += "%f," % slice['position'][coord]
-                    cmdSliceTransp += "%s," % slice['transp']['value']
-                        
-            cmd += "volume=" + cmdName.strip(',') + ' '
-            cmd += "volume_shading=" + cmdShade.strip(',') + ' '
-            cmd += "volume_resolution=" + cmdRes.strip(',') + ' '
-            if nvizData['position']:
-                cmd += "volume_position=" + cmdPos.strip(',') + ' '
-            if cmdIso:
-                cmd += "isosurf_level=" + cmdIso.strip(',') + ' '
-                if cmdIsoColorMap:
-                    cmd += "isosurf_color_map=" + cmdIsoColorMap.strip(',') + ' '
-                if cmdIsoColorVal:
-                    cmd += "isosurf_color_value=" + cmdIsoColorVal.strip(',') + ' ' 
-                if cmdIsoTrMap:
-                    cmd += "isosurf_transp_map=" + cmdIsoTrMap.strip(',') + ' '
-                if cmdIsoTrVal:
-                    cmd += "isosurf_transp_value=" + cmdIsoTrVal.strip(',') + ' '
-            if cmdSlice:
-                cmd += "slice=" + cmdSlice.strip(',') + ' '
-                cmd += "slice_position=" + cmdSlicePos.strip(',') + ' '
-                cmd += "slice_transparency=" + cmdSliceTransp.strip(',') + ' '
-                
-        #
-        # cutting planes
-        #
-        cplane = self.lmgr.nviz.FindWindowById(self.lmgr.nviz.win['cplane']['planes']).GetStringSelection()
-        try:
-            planeIndex = int(cplane.split()[-1]) - 1
-        except (IndexError, ValueError):
-            planeIndex = None
-        if planeIndex is not None:
-            shading = ['clear', 'top', 'bottom', 'blend', 'shaded']
-            cmd += "cplane=%d " % planeIndex
-            cmd += "cplane_rotation=%d " % self.cplanes[planeIndex]['rotation']['rot']
-            cmd += "cplane_tilt=%d " % self.cplanes[planeIndex]['rotation']['tilt']
-            cmd += "cplane_position=%d,%d,%d " % (self.cplanes[planeIndex]['position']['x'],
-                                           self.cplanes[planeIndex]['position']['y'],
-                                           self.cplanes[planeIndex]['position']['z'])
-            cmd += "cplane_shading=%s " % shading[self.cplanes[planeIndex]['shading']]
-            cmd += "\\\n"                                        
-        # 
-        # viewpoint
-        #
-        subcmd  = "position=%.2f,%.2f " % (self.view['position']['x'], self.view['position']['y'])
-        subcmd += "height=%d " % (self.iview['height']['value'])
-        subcmd += "perspective=%d " % (self.view['persp']['value'])
-        subcmd += "twist=%d " % (self.view['twist']['value'])
-        subcmd += "zexag=%d " % (self.view['z-exag']['value'] * self.iview['z-exag']['original'])
-        subcmd += "focus=%d,%d,%d " % (self.iview['focus']['x'],self.iview['focus']['y'],self.iview['focus']['z'])
-        cmd += subcmd
-        
-        # background
-        subcmd  = "bgcolor=%d:%d:%d " % (self.view['background']['color'][:3])
-        if self.view['background']['color'] != (255, 255, 255):
-            cmd += subcmd
-        cmd += "\\\n"
-        # light
-        subcmd  = "light_position=%.2f,%.2f,%.2f " % (self.light['position']['x'],
-                                                      self.light['position']['y'],
-                                                      self.light['position']['z']/100.)
-        subcmd += "light_brightness=%d " % (self.light['bright'])
-        subcmd += "light_ambient=%d " % (self.light['ambient'])
-        subcmd += "light_color=%d:%d:%d " % (self.light['color'][:3])
-        cmd += subcmd
-        cmd += "\\\n"
-        # fringe
-        toolWindow = self.lmgr.nviz
-        direction = ''
-        for dir in ('nw', 'ne', 'sw', 'se'):
-            if toolWindow.FindWindowById(toolWindow.win['fringe'][dir]).IsChecked():
-                direction += "%s," % dir
-        if direction:
-            subcmd = "fringe=%s " % (direction.strip(','))
-            color = toolWindow.FindWindowById(toolWindow.win['fringe']['color']).GetValue()
-            subcmd += "fringe_color=%d:%d:%d " % (color[0], color[1], color[2])
-            subcmd += "fringe_elevation=%d " % (toolWindow.FindWindowById(toolWindow.win['fringe']['elev']).GetValue())
-            cmd += subcmd
-            cmd += "\\\n"
-        # north arrow
-        if self.decoration['arrow']['show']:
-            subcmd = "arrow_position=%d,%d " % (self.decoration['arrow']['position']['x'],
-                                                self.decoration['arrow']['position']['y'])
-            subcmd += "arrow_color=%s " % self.decoration['arrow']['color']
-            subcmd += "arrow_size=%d " % self.decoration['arrow']['size']
-            cmd += subcmd
-            
-        # output
-        subcmd = 'output=nviz_output '
-        subcmd += 'format=ppm '
-        subcmd += 'size=%d,%d ' % self.GetClientSizeTuple()
-        cmd += subcmd
-        
-        return cmd
-    
-    def OnNvizCmd(self):
-        """!Generate and write command to command output"""
-        self.log.WriteLog(self.NvizCmdCommand(), switchPage = True)
-        
-    def SaveToFile(self, FileName, FileType, width, height):
-        """!This draws the DC to a buffer that can be saved to a file.
-        
-        @todo fix BufferedPaintDC
-        
-        @param FileName file name
-        @param FileType type of bitmap
-        @param width image width
-        @param height image height
-        """
-        self._display.SaveToFile(FileName, width, height, FileType)
-                
-        # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
-        # dc = wx.BufferedPaintDC(self, pbuffer)
-        # dc.Clear()
-        # self.SetCurrent()
-        # self._display.Draw(False, -1)
-        # pbuffer.SaveFile(FileName, FileType)
-        # self.SwapBuffers()
-        
-    def GetDisplay(self):
-        """!Get display instance"""
-        return self._display
-        
-    def ZoomToMap(self, layers):
-        """!Reset view
-        
-        @param layers so far unused
-        """
-        self.lmgr.nviz.OnResetView(None)
-        
-    def TextBounds(self, textinfo):
-        """!Return text boundary data
-        
-        @param textinfo text metadata (text, font, color, rotation)
-        """
-        return self.parent.MapWindow2D.TextBounds(textinfo, relcoords = True)

Deleted: grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,629 +0,0 @@
-"""
- at package nviz_preferences.py
-
- at brief Nviz (3D view) preferences window
-
-Classes:
- - NvizPreferencesDialog
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
- at author Enhancements by Michael Barton <michael.barton asu.edu>
- at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
-"""
-
-import types
-import copy
-
-import wx
-import wx.lib.colourselect as csel
-
-import globalvar
-from preferences import globalSettings as UserSettings
-from preferences import PreferencesBaseDialog
-
-class NvizPreferencesDialog(PreferencesBaseDialog):
-    """!Nviz preferences dialog"""
-    def __init__(self, parent, title = _("3D view settings"),
-                 settings = UserSettings):
-        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
-                                       settings = settings)
-        self.toolWin = self.parent.nviz
-        
-        # create notebook pages
-        self._createViewPage(self.notebook)
-        self._createFlyPage(self.notebook)
-        self._createLightPage(self.notebook)
-        self._createSurfacePage(self.notebook)
-        self._createVectorPage(self.notebook)
-        
-        self.SetMinSize(self.GetBestSize())
-        self.SetSize(self.size)
-        self.btnDefault.SetToolTipString(_("Revert settings to default, changes are not applied"))
-        
-    def _createViewPage(self, notebook):
-        """!Create notebook page for view settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        
-        notebook.AddPage(page = panel,
-                         text = " %s " % _("View"))
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("View")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        row = 0
-        # perspective
-        pvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'persp')
-        ipvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'persp', internal = True)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Perspective:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("value:")),
-                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        pval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = pvals['value'],
-                           min = ipvals['min'],
-                           max = ipvals['max'])
-        self.winId['nviz:view:persp:value'] = pval.GetId()
-        gridSizer.Add(item = pval, pos = (row, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("step:")),
-                      pos = (row, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        pstep = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = pvals['step'],
-                           min = ipvals['min'],
-                           max = ipvals['max']-1)
-        self.winId['nviz:view:persp:step'] = pstep.GetId()
-        gridSizer.Add(item = pstep, pos = (row, 4),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1
-        
-        # position
-        posvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'position')
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Position:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("x:")),
-                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        px = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = posvals['x'] * 100,
-                           min = 0,
-                           max = 100)
-        self.winId['nviz:view:position:x'] = px.GetId()
-        gridSizer.Add(item = px, pos = (row, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "y:"),
-                      pos = (row, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        py = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = posvals['y'] * 100,
-                           min = 0,
-                           max = 100)
-        self.winId['nviz:view:position:y'] = py.GetId()
-        gridSizer.Add(item = py, pos = (row, 4),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1
-        
-        # height is computed dynamically
-        
-        # twist
-        tvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'twist')
-        itvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'twist', internal = True)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Twist:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("value:")),
-                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        tval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = tvals['value'],
-                           min = itvals['min'],
-                           max = itvals['max'])
-        self.winId['nviz:view:twist:value'] = tval.GetId()
-        gridSizer.Add(item = tval, pos = (row, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        row += 1
-        
-        # z-exag
-        zvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'z-exag')
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Z-exag:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("value:")),
-                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        zval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = zvals['value'],
-                           min = -1e6,
-                           max = 1e6)
-        self.winId['nviz:view:z-exag:value'] = zval.GetId()
-        gridSizer.Add(item = zval, pos = (row, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-
-        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                           label = " %s " % (_("Image Appearance")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        # background color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Background color:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = UserSettings.Get(group = 'nviz', key = 'view',
-                                                            subkey = ['background', 'color']),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        color.SetName('GetColour')
-        self.winId['nviz:view:background:color'] = color.GetId()
-        gridSizer.Add(item = color, pos = (0, 1))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 5)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-        
-    def _createFlyPage(self, notebook):
-        """!Create notebook page for view settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        
-        notebook.AddPage(page = panel,
-                         text = " %s " % _("Fly-through"))
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        # fly throuhg mode
-        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                           label = " %s " % (_("Fly-through mode")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        # move exag
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Move exag:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        moveExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
-                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
-                                                             subkey = ['exag', 'move']),
-                                  size = (65, -1))
-        self.winId['nviz:fly:exag:move'] = moveExag.GetId()
-        gridSizer.Add(item = moveExag, pos = (0, 1))
-        
-        # turn exag
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Turn exag:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        turnExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
-                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
-                                                             subkey = ['exag', 'turn']),
-                                  size = (65, -1))
-        self.winId['nviz:fly:exag:turn'] = turnExag.GetId()
-        gridSizer.Add(item = turnExag, pos = (1, 1))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 5)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-        
-    def _createLightPage(self, notebook):
-        """!Create notebook page for light settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        
-        notebook.AddPage(page = panel,
-                         text = " %s " % _("Lighting"))
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Light")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-
-        
-        # position
-        posvals = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'position')
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Position:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("x:")),
-                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        px = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = posvals['x'] * 100,
-                           min = -100,
-                           max = 100)
-        self.winId['nviz:light:position:x'] = px.GetId()
-        gridSizer.Add(item = px, pos = (0, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = "y:"),
-                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        py = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = posvals['y'] * 100,
-                           min = -100,
-                           max = 100)
-        self.winId['nviz:light:position:y'] = py.GetId()
-        gridSizer.Add(item = py, pos = (0, 4),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-                    
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("z:")),
-                      pos = (0, 5), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        
-        pz = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = posvals['z'],
-                           min = 0,
-                           max = 100)
-        self.winId['nviz:light:position:z'] = pz.GetId()
-        gridSizer.Add(item = pz, pos = (0, 6),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-                    
-        # brightness
-        brightval = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'bright')
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Brightness:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        bright = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = brightval,
-                           min = 0,
-                           max = 100)
-        self.winId['nviz:light:bright'] = bright.GetId()
-        gridSizer.Add(item = bright, pos = (1, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-                    
-        # ambient
-        ambval = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'ambient')
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Ambient:")),
-                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        amb = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = ambval,
-                           min = 0,
-                           max = 100)
-        self.winId['nviz:light:ambient'] = amb.GetId()
-        gridSizer.Add(item = amb, pos = (2, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-                    
-        # light color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Color:")),
-                      pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = UserSettings.Get(group = 'nviz', key = 'light',
-                                                            subkey = 'color'),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        color.SetName('GetColour')
-        self.winId['nviz:light:color'] = color.GetId()
-        gridSizer.Add(item = color, pos = (3, 2))
-        
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 5)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-    
-    def _createSurfacePage(self, notebook):
-        """!Create notebook page for surface settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        
-        notebook.AddPage(page = panel,
-                         text = " %s " % _("Surface"))
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # draw
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Draw")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        # mode
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                        label = _("Mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
-                        pos = (0, 0))
-        mode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                          choices = [_("coarse"),
-                                     _("fine"),
-                                     _("both")])
-        self.winId['nviz:surface:draw:mode'] = mode.GetId()
-        mode.SetName('GetSelection')
-        mode.SetSelection(UserSettings.Get(group = 'nviz', key = 'surface',
-                                            subkey = ['draw', 'mode']))
-        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 1))
-                    
-        # fine
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                        label = _("Fine mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
-                        pos = (1, 0))
-        res = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['draw','res-fine'])
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                        label = _("resolution:")), flag = wx.ALIGN_CENTER_VERTICAL,
-                        pos = (1, 1))
-        fine = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = res,
-                           min = 1,
-                           max = 100)
-        self.winId['nviz:surface:draw:res-fine'] = fine.GetId()
-        
-        gridSizer.Add(item = fine, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (1, 2))
-                    
-        # coarse
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                        label = _("Coarse mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
-                        pos = (2, 0))
-        res = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['draw','res-coarse'])
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                        label = _("resolution:")), flag = wx.ALIGN_CENTER_VERTICAL,
-                        pos = (2, 1))
-        coarse = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = res,
-                           min = 1,
-                           max = 100)
-        self.winId['nviz:surface:draw:res-coarse'] = coarse.GetId()
-        
-        gridSizer.Add(item = coarse, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2, 2))
-        #style
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-            label = _("style:")), flag = wx.ALIGN_CENTER_VERTICAL,
-            pos = (3, 1))
-        style = wx.Choice(parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                          choices = [_("wire"),
-                                     _("surface")])
-        self.winId['nviz:surface:draw:style'] = style.GetId()
-        style.SetName('GetSelection')
-        style.SetSelection(UserSettings.Get(group = 'nviz', key = 'surface',
-                                            subkey = ['draw', 'style']))
-        self.winId['nviz:surface:draw:style'] = style.GetId()
-        
-        gridSizer.Add(item = style, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (3, 2))
-        #wire color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-            label = _("wire color:")), flag = wx.ALIGN_CENTER_VERTICAL,
-            pos = (4, 1))
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = UserSettings.Get(group = 'nviz', key = 'surface',
-                                                            subkey = ['draw', 'wire-color']),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        color.SetName('GetColour')
-        self.winId['nviz:surface:draw:wire-color'] = color.GetId() 
-        gridSizer.Add(item = color, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (4, 2))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)            
-        pageSizer.Add(item = boxSizer, proportion = 0,
-              flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-              border = 5)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-    
-    def _createVectorPage(self, notebook):
-        """!Create notebook page for vector settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        
-        notebook.AddPage(page = panel,
-                         text = " %s " % _("Vector"))
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # vector lines
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Vector lines")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        row = 0
-        # icon size
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Width:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        iwidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                            initial = 12,
-                            min = 1,
-                            max = 100)
-        self.winId['nviz:vector:lines:width'] = iwidth.GetId()
-        iwidth.SetValue(UserSettings.Get(group = 'nviz', key = 'vector',
-                                        subkey = ['lines', 'width']))
-        gridSizer.Add(item = iwidth, pos = (row, 1),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        # icon color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Color:")),
-                      pos = (row, 4), flag = wx.ALIGN_CENTER_VERTICAL)
-        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        icolor.SetName('GetColour')
-        self.winId['nviz:vector:lines:color'] = icolor.GetId()
-        icolor.SetColour(UserSettings.Get(group = 'nviz', key = 'vector',
-                                          subkey = ['lines', 'color']))
-        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 5))
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 5)
-        
-        # vector points
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Vector points")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 5)
-        
-        row = 0
-        # icon size
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Size:")),
-                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        isize = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                            initial = 100,
-                            min = 1,
-                            max = 1e6)
-        self.winId['nviz:vector:points:size'] = isize.GetId()
-        isize.SetValue(UserSettings.Get(group = 'nviz', key = 'vector',
-                                        subkey = ['points', 'size']))
-        gridSizer.Add(item = isize, pos = (row, 1),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        # icon symbol
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Marker:")),
-                      pos = (row, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        isym = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                          choices = UserSettings.Get(group = 'nviz', key = 'vector',
-                                                   subkey = ['points', 'marker'], internal = True))
-        isym.SetName("GetSelection")
-        self.winId['nviz:vector:points:marker'] = isym.GetId()
-        isym.SetSelection(UserSettings.Get(group = 'nviz', key = 'vector',
-                                           subkey = ['points', 'marker']))
-        gridSizer.Add(item = isym, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 3))
-        
-        # icon color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Color:")),
-                      pos = (row, 4), flag = wx.ALIGN_CENTER_VERTICAL)
-        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        icolor.SetName('GetColour')
-        self.winId['nviz:vector:points:color'] = icolor.GetId()
-        icolor.SetColour(UserSettings.Get(group = 'nviz', key = 'vector',
-                                          subkey = ['points', 'color']))
-        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 5))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 5)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-
-    def OnDefault(self, event):
-        """!Button 'Set to default' pressed"""
-        self.settings.userSettings = copy.deepcopy(self.settings.defaultSettings)
-        
-        # update widgets
-        for gks in self.winId.keys():
-            subkey1 = None
-            try:
-                group, key, subkey = gks.split(':')
-                value = self.settings.Get(group, key, subkey)
-            except ValueError:
-                group, key, subkey, subkey1 = gks.split(':')
-                value = self.settings.Get(group, key, [subkey, subkey1])
-            if subkey == 'position':
-                if subkey1 in ('x', 'y'):
-                    value = float(value) * 100
-            win = self.FindWindowById(self.winId[gks])
-            if win.GetName() == 'GetSelection':
-                value = win.SetSelection(value)
-            else:
-                value = win.SetValue(value)        
-        
-    def OnApply(self, event):
-        """Apply Nviz settings for current session"""
-        for item in self.winId.keys():
-            try:
-                group, key, subkey = item.split(':')
-                subkey1 = None
-            except ValueError:
-                group, key, subkey, subkey1 = item.split(':')
-            
-            id = self.winId[item]
-            win = self.FindWindowById(id)
-            if win.GetName() == 'GetSelection':
-                value = win.GetSelection()
-            elif win.GetName() == 'GetColour':
-                value = tuple(win.GetValue())
-            else:
-                value = win.GetValue()
-            
-            if subkey == 'position':
-                if subkey1 in ('x', 'y'):
-                    value = float(value) / 100
-            if subkey1:
-                self.settings.Set(group, value, key, [subkey, subkey1])
-            else:
-                self.settings.Set(group, value, key, subkey)
-                
-        self.toolWin.LoadSettings()
-        
-        
-    def OnSave(self, event):
-        """!Save button pressed
-        
-        Apply changes and save settings to configuration file
-        """
-        self.OnApply(None)
-        fileSettings = {}
-        UserSettings.ReadSettingsFile(settings = fileSettings)
-        fileSettings['nviz'] = UserSettings.Get(group = 'nviz')
-        
-        UserSettings.SaveToFile(fileSettings)
-        self.parent.goutput.WriteLog(
-                _('3D view settings saved to file <%s>.') % UserSettings.filePath)
-        
-        self.Destroy()
-        

Deleted: grass/trunk/gui/wxpython/gui_modules/nviz_tools.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/nviz_tools.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/nviz_tools.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,5215 +0,0 @@
-"""!
- at package nviz_tools.py
-
- at brief Nviz (3D view) tools window
-
-Classes:
- - ScrolledPanel
- - NTCValidator
- - NumTextCtrl
- - FloatSlider
- - SymbolButton
- - NvizToolWindow
- - PositionWindow
- - ViewPositionWindow
- - LightPositionWindow
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
- at author Enhancements by Michael Barton <michael.barton asu.edu>
- at author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
-"""
-
-import os
-import sys
-import copy
-import types
-import string
-
-import wx
-import wx.lib.colourselect  as csel
-import wx.lib.scrolledpanel as SP
-import wx.lib.filebrowsebutton as filebrowse
-
-try:
-    from wx.lib.buttons import ThemedGenBitmapTextButton as BitmapTextButton
-except ImportError: # not sure about TGBTButton version
-    from wx.lib.buttons import GenBitmapTextButton as BitmapTextButton
-    
-try:
-    import wx.lib.agw.flatnotebook as FN
-except ImportError:
-    import wx.lib.flatnotebook as FN
-try:
-    from agw import foldpanelbar as fpb
-except ImportError: # if it's not there locally, try the wxPython lib.
-    try:
-        import wx.lib.agw.foldpanelbar as fpb
-    except ImportError:
-        import wx.lib.foldpanelbar as fpb # versions <=2.5.5.1
-        
-import grass.script as grass
-
-import globalvar
-import gselect
-import gcmd
-import colorrules
-from preferences import globalSettings as UserSettings
-from gselect import VectorDBInfo
-
-from nviz_animation import EVT_ANIM_FIN, EVT_ANIM_UPDATE_IDX
-try:
-    from nviz_mapdisp import wxUpdateView, wxUpdateLight, wxUpdateProperties,\
-                            wxUpdateCPlane
-    import wxnviz
-except ImportError:
-    pass
-
-from debug import Debug
-
-
-class ScrolledPanel(SP.ScrolledPanel):
-    """!Custom ScrolledPanel to avoid strange behaviour concerning focus"""
-    def __init__(self, parent):
-        SP.ScrolledPanel.__init__(self, parent = parent, id = wx.ID_ANY)
-    def OnChildFocus(self, event):
-        pass
-        
-        
-class NTCValidator(wx.PyValidator):
-    """!validates input in textctrls, taken from wxpython demo"""
-    def __init__(self, flag = None):
-        wx.PyValidator.__init__(self)
-        self.flag = flag
-        self.Bind(wx.EVT_CHAR, self.OnChar)
-
-    def Clone(self):
-        return NTCValidator(self.flag)
-
-    def OnChar(self, event):
-        key = event.GetKeyCode()
-        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
-            event.Skip()
-            return
-        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.-':
-            event.Skip()
-            return
-        if not wx.Validator_IsSilent():
-            wx.Bell()
-        # Returning without calling even.Skip eats the event before it
-        # gets to the text control
-        return  
-    
-class NumTextCtrl(wx.TextCtrl):
-    """!Class derived from wx.TextCtrl for numerical values only"""
-    def __init__(self, parent,  **kwargs):
-##        self.precision = kwargs.pop('prec')
-        wx.TextCtrl.__init__(self, parent = parent,
-            validator = NTCValidator(flag = 'DIGIT_ONLY'), **kwargs)
-        
-            
-    def SetValue(self, value):
-        super(NumTextCtrl, self).SetValue( str(value))
-        
-    def GetValue(self):
-        val = super(NumTextCtrl, self).GetValue()
-        if val == '':
-            val = '0'
-        try:
-            return float(val)
-        except ValueError:
-            val = ''.join(''.join(val.split('-')).split('.'))
-            return float(val)
-        
-    def SetRange(self, min, max):
-        pass
-   
-class FloatSlider(wx.Slider):
-    """!Class derived from wx.Slider for floats"""
-    def __init__(self, **kwargs):
-        Debug.msg(1, "FloatSlider.__init__()")
-        wx.Slider.__init__(self, **kwargs)
-        self.coef = 1.
-        #init range
-        self.minValueOrig = 0
-        self.maxValueOrig = 1
-        
-    def SetValue(self, value):
-        value *= self.coef 
-        if abs(value) < 1 and value != 0:
-            while abs(value) < 1:
-                value *= 100
-                self.coef *= 100
-            super(FloatSlider, self).SetRange(self.minValueOrig * self.coef, self.maxValueOrig * self.coef)
-        super(FloatSlider, self).SetValue(value)
-        
-        Debug.msg(4, "FloatSlider.SetValue(): value = %f" % value)
-        
-    def SetRange(self, minValue, maxValue):
-        self.coef = 1.
-        self.minValueOrig = minValue
-        self.maxValueOrig = maxValue
-        if abs(minValue) < 1 or abs(maxValue) < 1:
-            while (abs(minValue) < 1 and minValue != 0) or (abs(maxValue) < 1 and maxValue != 0):
-                minValue *= 100
-                maxValue *= 100
-                self.coef *= 100
-            super(FloatSlider, self).SetValue(super(FloatSlider, self).GetValue() * self.coef)
-        super(FloatSlider, self).SetRange(minValue, maxValue)
-        Debug.msg(4, "FloatSlider.SetRange(): minValue = %f, maxValue = %f" % (minValue, maxValue))
-            
-    def GetValue(self):
-        val = super(FloatSlider, self).GetValue()
-        Debug.msg(4, "FloatSlider.GetValue(): value = %f" % (val/self.coef))
-        return val/self.coef
-        
-        
-class SymbolButton(BitmapTextButton):
-    """!Button with symbol and label."""
-    def __init__(self, parent, usage, label, **kwargs):
-        """!Constructor
-        
-        @param parent parent (usually wx.Panel)
-        @param usage determines usage and picture
-        @param label displayed label
-        """
-        size = (15, 15)
-        buffer = wx.EmptyBitmap(*size)
-        BitmapTextButton.__init__(self, parent = parent, label = " " + label, bitmap = buffer, **kwargs)
-        
-        dc = wx.MemoryDC()
-        dc.SelectObject(buffer)
-        maskColor = wx.Color(255, 255, 255)
-        dc.SetBrush(wx.Brush(maskColor))
-        dc.Clear()
-        
-        if usage == 'record':
-            self.DrawRecord(dc, size)
-        elif usage == 'stop':
-            self.DrawStop(dc, size)
-        elif usage == 'play':
-            self.DrawPlay(dc, size)
-        elif usage == 'pause':
-            self.DrawPause(dc, size)
-
-        buffer.SetMaskColour(maskColor)
-        self.SetBitmapLabel(buffer)
-        dc.SelectObject(wx.NullBitmap)
-        
-    def DrawRecord(self, dc, size):
-        """!Draw record symbol"""
-        dc.SetBrush(wx.Brush(wx.Color(255, 0, 0)))
-        dc.DrawCircle(size[0]/2, size[1] / 2, size[0] / 2)
-        
-    def DrawStop(self, dc, size):
-        """!Draw stop symbol"""
-        dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
-        dc.DrawRectangle(0, 0, size[0], size[1])
-        
-    def DrawPlay(self, dc, size):
-        """!Draw play symbol"""
-        dc.SetBrush(wx.Brush(wx.Color(0, 255, 0)))
-        points = (wx.Point(0, 0), wx.Point(0, size[1]), wx.Point(size[0], size[1] / 2))
-        dc.DrawPolygon(points)
-        
-    def DrawPause(self, dc, size):
-        """!Draw pause symbol"""
-        dc.SetBrush(wx.Brush(wx.Color(50, 50, 50)))
-        dc.DrawRectangle(0, 0, 2 * size[0] / 5, size[1])
-        dc.DrawRectangle(3 * size[0] / 5, 0, 2 * size[0] / 5, size[1])
-        
-        
-class NvizToolWindow(FN.FlatNotebook):
-    """!Nviz (3D view) tools panel
-    """
-    def __init__(self, parent, display, id = wx.ID_ANY,
-                 style = globalvar.FNPageStyle|FN.FNB_NO_X_BUTTON,
-                 **kwargs):
-        Debug.msg(5, "NvizToolWindow.__init__()")
-        self.parent     = parent # GMFrame
-        self.mapDisplay = display
-        self.mapWindow  = display.GetWindow()
-        self._display   = self.mapWindow.GetDisplay()
-         
-        if globalvar.hasAgw:
-            kwargs['agwStyle'] = style
-        else:
-            kwargs['style'] = style
-        FN.FlatNotebook.__init__(self, parent, id, **kwargs)
-        self.SetTabAreaColour(globalvar.FNPageColor)
-        
-        self.win  = {} # window ids
-        self.page = {} # page ids
-
-        # view page
-        self.AddPage(page = self._createViewPage(),
-                     text = " %s " % _("View"))
-
-        # data page
-        self.AddPage(page = self._createDataPage(),
-                     text = " %s " % _("Data"))
-        
-        # appearance page
-        self.AddPage(page = self._createAppearancePage(),
-                     text = " %s " % _("Appearance"))
-                    
-        # analysis page
-        self.AddPage(page = self._createAnalysisPage(),
-                     text = " %s " % _("Analysis"))
-        # view page
-        self.AddPage(page = self._createAnimationPage(),
-                     text = " %s " % _("Animation"))
-        
-        self.UpdateSettings()
-        
-        self.mapWindow.SetToolWin(self)
-        
-        self.pageChanging = False
-        self.vetoGSelectEvt = False #when setting map, event is invoked
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-        
-        # bindings
-        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        
-        self.Bind(EVT_ANIM_FIN, self.OnAnimationFinished)
-        self.Bind(EVT_ANIM_UPDATE_IDX, self.OnAnimationUpdateIndex)
-        
-        Debug.msg(3, "NvizToolWindow.__init__()")
-        
-        self.Update()
-        wx.CallAfter(self.SetPage, 'view')
-        wx.CallAfter(self.UpdateScrolling, (self.foldpanelData, self.foldpanelAppear,
-                                            self.foldpanelAnalysis))       
-        wx.CallAfter(self.SetInitialMaps)
-        
-    def SetInitialMaps(self):
-        """!Set initial raster and vector map"""
-        for l_type in ('raster', 'vector', '3d-raster'):
-            selectedLayer = self.mapWindow.GetSelectedLayer()
-            layers = self.mapWindow.Map.GetListOfLayers(l_type = l_type, l_active = True)
-            if selectedLayer in layers:
-                selection = selectedLayer.GetName()
-            else:
-                try:
-                    selection = layers[0].GetName()
-                except:
-                    continue
-            if l_type == 'raster':
-                self.FindWindowById(self.win['surface']['map']).SetValue(selection)
-                self.FindWindowById(self.win['fringe']['map']).SetValue(selection)
-            elif l_type == 'vector':
-                self.FindWindowById(self.win['vector']['map']).SetValue(selection)
-            elif l_type == '3d-raster':
-                self.FindWindowById(self.win['volume']['map']).SetValue(selection)
-               
-    def UpdateState(self, **kwargs):
-        if 'view' in kwargs:
-            self.mapWindow.view = kwargs['view']
-            self.FindWindowById(self.win['view']['position']).data = kwargs['view']
-            self.FindWindowById(self.win['view']['position']).PostDraw()
-        if 'iview' in kwargs:
-            self.mapWindow.iview = kwargs['iview']
-        if 'light' in kwargs:
-            self.mapWindow.light = kwargs['light']  
-            self.FindWindowById(self.win['light']['position']).data = kwargs['light']  
-            self.FindWindowById(self.win['light']['position']).PostDraw()
-        if 'fly' in kwargs:
-            self.mapWindow.fly['exag'] = kwargs['fly']['exag']
-    
-    def LoadSettings(self):
-        """!Load Nviz settings and apply to current session"""
-        view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
-        light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
-        fly = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'fly')) # copy
-        self.UpdateState(view = view, light = light, fly = fly)
-        self.PostViewEvent(zExag = True)
-        self.PostLightEvent()
-        self.UpdatePage('view')
-        self.UpdatePage('light')
-        
-        self.mapWindow.ReloadLayersData()
-        self.UpdatePage('surface')
-        self.UpdatePage('vector')
-        self.UpdateSettings()
-               
-    def OnPageChanged(self, event):
-        new = event.GetSelection()
-        # self.ChangeSelection(new)
-        
-    def PostViewEvent(self, zExag = False):
-        """!Change view settings"""
-        event = wxUpdateView(zExag = zExag)
-        wx.PostEvent(self.mapWindow, event)
-        
-    def PostLightEvent(self, refresh = False): 
-        """!Change light settings"""   
-        event = wxUpdateLight(refresh = refresh)
-        wx.PostEvent(self.mapWindow, event)
-        
-    def OnSize(self, event):
-        """!After window is resized, update scrolling"""
-        # workaround to resize captionbars of foldpanelbar
-        wx.CallAfter(self.UpdateScrolling, (self.foldpanelData, self.foldpanelAppear,
-                                            self.foldpanelAnalysis)) 
-        event.Skip()
-           
-    def OnPressCaption(self, event):
-        """!When foldpanel item collapsed/expanded, update scrollbars"""
-        foldpanel = event.GetBar().GetGrandParent().GetParent()
-        wx.CallAfter(self.UpdateScrolling, (foldpanel,))
-        event.Skip()
-        
-    def UpdateScrolling(self, foldpanels):
-        """!Update scrollbars in foldpanel"""
-        for foldpanel in foldpanels:
-            length = foldpanel.GetPanelsLength(collapsed = 0, expanded = 0)
-            # virtual width is set to fixed value to suppress GTK warning
-            foldpanel.GetParent().SetVirtualSize((100, length[2]))
-            foldpanel.GetParent().Layout()
-        
-    def _createViewPage(self):
-        """!Create view settings page"""
-        panel = SP.ScrolledPanel(parent = self, id = wx.ID_ANY)
-        panel.SetupScrolling(scroll_x = False)
-        self.page['view'] = { 'id' : 0,
-                              'notebook' : self.GetId()}
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Control View")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 10)
-        
-        self.win['view'] = {}
-        
-        # position
-        posSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        self._createCompass(panel = panel, sizer = posSizer, type = 'view')
-        
-        view = ViewPositionWindow(panel, size = (175, 175),
-                                  mapwindow = self.mapWindow)
-        self.win['view']['position'] = view.GetId()
-        posSizer.Add(item = view,
-                     pos = (1, 1), flag = wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = posSizer, pos = (0, 0))
-                  
-        # perspective
-        # set initial defaults here (or perhaps in a default values file), not in user settings
-        #todo: consider setting an absolute max at 360 instead of undefined. (leave the default max value at pi)
-        self._createControl(panel, data = self.win['view'], name = 'persp',
-                            range = (1,180),
-                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
-        
-        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Perspective:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER)
-        gridSizer.Add(item = self.FindWindowById(self.win['view']['persp']['slider']), pos = (2, 0),
-                      flag = wx.ALIGN_CENTER)
-        gridSizer.Add(item = self.FindWindowById(self.win['view']['persp']['text']), pos = (3, 0),
-                      flag = wx.ALIGN_CENTER)        
-        
-        # twist
-        self._createControl(panel, data = self.win['view'], name = 'twist',
-                            range = (-180,180),
-                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
-        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Twist:")),
-                      pos = (1, 1), flag = wx.ALIGN_CENTER)
-        gridSizer.Add(item = self.FindWindowById(self.win['view']['twist']['slider']), pos = (2, 1))
-        gridSizer.Add(item = self.FindWindowById(self.win['view']['twist']['text']), pos = (3, 1),
-                      flag = wx.ALIGN_CENTER)        
-        
-        # height + z-exag
-        self._createControl(panel, data = self.win['view'], name = 'height', sliderHor = False,
-                            range = (0, 1),
-                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
-        self._createControl(panel, data = self.win['view'], name = 'z-exag', sliderHor = False,
-                            range = (0, 10), floatSlider = True,
-                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
-        self.FindWindowById(self.win['view']['z-exag']['slider']).SetValue(1)
-        self.FindWindowById(self.win['view']['z-exag']['text']).SetValue(1)
-        
-        heightSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:")),
-                      pos = (0, 0), flag = wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL, span = (1, 2))
-        heightSizer.Add(item = self.FindWindowById(self.win['view']['height']['slider']),
-                        flag = wx.ALIGN_RIGHT, pos = (1, 0))
-        heightSizer.Add(item = self.FindWindowById(self.win['view']['height']['text']),
-                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT, pos = (1, 1))
-        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Z-exag:")),
-                      pos = (0, 2), flag = wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL, span = (1, 2))
-        heightSizer.Add(item = self.FindWindowById(self.win['view']['z-exag']['slider']),
-                        flag = wx.ALIGN_RIGHT, pos = (1, 2))
-        heightSizer.Add(item = self.FindWindowById(self.win['view']['z-exag']['text']),
-                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.TOP |
-                        wx.BOTTOM | wx.RIGHT, pos = (1, 3))
-        
-        gridSizer.Add(item = heightSizer, pos = (0, 1), flag = wx.ALIGN_CENTER)
-        
-        # view setup + reset
-        viewSizer = wx.BoxSizer(wx.HORIZONTAL)
-        viewSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY,
-                                           label = _("Look:")),
-                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL,
-                      border = 5)
-        here = wx.ToggleButton(panel, id = wx.ID_ANY, label = _("here"))
-        here.Bind(wx.EVT_TOGGLEBUTTON, self.OnLookAt)
-        here.SetName('here')
-        viewSizer.Add(item = here, flag = wx.TOP|wx.BOTTOM|wx.LEFT|wx.ALIGN_CENTER_VERTICAL,
-                      border = 5)
-                    
-        center = wx.Button(panel, id = wx.ID_ANY, label = _("center"))
-        center.Bind(wx.EVT_BUTTON, self.OnLookAt)
-        center.SetName('center')
-        viewSizer.Add(item = center, flag = wx.TOP|wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL,
-                      border = 5)
-                    
-        top = wx.Button(panel, id = wx.ID_ANY, label = _("top"))
-        top.Bind(wx.EVT_BUTTON, self.OnLookAt)
-        top.SetName('top')
-        viewSizer.Add(item = top, flag = wx.TOP|wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL,
-                      border = 5)
-                    
-        reset = wx.Button(panel, id = wx.ID_ANY, label = _("reset"))
-        reset.SetToolTipString(_("Reset to default view"))
-        reset.Bind(wx.EVT_BUTTON, self.OnResetView)
-        viewSizer.Add(item = reset, proportion = 0,
-                      flag = wx.TOP|wx.BOTTOM|wx.RIGHT| wx.ALIGN_RIGHT,
-                      border = 5)
-        
-        gridSizer.AddGrowableCol(2)
-        gridSizer.Add(item = viewSizer, pos = (4, 0), span = (1, 3),
-                      flag = wx.EXPAND)
-        
-        # body
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 2)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 3)
-        
-        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                           label = " %s " % (_("Image Appearance")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        # background color
-        self.win['view']['background'] = {}
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Background color:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = UserSettings.Get(group = 'nviz', key = 'view',
-                                                            subkey = ['background', 'color']),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        self.win['view']['background']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnBgColor)
-        gridSizer.Add(item = color, pos = (0, 1))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-        
-    def _createAnimationPage(self):
-        """!Create view settings page"""
-        panel = SP.ScrolledPanel(parent = self, id = wx.ID_ANY)
-        panel.SetupScrolling(scroll_x = False)
-        self.page['animation'] = { 'id' : 0,
-                                   'notebook' : self.GetId()}
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Animation")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        self.win['anim'] = {}
-        # animation help text
-        help = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                             label = _("Press 'Record' button and start changing the view. "
-                                       "It is recommended to use fly-through mode "
-                                       "(Map Display toolbar) to achieve smooth motion."))
-        self.win['anim']['help'] = help.GetId()
-        hSizer.Add(item = help, proportion = 0)
-        boxSizer.Add(item = hSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 5)
-                     
-        # animation controls
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        record = SymbolButton(parent = panel, id = wx.ID_ANY,
-                                    usage = "record", label = _("Record"))
-        play = SymbolButton(parent = panel, id = wx.ID_ANY,
-                                  usage = "play", label = _("Play"))
-        pause = SymbolButton(parent = panel, id = wx.ID_ANY,
-                                   usage = "pause", label = _("Pause"))
-        stop = SymbolButton(parent = panel, id = wx.ID_ANY,
-                                  usage = "stop", label = _("Stop"))
-        
-        self.win['anim']['record'] = record.GetId()
-        self.win['anim']['play'] = play.GetId()
-        self.win['anim']['pause'] = pause.GetId()
-        self.win['anim']['stop'] = stop.GetId()
-                            
-        self._createControl(panel, data = self.win['anim'], name = 'frameIndex',
-                            range = (0, 1), floatSlider = False,
-                            bind = (self.OnFrameIndex, None, self.OnFrameIndexText))
-        frameSlider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
-        frameText = self.FindWindowById(self.win['anim']['frameIndex']['text'])
-        infoLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Total number of frames :"))
-        info = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        self.win['anim']['info'] = info.GetId()
-        
-        fpsLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Frame rate (FPS):"))
-        fps = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = UserSettings.Get(group = 'nviz', key = 'animation', subkey = 'fps'),
-                           min = 1,
-                           max = 50)
-        self.win['anim']['fps'] = fps.GetId()
-        fps.SetToolTipString(_("Frames are recorded with given frequency (FPS). "))
-                            
-        record.Bind(wx.EVT_BUTTON, self.OnRecord)
-        play.Bind(wx.EVT_BUTTON, self.OnPlay)
-        stop.Bind(wx.EVT_BUTTON, self.OnStop)
-        pause.Bind(wx.EVT_BUTTON, self.OnPause)
-        fps.Bind(wx.EVT_SPINCTRL, self.OnFPS)
-        
-        hSizer.Add(item = record, proportion = 0)
-        hSizer.Add(item = play, proportion = 0)
-        hSizer.Add(item = pause, proportion = 0)
-        hSizer.Add(item = stop, proportion = 0)
-        boxSizer.Add(item = hSizer, proportion = 0,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        sliderBox = wx.BoxSizer(wx.HORIZONTAL)
-        sliderBox.Add(item = frameSlider, proportion = 1, border = 5, flag = wx.EXPAND | wx.RIGHT)
-        sliderBox.Add(item = frameText, proportion = 0, border = 5, flag = wx.EXPAND| wx.RIGHT | wx.LEFT)
-        boxSizer.Add(item = sliderBox, proportion = 0, flag = wx.EXPAND)
-        
-        # total number of frames
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer.Add(item = infoLabel, proportion = 0, flag = wx.RIGHT, border = 5)
-        hSizer.Add(item = info, proportion = 0, flag = wx.LEFT, border = 5)
-        
-        boxSizer.Add(item = hSizer, proportion = 0,
-                     flag = wx.ALL | wx.EXPAND, border = 5)
-                     
-        # frames per second
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer.Add(item = fpsLabel, proportion = 0, flag = wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border = 5)
-        hSizer.Add(item = fps, proportion = 0, flag = wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border = 5)
-        
-        boxSizer.Add(item = hSizer, proportion = 0,
-                     flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-                      
-        # save animation
-        self.win['anim']['save'] = {}
-        self.win['anim']['save']['image'] = {}
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Save image sequence")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        vSizer = wx.BoxSizer(wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 10)
-        
-        pwd = os.getcwd()
-        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
-                                         labelText = _("Choose a directory:"),
-                                         dialogTitle = _("Choose a directory for images"),
-                                         buttonText = _('Browse'),
-                                         startDirectory = pwd)
-        dir.SetValue(pwd)
-        prefixLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("File prefix:"))
-        prefixCtrl = wx.TextCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
-                                 value = UserSettings.Get(group = 'nviz',
-                                                          key = 'animation', subkey = 'prefix'))
-        prefixCtrl.SetToolTipString(_("Generated files names will look like this: prefix_1.ppm, prefix_2.ppm, ..."))
-        fileTypeLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("File format:"))
-        fileTypeCtrl = wx.Choice(parent = panel, id = wx.ID_ANY, choices = ["PPM", "TIF"])
-        
-        save = wx.Button(parent = panel, id = wx.ID_ANY,
-                         label = "Save")
-                         
-        self.win['anim']['save']['image']['dir'] = dir.GetId()
-        self.win['anim']['save']['image']['prefix'] = prefixCtrl.GetId()
-        self.win['anim']['save']['image']['format'] = fileTypeCtrl.GetId()
-        self.win['anim']['save']['image']['confirm'] = save.GetId()
-        
-        boxSizer.Add(item = dir, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        gridSizer.Add(item = prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-        gridSizer.Add(item = prefixCtrl, pos = (0, 1), flag = wx.EXPAND )
-        gridSizer.Add(item = fileTypeLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-        gridSizer.Add(item = fileTypeCtrl, pos = (1, 1), flag = wx.EXPAND )
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 5)
-        boxSizer.Add(item = save, proportion = 0, flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
-        
-        save.Bind(wx.EVT_BUTTON, self.OnSaveAnimation)
-        
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-        
-        return panel
-        
-    def _createDataPage(self):
-        """!Create data (surface, vector, volume) settings page"""
-
-        self.mainPanelData = ScrolledPanel(parent = self)
-        self.mainPanelData.SetupScrolling(scroll_x = False)
-##        style = fpb.CaptionBarStyle()
-##        style.SetCaptionStyle(fpb.CAPTIONBAR_FILLED_RECTANGLE)
-##        style.SetFirstColour(wx.Color(250,250,250))
-        try:# wxpython <= 2.8.10
-            self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,
-                                                  style = fpb.FPB_DEFAULT_STYLE,
-                                                  extraStyle = fpb.FPB_SINGLE_FOLD)
-        except:
-            try:# wxpython >= 2.8.11
-                self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,                               
-                                                      agwStyle = fpb.FPB_SINGLE_FOLD)
-            except: # to be sure
-                self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,                               
-                                                      style = fpb.FPB_SINGLE_FOLD)
-            
-                     
-        self.foldpanelData.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
-
-
-        
-        # surface page
-        self.surfacePanel = self.foldpanelData.AddFoldPanel(_("Surface"), collapsed = False)
-        self.foldpanelData.AddFoldPanelWindow(self.surfacePanel, 
-            window = self._createSurfacePage(parent = self.surfacePanel), flags = fpb.FPB_ALIGN_WIDTH)
-        self.EnablePage("surface", enabled = False)
-        
-        # constant page
-        constantPanel = self.foldpanelData.AddFoldPanel(_("Constant surface"), collapsed = True)
-        self.foldpanelData.AddFoldPanelWindow(constantPanel,
-            window = self._createConstantPage(parent = constantPanel), flags = fpb.FPB_ALIGN_WIDTH)
-        self.EnablePage("constant", enabled = False)
-        # vector page
-        vectorPanel = self.foldpanelData.AddFoldPanel(_("Vector"), collapsed = True)
-        self.foldpanelData.AddFoldPanelWindow(vectorPanel, 
-            window = self._createVectorPage(parent = vectorPanel), flags = fpb.FPB_ALIGN_WIDTH)
-        self.EnablePage("vector", enabled = False)
-        
-        # volume page
-        volumePanel = self.foldpanelData.AddFoldPanel(_("Volume"), collapsed = True)
-        self.foldpanelData.AddFoldPanelWindow(volumePanel,
-            window = self._createVolumePage(parent = volumePanel), flags = fpb.FPB_ALIGN_WIDTH)
-        self.EnablePage("volume", enabled = False)
-        
-##        self.foldpanelData.ApplyCaptionStyleAll(style)
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        sizer.Add(self.foldpanelData, proportion = 1, flag = wx.EXPAND)
-        self.mainPanelData.SetSizer(sizer)
-        self.mainPanelData.Layout()
-        self.mainPanelData.Fit()
-        
-        return self.mainPanelData
-        
-        
-    def _createAppearancePage(self):
-        """!Create data (surface, vector, volume) settings page"""
-        self.mainPanelAppear = ScrolledPanel(parent = self)
-        self.mainPanelAppear.SetupScrolling(scroll_x = False)
-        
-        try:# wxpython <= 2.8.10
-            self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,
-                                                  style = fpb.FPB_DEFAULT_STYLE,
-                                                  extraStyle = fpb.FPB_SINGLE_FOLD)
-        except:
-            try:# wxpython >= 2.8.11
-                self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,                               
-                                                      agwStyle = fpb.FPB_SINGLE_FOLD)
-            except: # to be sure
-                self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,                               
-                                                      style = fpb.FPB_SINGLE_FOLD)
-            
-        self.foldpanelAppear.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
-        # light page
-        lightPanel = self.foldpanelAppear.AddFoldPanel(_("Lighting"), collapsed = False)
-        self.foldpanelAppear.AddFoldPanelWindow(lightPanel, 
-            window = self._createLightPage(parent = lightPanel), flags = fpb.FPB_ALIGN_WIDTH)
-    
-        # fringe page
-        fringePanel = self.foldpanelAppear.AddFoldPanel(_("Fringe"), collapsed = True)
-        self.foldpanelAppear.AddFoldPanelWindow(fringePanel, 
-            window = self._createFringePage(parent = fringePanel), flags = fpb.FPB_ALIGN_WIDTH)
-        
-        self.EnablePage('fringe', False)
-        
-        # decoration page
-        decorationPanel = self.foldpanelAppear.AddFoldPanel(_("Decorations"), collapsed = True)
-        self.foldpanelAppear.AddFoldPanelWindow(decorationPanel, 
-            window = self._createDecorationPage(parent = decorationPanel), flags = fpb.FPB_ALIGN_WIDTH)
-        
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        sizer.Add(self.foldpanelAppear, proportion = 1, flag = wx.EXPAND)
-        self.mainPanelAppear.SetSizer(sizer)
-        self.mainPanelAppear.Layout()
-        self.mainPanelAppear.Fit()
-        return self.mainPanelAppear
-    
-    def _createAnalysisPage(self):
-        """!Create data analysis (cutting planes, ...) page"""
-        self.mainPanelAnalysis = ScrolledPanel(parent = self)
-        self.mainPanelAnalysis.SetupScrolling(scroll_x = False)
-        self.foldpanelAnalysis = fpb.FoldPanelBar(parent = self.mainPanelAnalysis, id = wx.ID_ANY,
-                                                  style = fpb.FPB_SINGLE_FOLD)
-        self.foldpanelAnalysis.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
-        # cutting planes page
-        cplanePanel = self.foldpanelAnalysis.AddFoldPanel(_("Cutting planes"), collapsed = False)
-        self.foldpanelAnalysis.AddFoldPanelWindow(cplanePanel, 
-            window = self._createCPlanePage(parent = cplanePanel), flags = fpb.FPB_ALIGN_WIDTH)
-        
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        sizer.Add(self.foldpanelAnalysis, proportion = 1, flag = wx.EXPAND)
-        self.mainPanelAnalysis.SetSizer(sizer)
-        self.mainPanelAnalysis.Layout()
-        self.mainPanelAnalysis.Fit()
-        return self.mainPanelAnalysis
-        
-    def _createSurfacePage(self, parent):
-        """!Create view settings page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        self.page['surface'] = { 'id' : 0,
-                                 'notebook' : self.foldpanelData.GetId() }
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        self.win['surface'] = {}
-        
-        # selection
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Raster map")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        rmaps = gselect.Select(parent = panel, type = 'raster',
-                               onPopup = self.GselectOnPopup)
-        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetRaster)
-        self.win['surface']['map'] = rmaps.GetId()
-        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        self.win['surface']['desc'] = desc.GetId()
-        boxSizer.Add(item = rmaps, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        boxSizer.Add(item = desc, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        #
-        # draw
-        #
-        self.win['surface']['draw'] = {}
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Draw")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(3)
-        
-        # mode
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Mode:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        mode = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                          choices = [_("coarse"),
-                                     _("fine"),
-                                     _("both")])
-        mode.SetName("selection")
-        mode.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
-        self.win['surface']['draw']['mode'] = mode.GetId()
-        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND,
-                      pos = (0, 1),span = (1, 2))
-        
-        # shading
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Shading:")),
-                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
-        shade = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                           choices = [_("flat"),
-                                      _("gouraud")])
-        shade.SetName("selection")
-        self.win['surface']['draw']['shading'] = shade.GetId()
-        shade.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
-        gridSizer.Add(item = shade, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 4))
-        
-        # set to all
-        all = wx.Button(panel, id = wx.ID_ANY, label = _("Set to all"))
-        all.SetToolTipString(_("Use draw settings for all loaded surfaces"))
-        all.Bind(wx.EVT_BUTTON, self.OnSurfaceModeAll)
-        gridSizer.Add(item = all, flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                      pos = (3, 4))
-        self.win['surface']['all'] = all.GetId()
-        
-        # resolution coarse
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Coarse mode:")),
-                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                        label = _("resolution:")),
-                     pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        resC = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = 6,
-                           min = 1,
-                           max = 100)
-        resC.SetName("value")
-        self.win['surface']['draw']['res-coarse'] = resC.GetId()
-        resC.Bind(wx.EVT_SPINCTRL, self.OnSurfaceResolution)
-        gridSizer.Add(item = resC, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
-        
-        # Coarse style
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("style:")),
-                      pos = (3, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        style = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                          choices = [_("wire"),
-                                     _("surface")])
-        style.SetName("selection")
-        self.win['surface']['draw']['style'] = style.GetId()
-        style.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
-        gridSizer.Add(item = style, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (3, 2))
-        
-        # color
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        color.SetName("colour")
-        color.Bind(csel.EVT_COLOURSELECT, self.OnSurfaceWireColor)
-        color.SetToolTipString(_("Change wire color"))
-        self.win['surface']['draw']['wire-color'] = color.GetId()
-        gridSizer.Add(item = color, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
-                      pos = (3, 3))
-        
-        # resolution fine
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Fine mode:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                        label = _("resolution:")),
-                     pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        resF = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = 3,
-                           min = 1,
-                           max = 100)
-        resF.SetName("value")
-        self.win['surface']['draw']['res-fine'] = resF.GetId()
-        resF.Bind(wx.EVT_SPINCTRL, self.OnSurfaceResolution)
-        gridSizer.Add(item = resF, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        #
-        # surface attributes
-        #
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Surface attributes")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(2)
-        
-        # type 
-        self.win['surface']['attr'] = {}
-        row = 0
-        for code, attrb in (('color', _("Color")),
-                           ('mask', _("Mask")),
-                           ('transp', _("Transparency")),
-                           ('shine', _("Shininess"))):
-            self.win['surface'][code] = {} 
-            gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                             label = attrb + ':'),
-                          pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-            use = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                             choices = [_("map")])
-            
-            if code not in ('color', 'shine'):
-                use.Insert(item = _("unset"), pos = 0)
-                self.win['surface'][code]['required'] = False
-            else:
-                self.win['surface'][code]['required'] = True
-            if code != 'mask':
-                use.Append(item = _('constant'))
-            self.win['surface'][code]['use'] = use.GetId()
-            use.Bind(wx.EVT_CHOICE, self.OnMapObjUse)
-            gridSizer.Add(item = use, flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 1))
-            
-            map = gselect.Select(parent = panel, id = wx.ID_ANY,
-                                 # size = globalvar.DIALOG_GSELECT_SIZE,
-                                 size = (-1, -1),
-                                 type = "raster")
-            self.win['surface'][code]['map'] = map.GetId() - 1 # FIXME
-            map.Bind(wx.EVT_TEXT, self.OnSurfaceMap)
-            gridSizer.Add(item = map, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND,
-                          pos = (row, 2))
-            
-            if code == 'color':
-                color = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['color', 'value'])
-                value = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                          colour = color,
-                                          size = globalvar.DIALOG_COLOR_SIZE)
-                value.Bind(csel.EVT_COLOURSELECT, self.OnSurfaceMap)
-            elif code == 'mask':
-                value = None
-            else:
-                value = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                                    initial = 0)
-                value.SetRange(minVal = 0, maxVal = 100)
-                value.Bind(wx.EVT_TEXT, self.OnSurfaceMap)
-            
-            if value:
-                self.win['surface'][code]['const'] = value.GetId()
-                value.Enable(False)
-                gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
-                              pos = (row, 3))
-            else:
-                self.win['surface'][code]['const'] = None
-            
-            self.SetMapObjUseMap(nvizType = 'surface',
-                                 attrb = code) # -> enable map / disable constant
-                
-            row += 1
-        boxSizer.Add(item = gridSizer, proportion = 0,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 3)
-        #
-        # position
-        #
-        self.win['surface']['position'] = {}
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Position")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(3)
-        
-        # position
-        self._createControl(panel, data = self.win['surface'], name = 'position',
-                            range = (-10000, 10000), floatSlider = True,
-                            bind = (self.OnSurfacePosition, self.OnSurfacePositionChanged, self.OnSurfacePositionText))
-        
-        axis = wx.Choice (parent = panel, id = wx.ID_ANY, size = (75, -1),
-                          choices = ["X",
-                                     "Y",
-                                     "Z"])
-                                    
-        reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
-        reset.SetToolTipString(_("Reset to default position"))
-        reset.Bind(wx.EVT_BUTTON, self.OnResetSurfacePosition)
-        self.win['surface']['position']['reset'] = reset.GetId()
-        
-        self.win['surface']['position']['axis'] = axis.GetId()
-        axis.SetSelection(0)
-        axis.Bind(wx.EVT_CHOICE, self.OnSurfaceAxis)
-        
-        pslide = self.FindWindowById(self.win['surface']['position']['slider'])
-        ptext = self.FindWindowById(self.win['surface']['position']['text'])
-        ptext.SetValue('0')
-        
-        gridSizer.Add(item = axis, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        gridSizer.Add(item = pslide, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
-        gridSizer.Add(item = ptext, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 2))
-        gridSizer.Add(item = reset, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, pos = (0, 3))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        box.SetSizer(boxSizer)
-        box.Layout()
-        
-        pageSizer.Add(item = boxSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        #
-        # mask
-        #
-##        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-##                            label = " %s " % (_("Mask")))
-##        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-##        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-##        
-##        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-##                                         label = _("Mask zeros:")),
-##                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-##        
-##        elev = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-##                           label = _("by elevation"))
-##        elev.Enable(False) # TODO: not implemented yet
-##        gridSizer.Add(item = elev, pos = (0, 1))
-##        
-##        color = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-##                           label = _("by color"))
-##        color.Enable(False) # TODO: not implemented yet
-##        gridSizer.Add(item = color, pos = (0, 2))
-##        
-##        boxSizer.Add(item = gridSizer, proportion = 1,
-##                  flag = wx.ALL | wx.EXPAND, border = 3)
-##        pageSizer.Add(item = boxSizer, proportion = 0,
-##                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-##                      border = 3)
-        
-        
-        panel.SetSizer(pageSizer)
-
-        panel.Layout()
-        panel.Fit()
-        
-        return panel
-    def _createCPlanePage(self, parent):
-        """!Create cutting planes page"""  
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        self.page['cplane'] = { 'id' : 4, 
-                                'notebook' : self.foldpanelData.GetId() }
-        self.win['cplane'] = {}
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Cutting planes")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        horSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        # planes
-        horSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Active cutting plane:")),
-                     flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        choice = wx.Choice(parent = panel, id = wx.ID_ANY, choices = [])
-        self.win['cplane']['planes'] = choice.GetId()
-        choice.Bind(wx.EVT_CHOICE, self.OnCPlaneSelection)
-        horSizer.Add(item = choice, flag = wx.ALL, border = 5)
-        
-        # shading
-        horSizer.Add(item = wx.Size(-1, -1), proportion = 1)
-        horSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Shading:")),
-                     flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        choices = [_("clear"),
-                   _("top color"),
-                   _("bottom color"),
-                   _("blend"),
-                   _("shaded")]
-        choice = wx.Choice(parent = panel, id = wx.ID_ANY, choices = choices)
-        self.win['cplane']['shading'] = choice.GetId()
-        choice.Bind(wx.EVT_CHOICE, self.OnCPlaneShading)
-        horSizer.Add(item = choice, flag = wx.ALL, border = 5)
-        boxSizer.Add(item = horSizer, flag = wx.EXPAND)
-        
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        # cutting plane horizontal x position
-        self.win['cplane']['position'] = {}
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Horizontal X:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self._createControl(panel, data = self.win['cplane']['position'], name = 'x', size = 250,
-                            range = (-1000, 1000), sliderHor = True, floatSlider = True,
-                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
-        self.FindWindowById(self.win['cplane']['position']['x']['slider']).SetValue(0)
-        self.FindWindowById(self.win['cplane']['position']['x']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['x']['slider']),
-                      pos = (0, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['x']['text']),
-                      pos = (0, 2),
-                      flag = wx.ALIGN_CENTER)   
-        
-        # cutting plane horizontal y position
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Horizontal Y:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self._createControl(panel, data = self.win['cplane']['position'], name = 'y', size = 250,
-                            range = (-1000, 1000), sliderHor = True, floatSlider = True,
-                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
-        self.FindWindowById(self.win['cplane']['position']['y']['slider']).SetValue(0)
-        self.FindWindowById(self.win['cplane']['position']['y']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['y']['slider']),
-                      pos = (1, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['y']['text']),
-                      pos = (1, 2),
-                      flag = wx.ALIGN_CENTER)                         
-        
-        # cutting plane rotation
-        self.win['cplane']['rotation'] = {}
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Rotation:")),
-                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self._createControl(panel, data = self.win['cplane']['rotation'], name = 'rot', size = 250,
-                            range = (0, 360), sliderHor = True,
-                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
-        self.FindWindowById(self.win['cplane']['rotation']['rot']['slider']).SetValue(0)
-        self.FindWindowById(self.win['cplane']['rotation']['rot']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['rot']['slider']),
-                      pos = (2, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['rot']['text']),
-                      pos = (2, 2),
-                      flag = wx.ALIGN_CENTER)
-
-        # cutting plane tilt        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Tilt:")),
-                      pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL)                    
-        self._createControl(panel, data = self.win['cplane']['rotation'], name = 'tilt', size = 250,
-                            range = (0, 360), sliderHor = True,
-                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
-        self.FindWindowById(self.win['cplane']['rotation']['tilt']['slider']).SetValue(0)
-        self.FindWindowById(self.win['cplane']['rotation']['tilt']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['tilt']['slider']),
-                      pos = (3, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['tilt']['text']),
-                      pos = (3, 2),
-                      flag = wx.ALIGN_CENTER)          
-        
-        # cutting pland height
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Height:")),
-                      pos = (4, 0), flag = wx.ALIGN_CENTER_VERTICAL)        
-        self._createControl(panel, data = self.win['cplane']['position'], name = 'z', size = 250,
-                            range = (-1000, 1000), sliderHor = True,
-                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
-        self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetValue(0)
-        self.FindWindowById(self.win['cplane']['position']['z']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['z']['slider']),
-                      pos = (4, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['z']['text']),
-                      pos = (4, 2),
-                      flag = wx.ALIGN_CENTER)
-        
-        boxSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
-                    
-        horSizer = wx.BoxSizer(wx.HORIZONTAL)
-        horSizer.Add(item = wx.Size(-1, -1), proportion = 1, flag = wx.ALL, border = 5)  
-        # reset
-        reset = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Reset"))
-        self.win['cplane']['reset'] = reset.GetId()
-        reset.Bind(wx.EVT_BUTTON, self.OnCPlaneReset)
-        horSizer.Add(item = reset, flag = wx.ALL, border = 5)
-        boxSizer.Add(horSizer, proportion = 0, flag = wx.EXPAND)            
-        
-        
-        pageSizer.Add(boxSizer, proportion = 0, flag = wx.EXPAND)
-        
-        panel.SetSizer(pageSizer)
-        panel.Fit()    
-        
-        return panel
-        
-    def _createConstantPage(self, parent):
-        """!Create constant page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        self.page['constant'] = { 'id' : 1, 
-                                'notebook' : self.foldpanelData.GetId() }
-        self.win['constant'] = {}
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Constant surface")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        horsizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        surface = wx.ComboBox(parent = panel, id = wx.ID_ANY, 
-                              style = wx.CB_SIMPLE | wx.CB_READONLY,
-                              choices = [])
-        self.win['constant']['surface'] = surface.GetId()
-        surface.Bind(wx.EVT_COMBOBOX, self.OnConstantSelection)
-        horsizer.Add(surface, proportion = 1, flag = wx.EXPAND|wx.RIGHT, border = 20)
-
-        addNew = wx.Button(panel, id = wx.ID_ANY, label = _("New"))
-        addNew.Bind(wx.EVT_BUTTON, self.OnNewConstant)
-        self.win['constant']['new'] = addNew.GetId()
-
-        delete = wx.Button(panel, id = wx.ID_ANY, label = _("Delete"))
-        delete.Bind(wx.EVT_BUTTON, self.OnDeleteConstant)
-        self.win['constant']['delete'] = delete.GetId()
-        
-        horsizer.Add(item = addNew, proportion = 0, flag = wx.RIGHT|wx.LEFT, border = 3)
-        horsizer.Add(item = delete, proportion = 0, flag = wx.RIGHT|wx.LEFT, border = 3)
-    
-        boxSizer.Add(item = horsizer, proportion = 0, flag = wx.ALL|wx.EXPAND,
-                      border = 5)
-        
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        # fine resolution
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Fine resolution:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        resF = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           initial = 3,
-                           min = 1,
-                           max = 100)
-        resF.SetName("value")
-        self.win['constant']['resolution'] = resF.GetId()
-        resF.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
-        gridSizer.Add(item = resF, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
-        # value 
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Value:")), pos = (1, 0),
-                                         flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        value = wx.SpinCtrl(panel, id = wx.ID_ANY,
-                                  min = -1e9, max = 1e9,
-                                  size = (65, -1))
-        self.win['constant']['value'] = value.GetId()
-        value.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
-        gridSizer.Add(item = value, pos = (1, 1))
-        
-        # transparency 
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Transparency:")), pos = (2, 0),
-                                         flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        transp = wx.SpinCtrl(panel, id = wx.ID_ANY,
-                                  min = 0, max = 100,
-                                  size = (65, -1))
-        self.win['constant']['transp'] = transp.GetId()
-        transp.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
-        gridSizer.Add(item = transp, pos = (2, 1))
-        
-        # color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Color:")), pos = (3, 0),
-                                         flag = wx.ALIGN_CENTER_VERTICAL)
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = (0,0,0),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        self.win['constant']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnSetConstantProp)
-        gridSizer.Add(item = color, pos = (3, 1))
-        boxSizer.Add(item = gridSizer, proportion = 0, flag = wx.ALL,
-                      border = 5)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-        panel.Fit()    
-        
-        return panel
-        
-    def _createVectorPage(self, parent):
-        """!Create view settings page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        self.page['vector'] = { 'id' : 2,
-                                'notebook' : self.foldpanelData.GetId() }
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        self.win['vector'] = {}
-        
-        # selection
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Vector map")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        vmaps = gselect.Select(parent = panel, type = 'vector',
-                               onPopup = self.GselectOnPopup)
-        vmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetVector)
-        self.win['vector']['map'] = vmaps.GetId()
-        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        self.win['vector']['desc'] = desc.GetId()
-        boxSizer.Add(item = vmaps, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        boxSizer.Add(item = desc, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        #
-        # vector lines
-        #
-        self.win['vector']['lines'] = {}
-        
-        showLines = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                label = _("Show vector lines"))
-        showLines.SetValue(True)
-        
-        self.win['vector']['lines']['show'] = showLines.GetId()
-        showLines.Bind(wx.EVT_CHECKBOX, self.OnVectorShow)
-        
-        pageSizer.Add(item = showLines, proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Vector lines")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        gridSizer.AddGrowableCol(5)
-        
-        # width
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Line:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("width:")),
-                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL | 
-                      wx.ALIGN_RIGHT)
-        
-        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                            initial = 1,
-                            min = 0,
-                            max = 100)
-        width.SetValue(1)
-        self.win['vector']['lines']['width'] = width.GetId()
-        width.Bind(wx.EVT_SPINCTRL, self.OnVectorLines)
-        gridSizer.Add(item = width, pos = (0, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-        
-        # color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("color:")),
-                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALIGN_RIGHT)
-        
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = (0,0,0),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        self.win['vector']['lines']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnVectorLines)
-
-        gridSizer.Add(item = color, pos = (0, 4), flag = wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALIGN_LEFT)
-        
-        # thematic mapping
-        self.win['vector']['lines']['thematic'] = {}
-        checkThematicColor = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                         label = _("use color for thematic mapping"))
-        checkThematicWidth = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                         label = _("use width for thematic mapping"))
-        self.win['vector']['lines']['thematic']['checkcolor'] = checkThematicColor.GetId()
-        self.win['vector']['lines']['thematic']['checkwidth'] = checkThematicWidth.GetId()
-        checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
-        checkThematicWidth.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
-        checkThematicColor.SetValue(False)
-        checkThematicWidth.SetValue(False)
-        
-        vSizer = wx.BoxSizer(wx.VERTICAL)
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer.Add(item = checkThematicColor, flag = wx.ALIGN_CENTER_VERTICAL,
-                    border = 5)
-        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
-                                         label = _("Set options..."))
-        self.win['vector']['lines']['thematic']['buttoncolor'] = setThematic.GetId()
-        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
-        hSizer.Add(item = wx.Size(-1, -1), proportion = 1)
-        hSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
-                    border = 5, proportion = 0)
-        vSizer.Add(hSizer, flag = wx.EXPAND)
-                    
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        hSizer.Add(item = checkThematicWidth, flag = wx.ALIGN_CENTER_VERTICAL,
-                    border = 5)
-        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
-                                         label = _("Set options..."))
-        self.win['vector']['lines']['thematic']['buttonwidth'] = setThematic.GetId()
-        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
-        hSizer.Add(item = wx.Size(-1, -1), proportion = 1)
-        hSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
-                    border = 5, proportion = 0)
-        
-        vSizer.Add(hSizer, flag = wx.EXPAND)
-        gridSizer.Add(item = vSizer, flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
-                      pos = (1, 1), span = (1, 5))
-        
-        # display
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Display")),
-                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALIGN_LEFT)
-        
-        display = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                             choices = [_("on surface(s):"),
-                                        _("flat")])
-        self.win['vector']['lines']['flat'] = display.GetId()
-        display.Bind(wx.EVT_CHOICE, self.OnVectorDisplay)
-        
-        gridSizer.Add(item = display, flag = wx.ALIGN_CENTER_VERTICAL | 
-                      wx.ALIGN_LEFT|wx.EXPAND, pos = (2, 1), span = (1,4))
-        
-        # height
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Height above surface:")),
-                      pos = (3, 5), flag = wx.ALIGN_BOTTOM|wx.EXPAND)
-        
-        surface = wx.CheckListBox(parent = panel, id = wx.ID_ANY, size = (-1, 60),
-                                  choices = [], style = wx.LB_NEEDED_SB)
-        surface.Bind(wx.EVT_CHECKLISTBOX, self.OnVectorSurface)
-        
-        self.win['vector']['lines']['surface'] = surface.GetId()
-        gridSizer.Add(item = surface, 
-                      pos = (3, 0), span = (3, 5),
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
-        
-        self._createControl(panel, data = self.win['vector']['lines'], name = 'height', size = -1,
-                            range = (0, 500), sliderHor = True,
-                            bind = (self.OnVectorHeight, self.OnVectorHeightFull, self.OnVectorHeightText))
-        self.FindWindowById(self.win['vector']['lines']['height']['slider']).SetValue(0)
-        self.FindWindowById(self.win['vector']['lines']['height']['text']).SetValue(0)
-        gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['slider']),
-                      pos = (4, 5),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
-        gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['text']),
-                      pos = (5, 5),
-                      flag = wx.ALIGN_CENTER)
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        #
-        # vector points
-        #
-        self.win['vector']['points'] = {}
-        
-        showPoints = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                 label = _("Show vector points"))
-        showPoints.SetValue(True)
-        self.win['vector']['points']['show'] = showPoints.GetId()
-        showPoints.Bind(wx.EVT_CHECKBOX, self.OnVectorShow)
-        
-        pageSizer.Add(item = showPoints, proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Vector points")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        vertSizer = wx.BoxSizer(wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        gridSizer.AddGrowableCol(0)
-        gridSizer.AddGrowableCol(2)
-        gridSizer.AddGrowableCol(4)
-        gridSizer.AddGrowableCol(6)
-        
-        # icon size
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Icon:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("size:")),
-                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALIGN_RIGHT)
-        
-        isize = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                            initial = 1,
-                            min = 1,
-                            max = 1e6)
-        isize.SetName('value')
-        isize.SetValue(100)
-        self.win['vector']['points']['size'] = isize.GetId()
-        isize.Bind(wx.EVT_SPINCTRL, self.OnVectorPoints)
-        isize.Bind(wx.EVT_TEXT, self.OnVectorPoints)
-        gridSizer.Add(item = isize, pos = (0, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-        
-        # icon color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("color:")),
-                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL |
-                      wx.ALIGN_RIGHT)
-        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                   size = globalvar.DIALOG_COLOR_SIZE)
-        icolor.SetName("color")
-        icolor.SetColour((0,0,255))
-        self.win['vector']['points']['color'] = icolor.GetId()
-        icolor.Bind(csel.EVT_COLOURSELECT, self.OnVectorPoints)
-        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL | 
-                      wx.ALIGN_LEFT,
-                      pos = (0, 4))
-
-        # icon width - seems to do nothing
-##        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-##                                           label = _("width")),
-##                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL |
-##                      wx.ALIGN_RIGHT)
-##        
-##        iwidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-##                             initial = 1,
-##                             min = 1,
-##                             max = 1e6)
-##        iwidth.SetName('value')
-##        iwidth.SetValue(100)
-##        self.win['vector']['points']['width'] = iwidth.GetId()
-##        iwidth.Bind(wx.EVT_SPINCTRL, self.OnVectorPoints)
-##        iwidth.Bind(wx.EVT_TEXT, self.OnVectorPoints)
-##        gridSizer.Add(item = iwidth, pos = (1, 2),
-##                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
-        # icon symbol
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("symbol:")),
-                      pos = (0, 5), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
-        isym = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                          choices = UserSettings.Get(group = 'nviz', key = 'vector',
-                                                   subkey = ['points', 'marker'], internal = True))
-        isym.SetName("selection")
-        self.win['vector']['points']['marker'] = isym.GetId()
-        isym.Bind(wx.EVT_CHOICE, self.OnVectorPoints)
-        gridSizer.Add(item = isym, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
-                      pos = (0, 6))
-        # thematic mapping
-        self.win['vector']['points']['thematic'] = {}
-        checkThematicColor = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                         label = _("use color for thematic mapping"))
-        checkThematicSize = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                         label = _("use size for thematic mapping"))
-        self.win['vector']['points']['thematic']['checkcolor'] = checkThematicColor.GetId()
-        self.win['vector']['points']['thematic']['checksize'] = checkThematicSize.GetId()
-        checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
-        checkThematicSize.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
-        checkThematicColor.SetValue(False)
-        checkThematicSize.SetValue(False)
-        
-        gridSizer.Add(item = checkThematicColor, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
-                      pos = (1, 1), span = (1, 5))
-        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
-                                         label = _("Set options..."))
-        self.win['vector']['points']['thematic']['buttoncolor'] = setThematic.GetId()
-        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
-        gridSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (1, 6))
-                    
-        gridSizer.Add(item = checkThematicSize, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
-                      pos = (2, 1), span = (1, 5))
-        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
-                                         label = _("Set options..."))
-        self.win['vector']['points']['thematic']['buttonsize'] = setThematic.GetId()
-        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
-        gridSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2, 6))                   
-        vertSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND, border = 0)
-        # high
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        gridSizer.AddGrowableCol(1)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Display on surface(s):")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Height above surface:")),
-                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        surface = wx.CheckListBox(parent = panel, id = wx.ID_ANY, size = (-1, 60),
-                                  choices = [], style = wx.LB_NEEDED_SB)
-        surface.Bind(wx.EVT_CHECKLISTBOX, self.OnVectorSurface)
-        self.win['vector']['points']['surface'] = surface.GetId()
-        gridSizer.Add(item = surface, 
-                      pos = (1, 0), span = (3, 1),
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
-        
-        self._createControl(panel, data = self.win['vector']['points'], name = 'height', size = -1,
-                            range = (0, 500),
-                            bind = (self.OnVectorHeight, self.OnVectorHeightFull, self.OnVectorHeightText))
-        
-        self.FindWindowById(self.win['vector']['points']['height']['slider']).SetValue(0)
-        self.FindWindowById(self.win['vector']['points']['height']['text']).SetValue(0)
-        
-        gridSizer.Add(item = self.FindWindowById(self.win['vector']['points']['height']['slider']),
-                      pos = (2, 1),flag = wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = self.FindWindowById(self.win['vector']['points']['height']['text']),
-                      pos = (3, 1),
-                      flag = wx.ALIGN_CENTER)
-                    
-        vertSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND, border = 0)
-        boxSizer.Add(item = vertSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-        panel.Fit()
-
-        return panel
-
-    def GselectOnPopup(self, ltype, exclude = False):
-        """Update gselect.Select() items"""
-        maps = list()
-        for layer in self.mapWindow.Map.GetListOfLayers(l_type = ltype, l_active = True):
-            maps.append(layer.GetName())
-        return maps, exclude
-    
-    def _createVolumePage(self, parent):
-        """!Create view settings page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        self.page['volume'] = { 'id' : 3,
-                                'notebook' : self.foldpanelData.GetId() }
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        self.win['volume'] = {}
-        
-        # selection
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("3D raster map")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        rmaps = gselect.Select(parent = panel, type = '3d-raster',
-                               onPopup = self.GselectOnPopup)
-        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetRaster3D)
-        self.win['volume']['map'] = rmaps.GetId()
-        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        self.win['volume']['desc'] = desc.GetId()
-        boxSizer.Add(item = rmaps, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        boxSizer.Add(item = desc, proportion = 0,
-                     flag = wx.ALL,
-                     border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-                
-        #
-        # draw
-        #
-        self.win['volume']['draw'] = {}
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Draw")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-##        gridSizer.AddGrowableCol(4)
-        
-        # mode
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Mode:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        mode = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
-                          choices = [_("isosurfaces"),
-                                     _("slices")])
-        mode.SetSelection(0)
-        mode.SetName("selection")
-        mode.Bind(wx.EVT_CHOICE, self.OnVolumeMode)
-        self.win['volume']['draw']['mode'] = mode.GetId()
-        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 1))
-        
-        # shading
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Shading:")),
-                      pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        shade = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                           choices = [_("flat"),
-                                      _("gouraud")])
-        shade.SetName("selection")
-        self.win['volume']['draw']['shading'] = shade.GetId()
-        shade.Bind(wx.EVT_CHOICE, self.OnVolumeDrawMode)
-        gridSizer.Add(item = shade, flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (0, 3))
-        
-        # resolution (mode)
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Resolution:")),
-                      pos = (0, 4), flag = wx.ALIGN_CENTER_VERTICAL)
-        resol = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                            initial = 1,
-                            min = 1,
-                            max = 100)
-        resol.SetName("value")
-        self.win['volume']['draw']['resolution'] = resol.GetId()
-        resol.Bind(wx.EVT_SPINCTRL, self.OnVolumeResolution)
-        resol.Bind(wx.EVT_TEXT, self.OnVolumeResolution)
-        gridSizer.Add(item = resol, pos = (0, 5))
-        
-        boxSizer.Add(item = gridSizer, proportion = 0,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 3)
-        
-        #
-        # manage isosurfaces
-        #
-        box = wx.StaticBox(parent = panel, id = wx.ID_ANY, 
-                           label = " %s " % (_("List of isosurfaces")))
-        box.SetName('listStaticBox')
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        # list
-        isolevel = wx.CheckListBox(parent = panel, id = wx.ID_ANY,
-                                   size = (300, 150))
-        self.Bind(wx.EVT_CHECKLISTBOX, self.OnVolumeCheck, isolevel)
-        self.Bind(wx.EVT_LISTBOX, self.OnVolumeSelect, isolevel)
-        
-        self.win['volume']['isosurfs'] = isolevel.GetId()
-        self.win['volume']['slices'] = isolevel.GetId()
-        gridSizer.Add(item = isolevel, pos = (0, 0), span = (4, 1))
-        
-        # buttons (add, delete, move up, move down)
-        btnAdd = wx.Button(parent = panel, id = wx.ID_ADD)
-        self.win['volume']['btnAdd'] = btnAdd.GetId()
-        btnAdd.Bind(wx.EVT_BUTTON, self.OnVolumeAdd)
-        gridSizer.Add(item = btnAdd,
-                      pos = (0, 1))
-        btnDelete = wx.Button(parent = panel, id = wx.ID_DELETE)
-        self.win['volume']['btnDelete'] = btnDelete.GetId()
-        btnDelete.Bind(wx.EVT_BUTTON, self.OnVolumeDelete)
-        btnDelete.Enable(False)
-        gridSizer.Add(item = btnDelete,
-                      pos = (1, 1))
-        btnMoveUp = wx.Button(parent = panel, id = wx.ID_UP)
-        self.win['volume']['btnMoveUp'] = btnMoveUp.GetId()
-        btnMoveUp.Bind(wx.EVT_BUTTON, self.OnVolumeMoveUp)
-        btnMoveUp.Enable(False)
-        gridSizer.Add(item = btnMoveUp,
-                      pos = (2, 1))
-        btnMoveDown = wx.Button(parent = panel, id = wx.ID_DOWN)
-        self.win['volume']['btnMoveDown'] = btnMoveDown.GetId()
-        btnMoveDown.Bind(wx.EVT_BUTTON, self.OnVolumeMoveDown)
-        btnMoveDown.Enable(False)
-        gridSizer.Add(item = btnMoveDown,
-                      pos = (3, 1))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        # isosurface/slice 
-        sizer = wx.BoxSizer()
-        self.isoPanel = self._createIsosurfacePanel(panel)
-        self.slicePanel = self._createSlicePanel(panel)
-        sizer.Add(self.isoPanel, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
-        sizer.Add(self.slicePanel, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
-        sizer.Hide(self.slicePanel)
-        pageSizer.Add(item = sizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL,
-                      border = 3)
-        #
-        # position
-        #
-        self.win['volume']['position'] = {}
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Position")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(3)
-        
-        # position
-        self._createControl(panel, data = self.win['volume'], name = 'position',
-                            range = (-10000, 10000), floatSlider = True,
-                            bind = (self.OnVolumePosition, self.OnVolumePositionChanged, self.OnVolumePositionText))
-        
-        axis = wx.Choice (parent = panel, id = wx.ID_ANY, size = (75, -1),
-                          choices = ["X",
-                                     "Y",
-                                     "Z"])
-                                    
-        reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
-        reset.SetToolTipString(_("Reset to default position"))
-        reset.Bind(wx.EVT_BUTTON, self.OnResetVolumePosition)
-        self.win['volume']['position']['reset'] = reset.GetId()
-        
-        self.win['volume']['position']['axis'] = axis.GetId()
-        axis.SetSelection(0)
-        axis.Bind(wx.EVT_CHOICE, self.OnVolumeAxis)
-        
-        pslide = self.FindWindowById(self.win['volume']['position']['slider'])
-        ptext = self.FindWindowById(self.win['volume']['position']['text'])
-        ptext.SetValue('0')
-        
-        gridSizer.Add(item = axis, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        gridSizer.Add(item = pslide, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
-        gridSizer.Add(item = ptext, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 2))
-        gridSizer.Add(item = reset, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, pos = (0, 3))
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        panel.SetSizer(pageSizer)
-        panel.Fit()
-        
-        return panel
-       
-        
-    def _createLightPage(self, parent):
-        """!Create light page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        
-        self.page['light'] = { 'id' : 0, 
-                               'notebook' : self.foldpanelAppear.GetId() }
-        self.win['light'] = {}
-        
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        show = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                           label = _("Show light model"))
-        show.Bind(wx.EVT_CHECKBOX, self.OnShowLightModel)
-        show.SetValue(True)
-        self._display.showLight = True
-        pageSizer.Add(item = show, proportion = 0,
-                      flag = wx.ALL, border = 3)
-##        surface = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-##                              label = _("Follow source viewpoint"))
-##        pageSizer.Add(item = surface, proportion = 0,
-##                      flag = wx.ALL, border = 3)
-        
-        # position
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Light source position")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        posSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        self._createCompass(panel = panel, sizer = posSizer, type = 'light')
-        
-        pos = LightPositionWindow(panel, id = wx.ID_ANY, size = (175, 175),
-                                  mapwindow = self.mapWindow)
-        self.win['light']['position'] = pos.GetId()
-        posSizer.Add(item = pos,
-                     pos = (1, 1), flag = wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = posSizer, pos = (0, 0))
-        
-        # height
-        self._createControl(panel, data = self.win['light'], name = 'z', sliderHor = False,
-                            range = (0, 100),
-                            bind = (self.OnLightChange, self.OnLightChanged, self.OnLightChange))
-        
-        heightSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:")),
-                      pos = (0, 0), flag = wx.ALIGN_LEFT, span = (1, 2))
-        heightSizer.Add(item = self.FindWindowById(self.win['light']['z']['slider']),
-                        flag = wx.ALIGN_RIGHT, pos = (1, 0))
-        heightSizer.Add(item = self.FindWindowById(self.win['light']['z']['text']),
-                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.TOP |
-                        wx.BOTTOM | wx.RIGHT, pos = (1, 1))
-        
-        gridSizer.Add(item = heightSizer, pos = (0, 2), flag = wx.ALIGN_RIGHT)
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 2)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        # position
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Light color and intensity")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-
-        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:")),
-                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                  colour = UserSettings.Get(group = 'nviz', key = 'light',
-                                                            subkey = 'color'),
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        self.win['light']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnLightColor)
-        gridSizer.Add(item = color, pos = (0, 2))
-
-        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Brightness:")),
-                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self._createControl(panel, data = self.win['light'], name = 'bright', size = 300,
-                            range = (0, 100),
-                            bind = (self.OnLightValue, self.OnLightChanged, self.OnLightValue))
-        gridSizer.Add(item = self.FindWindowById(self.win['light']['bright']['slider']),
-                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = self.FindWindowById(self.win['light']['bright']['text']),
-                      pos = (1, 2),
-                      flag = wx.ALIGN_CENTER)
-        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Ambient:")),
-                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        self._createControl(panel, data = self.win['light'], name = 'ambient', size = 300,
-                            range = (0, 100),
-                            bind = (self.OnLightValue, self.OnLightChanged, self.OnLightValue))
-        gridSizer.Add(item = self.FindWindowById(self.win['light']['ambient']['slider']),
-                      pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = self.FindWindowById(self.win['light']['ambient']['text']),
-                      pos = (2, 2),
-                      flag = wx.ALIGN_CENTER)
-
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 2)
-        pageSizer.Add(item = boxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        # reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
-        # reset.SetToolTipString(_("Reset to default view"))
-        # # self.win['reset'] = reset.GetId()
-        # reset.Bind(wx.EVT_BUTTON, self.OnResetView)
-        
-        # viewSizer.Add(item = reset, proportion = 1,
-        #               flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT,
-        #               border = 5)
-        
-        # gridSizer.AddGrowableCol(3)
-        # gridSizer.Add(item = viewSizer, pos = (4, 0), span = (1, 2),
-        #               flag = wx.EXPAND)
-        
-        panel.SetSizer(pageSizer)
-        panel.Layout()
-        panel.Fit()
-        
-        return panel
-
-    def _createFringePage(self, parent):
-        """!Create fringe page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        
-        self.page['fringe'] = { 'id' : 1,
-                                'notebook' : self.foldpanelAppear.GetId() }
-        self.win['fringe'] = {}
-
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # selection
-        rbox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                             label = " %s " % (_("Surface")))
-        rboxSizer = wx.StaticBoxSizer(rbox, wx.VERTICAL)
-        rmaps = gselect.Select(parent = panel, type = 'raster',
-                               onPopup = self.GselectOnPopup)
-        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetSurface)
-        self.win['fringe']['map'] = rmaps.GetId()
-        rboxSizer.Add(item = rmaps, proportion = 0,
-                      flag = wx.ALL,
-                      border = 3)
-        pageSizer.Add(item = rboxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        ebox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                             label = " %s " % (_("Edges with fringe")))
-        eboxSizer = wx.StaticBoxSizer(ebox, wx.HORIZONTAL)
-        for edge in [(_("N && W"), "nw"),
-                     (_("N && E"), "ne"),
-                     (_("S && W"), "sw"),
-                     (_("S && E"), "se")]:
-            chkbox = wx.CheckBox(parent = panel,
-                                 label = edge[0],
-                                 name = edge[1])
-            self.win['fringe'][edge[1]] = chkbox.GetId()
-            eboxSizer.Add(item = chkbox, proportion = 0,
-                         flag = wx.ADJUST_MINSIZE | wx.LEFT | wx.RIGHT, border = 5)
-            chkbox.Bind(wx.EVT_CHECKBOX, self.OnFringe)
-        
-        pageSizer.Add(item = eboxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-
-        sbox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                             label = " %s " % (_("Settings")))
-        sboxSizer = wx.StaticBoxSizer(sbox, wx.HORIZONTAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        
-        # elevation
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Elevation of fringe from bottom:")),
-                      pos = (0, 0),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                           size = (65, -1), min = -1e6, max = 1e6)
-        spin.SetValue(UserSettings.Get(group = 'nviz', key = 'fringe', subkey = 'elev'))
-        spin.Bind(wx.EVT_SPINCTRL, self.OnFringe)
-        self.win['fringe']['elev'] = spin.GetId()
-        gridSizer.Add(item = spin, pos = (0, 1))
-        
-        # color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Color:")),
-                      pos = (1, 0),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        color.SetColour(UserSettings.Get(group = 'nviz', key = 'fringe',
-                                         subkey = 'color'))
-        color.Bind(csel.EVT_COLOURSELECT, self.OnFringe)
-        self.win['fringe']['color'] = color.GetId()
-        gridSizer.Add(item = color, pos = (1, 1))
-        
-        sboxSizer.Add(item = gridSizer, proportion = 1,
-                      flag = wx.ALL | wx.EXPAND, border = 3)
-        pageSizer.Add(item = sboxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-        panel.Layout()
-        panel.Fit()
-
-        return panel
-    
-    def _createDecorationPage(self, parent):
-        """!Create decoration (north arrow, scalebar, legend) page"""
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        
-        self.page['decoration'] = { 'id' : 2,
-                                    'notebook' : self.foldpanelAppear.GetId()}
-        self.win['decoration'] = {}
-
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        # north arrow
-        self.win['decoration']['arrow'] = {}
-        nabox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                             label = " %s " % (_("North Arrow")))
-        naboxSizer = wx.StaticBoxSizer(nabox, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        # size
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Arrow length (in map units):")),
-                      pos = (0,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        sizeCtrl = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1), style = wx.TE_PROCESS_ENTER)
-        gridSizer.Add(sizeCtrl, pos = (0, 2))
-        self.win['decoration']['arrow']['size'] = sizeCtrl.GetId()
-        sizeCtrl.Bind(wx.EVT_TEXT_ENTER, self.OnDecorationProp)
-        sizeCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnDecorationProp)
-        
-        # color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Arrow color:")),
-                      pos = (1,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        gridSizer.Add(color, pos = (1, 2))
-        self.win['decoration']['arrow']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnDecorationProp)
-        
-        # control
-        toggle = wx.ToggleButton(parent = panel, id = wx.ID_ANY, label = _("Place arrow"))
-        gridSizer.Add(item = toggle, pos = (2, 0))
-        toggle.Bind(wx.EVT_TOGGLEBUTTON, self.OnDecorationPlacement)
-        self.win['decoration']['arrow']['place'] = toggle.GetId()
-        toggle.SetName('placeArrow')
-
-        delete = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Delete"))
-        gridSizer.Add(item = delete, pos = (2, 1))
-        delete.Bind(wx.EVT_BUTTON, self.OnArrowDelete)
-        naboxSizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND, border = 3)
-        pageSizer.Add(item = naboxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)
-        
-        
-        # north arrow
-        self.win['decoration']['scalebar'] = {}
-        nabox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                             label = " %s " % (_("Scale bar")))
-        naboxSizer = wx.StaticBoxSizer(nabox, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        # size
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Scale bar length (in map units):")),
-                      pos = (0,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        sizeCtrl = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1), style = wx.TE_PROCESS_ENTER)
-        gridSizer.Add(sizeCtrl, pos = (0, 2))
-        self.win['decoration']['scalebar']['size'] = sizeCtrl.GetId()
-        sizeCtrl.Bind(wx.EVT_TEXT_ENTER, self.OnDecorationProp)
-        sizeCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnDecorationProp)
-        
-        # color
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Scale bar color:")),
-                      pos = (1,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
-        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                  size = globalvar.DIALOG_COLOR_SIZE)
-        gridSizer.Add(color, pos = (1, 2))
-        self.win['decoration']['scalebar']['color'] = color.GetId()
-        color.Bind(csel.EVT_COLOURSELECT, self.OnDecorationProp)
-        
-        # control
-        toggle = wx.ToggleButton(parent = panel, id = wx.ID_ANY, label = _("Place scalebar"))
-        gridSizer.Add(item = toggle, pos = (2, 0))
-        toggle.Bind(wx.EVT_TOGGLEBUTTON, self.OnDecorationPlacement)
-        self.win['decoration']['scalebar']['place'] = toggle.GetId()
-        toggle.SetName('placeScalebar')
-
-        delete = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Delete last"))
-        gridSizer.Add(item = delete, pos = (2, 1))
-        delete.Bind(wx.EVT_BUTTON, self.OnScalebarDelete)
-        naboxSizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND, border = 3)
-        pageSizer.Add(item = naboxSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
-                      border = 3)      
-        panel.SetSizer(pageSizer)
-        panel.Layout()
-        panel.Fit()
-
-        return panel
-    
-    def GetLayerData(self, nvizType, nameOnly = False):
-        """!Get nviz data"""
-        name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
-        if nameOnly:
-            return name
-        
-        if nvizType == 'surface' or nvizType == 'fringe':
-            return self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
-        elif nvizType == 'vector':
-            return self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'nviz')
-        elif nvizType == 'volume':
-            return self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
-        
-        return None
-        
-    def OnRecord(self, event):
-        """!Animation: start recording"""
-        anim = self.mapWindow.GetAnimation()
-        if not anim.IsPaused():
-            if anim.Exists() and not anim.IsSaved():
-                msg = _("Do you want to record new animation without saving the previous one?")
-                dlg = wx.MessageDialog(parent = self,
-                                       message = msg,
-                                       caption =_("Animation already axists"),
-                                       style = wx.YES_NO | wx.CENTRE)
-                if dlg.ShowModal() == wx.ID_NO:
-                    dlg.Destroy()
-                    return
-                
-        
-            anim.Clear()
-            self.UpdateFrameIndex(0)
-            self.UpdateFrameCount()
-            
-        anim.SetPause(False)
-        anim.SetMode(mode = 'record')
-        anim.Start()
-        
-        self.FindWindowById(self.win['anim']['play']).Disable()
-        self.FindWindowById(self.win['anim']['record']).Disable()
-        self.FindWindowById(self.win['anim']['pause']).Enable()
-        self.FindWindowById(self.win['anim']['stop']).Enable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        
-    def OnPlay(self, event):
-        """!Animation: replay"""
-        anim = self.mapWindow.GetAnimation()
-        anim.SetPause(False)
-        anim.SetMode(mode = 'play')
-        anim.Start()
-        
-        self.FindWindowById(self.win['anim']['play']).Disable()
-        self.FindWindowById(self.win['anim']['record']).Disable()
-        self.FindWindowById(self.win['anim']['pause']).Enable()
-        self.FindWindowById(self.win['anim']['stop']).Enable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Enable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Enable()
-        
-    def OnStop(self, event):
-        """!Animation: stop recording/replaying"""
-        anim = self.mapWindow.GetAnimation()
-        anim.SetPause(False)
-        if anim.GetMode() == 'save':
-            anim.StopSaving()
-        if anim.IsRunning():
-            anim.Stop()
-        
-        self.UpdateFrameIndex(0)
-        
-        self.FindWindowById(self.win['anim']['play']).Enable()
-        self.FindWindowById(self.win['anim']['record']).Enable()
-        self.FindWindowById(self.win['anim']['pause']).Disable()
-        self.FindWindowById(self.win['anim']['stop']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        
-    def OnPause(self, event):
-        """!Pause animation"""
-        anim = self.mapWindow.GetAnimation()
-        
-        anim.SetPause(True)
-        mode = anim.GetMode()
-        if anim.IsRunning():
-            anim.Pause()
-            
-        if mode == "record":
-            self.FindWindowById(self.win['anim']['play']).Disable()
-            self.FindWindowById(self.win['anim']['record']).Enable()
-            self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-            self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        elif mode == 'play':
-            self.FindWindowById(self.win['anim']['record']).Disable()
-            self.FindWindowById(self.win['anim']['play']).Enable()
-            self.FindWindowById(self.win['anim']['frameIndex']['slider']).Enable()
-            self.FindWindowById(self.win['anim']['frameIndex']['text']).Enable()
-        
-        self.FindWindowById(self.win['anim']['pause']).Disable()
-        self.FindWindowById(self.win['anim']['stop']).Enable()
-
-        
-    def OnFrameIndex(self, event):
-        """!Frame index changed (by slider)"""
-        index = event.GetInt()
-        self.UpdateFrameIndex(index = index, sliderWidget = False)
-        
-    def OnFrameIndexText(self, event):
-        """!Frame index changed by (textCtrl)"""
-        index = event.GetValue()
-        self.UpdateFrameIndex(index = index, textWidget = False)
-        
-    def OnFPS(self, event):
-        """!Frames per second changed"""
-        anim = self.mapWindow.GetAnimation()
-        anim.SetFPS(event.GetInt())
-        
-    def UpdateFrameIndex(self, index, sliderWidget = True, textWidget = True, goToFrame = True):
-        """!Update frame index"""
-        anim = self.mapWindow.GetAnimation()
-        
-        # check index
-        frameCount = anim.GetFrameCount()
-        if index >= frameCount:
-            index = frameCount - 1
-        if index < 0:
-            index = 0
-            
-        if sliderWidget:
-            slider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
-            slider.SetValue(index)
-        if textWidget:
-            text = self.FindWindowById(self.win['anim']['frameIndex']['text'])
-            text.SetValue(int(index))
-        
-        # if called from tool window, update frame
-        if goToFrame:
-            anim.GoToFrame(int(index))
-            
-    def UpdateFrameCount(self):
-        """!Update frame count label"""
-        anim = self.mapWindow.GetAnimation()
-        count = anim.GetFrameCount()
-        self.FindWindowById(self.win['anim']['info']).SetLabel(str(count))
-        
-    def OnAnimationFinished(self, event):
-        """!Animation finished"""
-        anim = self.mapWindow.GetAnimation()
-        self.UpdateFrameIndex(index = 0)
-        
-        slider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
-        text = self.FindWindowById(self.win['anim']['frameIndex']['text'])
-        
-        if event.mode == 'record':
-            count = anim.GetFrameCount()
-            slider.SetMax(count)
-            self.UpdateFrameCount()
-            
-        self.FindWindowById(self.win['anim']['pause']).Disable()
-        self.FindWindowById(self.win['anim']['stop']).Disable()
-        self.FindWindowById(self.win['anim']['record']).Enable()
-        self.FindWindowById(self.win['anim']['play']).Enable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        self.FindWindowById(self.win['anim']['save']['image']['confirm']).Enable()
-        
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-        
-    def OnAnimationUpdateIndex(self, event):
-        """!Animation: frame index changed"""
-        if event.mode == 'record':
-            self.UpdateFrameCount()
-        elif event.mode == 'play':
-            self.UpdateFrameIndex(index = event.index, goToFrame = False)
-        
-    def OnSaveAnimation(self, event):
-        """!Save animation as a sequence of images"""
-        anim = self.mapWindow.GetAnimation()
-        
-        prefix = self.FindWindowById(self.win['anim']['save']['image']['prefix']).GetValue()
-        format = self.FindWindowById(self.win['anim']['save']['image']['format']).GetSelection()
-        dir = self.FindWindowById(self.win['anim']['save']['image']['dir']).GetValue()
-        
-        if not prefix:
-            gcmd.GMessage(parent = self,
-                          message = _("No file prefix given."))
-            return
-        elif not os.path.exists(dir):
-            gcmd.GMessage(parent = self,
-                          message = _("Directory %s does not exist.") % dir)
-            return
-            
-        self.FindWindowById(self.win['anim']['pause']).Disable()
-        self.FindWindowById(self.win['anim']['stop']).Enable()
-        self.FindWindowById(self.win['anim']['record']).Disable()
-        self.FindWindowById(self.win['anim']['play']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        
-        self.FindWindowById(self.win['anim']['save']['image']['confirm']).Disable()
-        
-        anim.SaveAnimationFile(path = dir, prefix = prefix, format = format)
-        
-    def OnNewConstant(self, event):
-        """!Create new surface with constant value"""
-        #TODO settings
-        name = self.mapWindow.NewConstant()
-        win = self.FindWindowById(self.win['constant']['surface'])
-        name = _("constant#") + str(name)
-        win.Append(name)
-        win.SetStringSelection(name)
-        self.OnConstantSelection(None)
-        self.EnablePage(name = 'constant', enabled = True)
-        
-        self.mapWindow.Refresh(eraseBackground = False)
-        
-        # need to update list of surfaces in vector page
-        for vtype in ('points', 'lines'):
-            checklist = self.FindWindowById(self.win['vector'][vtype]['surface'])
-            checklist.Append(name)
-        win = self.FindWindowById(self.win['vector']['map'])
-        win.SetValue(win.GetValue())
-                
-
-    def OnDeleteConstant(self, event):
-        """!Delete selected constant surface"""
-        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
-        if layerIdx == wx.NOT_FOUND:
-            return
-        name = self.FindWindowById(self.win['constant']['surface']).GetStringSelection()
-        self.mapWindow.DeleteConstant(layerIdx)
-        win = self.FindWindowById(self.win['constant']['surface'])
-        win.Delete(layerIdx)
-        if win.IsEmpty():
-            win.SetValue("")
-            self.EnablePage(name = 'constant', enabled = False)
-        else:
-            win.SetSelection(0)
-            self.OnConstantSelection(None)
-            
-        # need to update list of surfaces in vector page
-        for vtype in ('points', 'lines'):
-            checklist = self.FindWindowById(self.win['vector'][vtype]['surface'])
-            checklist.Delete(checklist.FindString(name))
-            
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-    
-    def OnConstantSelection(self, event):
-        """!Constant selected"""
-        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
-        if layerIdx == wx.NOT_FOUND:
-            return
-        name = _("constant#") + str(layerIdx + 1)
-        data = self.mapWindow.constants[layerIdx]
-        for attr, value in data['constant'].iteritems():
-            if attr == 'color':
-                value = self._getColorFromString(value)
-            if attr in ('color', 'value', 'resolution', 'transp'):
-                if attr == 'transp':
-                    self.FindWindowById(self.win['constant'][attr]).SetValue(self._getPercent(value))
-                self.FindWindowById(self.win['constant'][attr]).SetValue(value)
-        
-    def OnSetConstantProp(self, event):
-        """!Change properties (color, value, resolution)
-            of currently selected constant surface"""
-        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
-        if layerIdx == wx.NOT_FOUND:
-            return
-        data = self.mapWindow.constants[layerIdx]
-        for attr in ('resolution', 'value', 'transp'):
-            data['constant'][attr] = self.FindWindowById(self.win['constant'][attr]).GetValue()
-        data['constant']['color'] = self._getColorString(
-                self.FindWindowById(self.win['constant']['color']).GetValue())
-        data['constant']['transp'] = self._getPercent(data['constant']['transp'], toPercent = False)
-        
-       # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event) 
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnFringe(self, event):
-        """!Show/hide fringe"""
-        data = self.GetLayerData('fringe')['surface']
-        
-        sid = data['object']['id']
-        elev = self.FindWindowById(self.win['fringe']['elev']).GetValue()
-        color = self.FindWindowById(self.win['fringe']['color']).GetValue()
-        
-        self._display.SetFringe(sid, color, elev,
-                                self.FindWindowById(self.win['fringe']['nw']).IsChecked(),
-                                self.FindWindowById(self.win['fringe']['ne']).IsChecked(),
-                                self.FindWindowById(self.win['fringe']['sw']).IsChecked(),
-                                self.FindWindowById(self.win['fringe']['se']).IsChecked())
-        self.mapWindow.Refresh(False)
-        
-    def OnScroll(self, event, win, data):
-        """!Generic scrolling handler"""
-        winName = self.__GetWindowName(win, event.GetId())
-        if not winName:
-            return
-        data[winName] = self.FindWindowById(event.GetId()).GetValue()
-        for w in win[winName].itervalues():
-            self.FindWindowById(w).SetValue(data[winName])
-        
-        event.Skip()
-        
-    def AdjustSliderRange(self, slider, value):
-        minim, maxim = slider.GetRange()
-        if not (minim <= value <= maxim):
-            slider.SetRange(min(minim, value), max(maxim, value))
-    
-    def _createIsosurfacePanel(self, parent):
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        
-        vSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Isosurface attributes")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        
-        self.win['volume']['attr'] = {}
-        inout = wx.CheckBox(parent = panel, id = wx.ID_ANY, 
-                            label = _("toggle normal direction"))
-        gridSizer.Add(item = inout, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL)
-        inout.Bind(wx.EVT_CHECKBOX, self.OnInOutMode)
-        self.win['volume']['inout'] = inout.GetId()
-        
-        row = 1
-        for code, attrb in (('topo', _("Isosurface value")),
-                            ('color', _("Color")),
-                            ('mask', _("Mask")),
-                            ('transp', _("Transparency")),
-                            ('shine', _("Shininess"))):
-            self.win['volume'][code] = {} 
-            # label
-            colspan = 1
-            if code == 'topo':
-                colspan = 2
-            gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                             label = attrb + ':'),
-                          pos = (row, 0), span = (1, colspan),flag = wx.ALIGN_CENTER_VERTICAL)
-            if code != 'topo':
-                use = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
-                                 choices = [_("map")])
-            else:
-                use = None
-            # check for required properties
-            if code not in ('topo', 'color', 'shine'):
-                use.Insert(item = _("unset"), pos = 0)
-                self.win['volume'][code]['required'] = False
-            else:
-                self.win['volume'][code]['required'] = True
-            if use and code != 'mask':
-                use.Append(item = _('constant'))
-            if use:
-                self.win['volume'][code]['use'] = use.GetId()
-                use.Bind(wx.EVT_CHOICE, self.OnMapObjUse)
-                gridSizer.Add(item = use, flag = wx.ALIGN_CENTER_VERTICAL,
-                              pos = (row, 1))
-                    
-            if code != 'topo':
-                map = gselect.Select(parent = panel, id = wx.ID_ANY,
-                                     # size = globalvar.DIALOG_GSELECT_SIZE,
-                                     size = (200, -1),
-                                     type = "grid3")
-                self.win['volume'][code]['map'] = map.GetId() - 1 # FIXME
-                map.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
-                gridSizer.Add(item = map, flag = wx.ALIGN_CENTER_VERTICAL,
-                              pos = (row, 2))
-            else:
-                map = None
-            
-            if code == 'color':
-                color = UserSettings.Get(group = 'nviz', key = 'volume', subkey = ['color', 'value'])
-                value = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                          colour = color,
-                                          size = globalvar.DIALOG_COLOR_SIZE)
-                value.Bind(csel.EVT_COLOURSELECT, self.OnVolumeIsosurfMap)
-                value.SetName('color')
-            elif code == 'mask':
-                value = None
-            elif code == 'topo':
-                value = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (200, -1),
-                            style = wx.TE_PROCESS_ENTER)
-                value.Bind(wx.EVT_TEXT_ENTER, self.OnVolumeIsosurfMap)
-                value.Bind(wx.EVT_KILL_FOCUS, self.OnVolumeIsosurfMap)
-##                value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
-            else:
-                size = (65, -1)
-                value = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = size,
-                                    initial = 0)
-                if code == 'topo':
-                    value.SetRange(minVal = -1e9, maxVal = 1e9)
-                elif code in ('shine', 'transp'):
-                    value.SetRange(minVal = 0, maxVal = 100)
-                
-                value.Bind(wx.EVT_SPINCTRL, self.OnVolumeIsosurfMap)
-                value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
-            
-            if value:
-                self.win['volume'][code]['const'] = value.GetId()
-                if code == 'topo':
-                    gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
-                                  pos = (row, 2))
-                else:
-                    value.Enable(False)
-                    gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
-                                  pos = (row, 3))
-            else:
-                self.win['volume'][code]['const'] = None
-            
-            if code != 'topo':
-                self.SetMapObjUseMap(nvizType = 'volume',
-                                     attrb = code) # -> enable map / disable constant
-            
-            row += 1
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        vSizer.Add(item = boxSizer, proportion = 1,
-                     flag = wx.EXPAND, border = 0)
-        panel.SetSizer(vSizer)
-        
-        return panel
-    
-    def _createSlicePanel(self, parent):
-        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
-        
-        vSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                            label = " %s " % (_("Slice attributes")))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        hSizer = wx.BoxSizer()
-        
-        self.win['volume']['slice'] = {}
-        hSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                      label = _("Slice parallel to axis:")), proportion = 0,
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 3)
-        axes = wx.Choice(parent = panel, id = wx.ID_ANY, size = (65, -1), choices = ("X", "Y", "Z"))
-        hSizer.Add(axes, proportion = 0, flag = wx.ALIGN_LEFT|wx.LEFT, border = 3)
-        self.win['volume']['slice']['axes'] = axes.GetId()
-        axes.Bind(wx.EVT_CHOICE, self.OnVolumeSliceAxes)
-        boxSizer.Add(hSizer, proportion = 0, flag = wx.ALL|wx.EXPAND, border = 3)
-        
-        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
-        gridSizer.AddGrowableCol(0,1)
-        gridSizer.AddGrowableCol(1,2)
-        gridSizer.AddGrowableCol(2,2)
-        
-        # text labels
-        for i in range(2):
-            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
-            label.SetName('label_edge_' + str(i))
-            gridSizer.Add(item = label, pos = (0, i + 1),
-                          flag = wx.ALIGN_CENTER)
-        for i in range(2,4):
-            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
-            label.SetName('label_edge_' + str(i))
-            gridSizer.Add(item = label, pos = (3, i -1),
-                          flag = wx.ALIGN_CENTER)
-        for i in range(2):
-            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
-            label.SetName('label_coord_' + str(i))
-            gridSizer.Add(item = label, pos = (i + 1, 0),
-                          flag = wx.ALIGN_CENTER_VERTICAL)
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        label.SetName('label_coord_2')
-        gridSizer.Add(item = label, pos = (4, 0), 
-                          flag = wx.ALIGN_CENTER_VERTICAL)
-        # sliders
-        for i, coord in enumerate(('x1', 'x2')):
-            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
-            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
-            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
-            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
-            gridSizer.Add(item = slider, pos = (1, i + 1), 
-                          flag = wx.ALIGN_CENTER|wx.EXPAND)
-                        
-        for i, coord in enumerate(('y1', 'y2')):
-            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
-            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
-            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
-            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
-            gridSizer.Add(item = slider, pos = (2, i + 1), 
-                          flag = wx.ALIGN_CENTER|wx.EXPAND)
-        
-        for i, coord in enumerate(('z1', 'z2')):
-            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
-            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
-            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
-            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
-            gridSizer.Add(item = slider, pos = (4,i+1), 
-                          flag = wx.ALIGN_CENTER|wx.EXPAND)
-                        
-        
-        boxSizer.Add(item = gridSizer, proportion = 1,
-                     flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        # transparency, reset
-        hSizer = wx.BoxSizer()
-        hSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                      label = _("Transparency:")), proportion = 0,
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, border = 7)
-        spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
-                           min = 0, max = 100, initial = 0)
-        spin.Bind(wx.EVT_SPINCTRL, self.OnSliceTransparency)
-        self.win['volume']['slice']['transp'] = spin.GetId()
-        hSizer.Add(item = spin, proportion = 0,
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, border = 7)
-                    
-        hSizer.Add(item = wx.Size(-1, -1), proportion = 1,
-                      flag = wx.EXPAND)
-        reset = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Reset"))
-        reset.Bind(wx.EVT_BUTTON, self.OnSliceReset)
-        self.win['volume']['slice']['reset'] = reset.GetId()
-        hSizer.Add(item = reset, proportion = 0,
-                      flag = wx.ALIGN_CENTER_VERTICAL|wx.TOP, border = 7)
-        
-        boxSizer.Add(hSizer, proportion = 0, flag = wx.ALL|wx.EXPAND, border = 3)
-        panel.SetSizer(boxSizer)
-        
-        return panel
-    
-    def _createControl(self, parent, data, name, range, bind = (None, None, None),
-                       sliderHor = True, size = 200, floatSlider = False):
-        """!Add control (Slider + TextCtrl)"""
-        data[name] = dict()
-        if sliderHor:
-            style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
-                wx.SL_BOTTOM
-            sizeW = (size, -1)
-        else:
-            style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | \
-                wx.SL_INVERSE
-            sizeW = (-1, size)
-        
-        kwargs = dict(parent = parent, id = wx.ID_ANY,
-                           minValue = range[0],
-                           maxValue = range[1],
-                           style = style,
-                           size = sizeW)
-        if floatSlider:
-            slider = FloatSlider(**kwargs)
-        else:
-            slider = wx.Slider(**kwargs)
-            
-        slider.SetName('slider')
-        if bind[0]:
-            #EVT_SCROLL emits event after slider is released, EVT_SPIN not
-            slider.Bind(wx.EVT_SPIN, bind[0])
-        
-        if bind[1]:
-            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, bind[1]) 
-        data[name]['slider'] = slider.GetId()
-        
-        text = NumTextCtrl(parent = parent, id = wx.ID_ANY, size = (65, -1),
-                            style = wx.TE_PROCESS_ENTER)
-        
-        text.SetName('text')
-        if bind[2]:
-            text.Bind(wx.EVT_TEXT_ENTER, bind[2])
-            text.Bind(wx.EVT_KILL_FOCUS, bind[2])
-        
-        data[name]['text'] = text.GetId()
-        
-    def _createCompass(self, panel, sizer, type):
-        """!Create 'compass' widget for light and view page"""
-        w = wx.Button(panel, id = wx.ID_ANY, label = _("W"))
-        n = wx.Button(panel, id = wx.ID_ANY, label = _("N"))
-        s = wx.Button(panel, id = wx.ID_ANY, label = _("S"))
-        e = wx.Button(panel, id = wx.ID_ANY, label = _("E"))
-        nw = wx.Button(panel, id = wx.ID_ANY, label = _("NW"))
-        ne = wx.Button(panel, id = wx.ID_ANY, label = _("NE"))
-        se = wx.Button(panel, id = wx.ID_ANY, label = _("SE"))
-        sw = wx.Button(panel, id = wx.ID_ANY, label = _("SW"))
-        minWidth = sw.GetTextExtent(sw.GetLabel())[0] + 15
-        for win, name in zip((w, n, s, e, nw, ne, se, sw),
-                        ('w', 'n', 's', 'e', 'nw', 'ne', 'se', 'sw')):
-            win.SetMinSize((minWidth, -1))
-            win.Bind(wx.EVT_BUTTON, self.OnLookFrom)
-            win.SetName(type + '_' + name)
-        sizer.Add(item = nw, pos = (0, 0), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = n, pos = (0, 1), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = ne, pos = (0, 2), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = e, pos = (1, 2), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = se, pos = (2, 2), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = s, pos = (2, 1), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = sw, pos = (2, 0), flag = wx.ALIGN_CENTER)
-        sizer.Add(item = w, pos = (1, 0), flag = wx.ALIGN_CENTER)
-        
-        
-        
-    def __GetWindowName(self, data, id):
-        for name in data.iterkeys():
-            if type(data[name]) is type({}):
-                for win in data[name].itervalues():
-                    if win == id:
-                        return name
-            else:
-                if data[name] == id:
-                    return name
-        
-        return None
-
-    def UpdateSettings(self):
-        """!Update view from settings values 
-        stored in self.mapWindow.view dictionary"""
-        for control in ('height',
-                        'persp',
-                        'twist',
-                        'z-exag'):
-            for win in self.win['view'][control].itervalues():             
-                try:
-                    if control == 'height':
-                        value = int(self.mapWindow.iview[control]['value'])
-                    else:
-                        value = self.mapWindow.view[control]['value']
-                except KeyError:
-                    value = -1
-                        
-                self.FindWindowById(win).SetValue(value)
-        
-        viewWin = self.FindWindowById(self.win['view']['position'])
-        x, y = viewWin.UpdatePos(self.mapWindow.view['position']['x'],
-                                 self.mapWindow.view['position']['y'])
-        viewWin.Draw(pos = (x, y), scale = True)
-        viewWin.Refresh(False)
-        
-        color = self._getColorString(self.mapWindow.view['background']['color'])
-        self._display.SetBgColor(str(color))
-        
-        self.Update()
-        
-        self.mapWindow.Refresh(eraseBackground = False)
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(True)
-        
-    def OnShowLightModel(self, event):
-        """!Show light model"""
-        self._display.showLight = event.IsChecked()
-        self._display.DrawLightingModel()
-        
-    def OnLightChange(self, event):
-        """!Position of the light changing"""
-        winName = self.__GetWindowName(self.win['light'], event.GetId())
-        if not winName:
-            return
-        
-        value = self.FindWindowById(event.GetId()).GetValue()
-        
-        self.mapWindow.light['position']['z'] = value
-        for win in self.win['light'][winName].itervalues():
-            self.FindWindowById(win).SetValue(value)
-            
-        self.PostLightEvent()
-        
-        event.Skip()
-        
-    def OnLightChanged(self, event):
-        """!Light changed"""
-        self.PostLightEvent(refresh = True)
-        
-    def OnLightColor(self, event):
-        """!Color of the light changed"""
-        self.mapWindow.light['color'] = tuple(event.GetValue())
-        
-        self.PostLightEvent(refresh = True)
-        
-        event.Skip()
-        
-    def OnLightValue(self, event):
-        """!Light brightness/ambient changing"""
-        data = self.mapWindow.light
-        self.OnScroll(event, self.win['light'], data)
-        
-        self.PostLightEvent()
-        event.Skip()
-        
-    def OnBgColor(self, event):
-        """!Background color changed"""
-        color = event.GetValue()
-        self.mapWindow.view['background']['color'] = tuple(color)
-        color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
-        self._display.SetBgColor(str(color))
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnSetSurface(self, event):
-        """!Surface selected, currently used for fringes"""
-        name = event.GetString()
-        try:
-            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')['surface']
-        except:
-            self.EnablePage('fringe', False)
-            return
-        
-        layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
-        self.EnablePage('fringe', True)
-        
-    def OnSetRaster(self, event):
-        """!Raster map selected, update surface page"""
-        name = event.GetString()
-        try:
-            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')['surface']
-        except:
-            self.EnablePage('surface', False)
-            return
-
-        layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
-        self.EnablePage('surface', True)
-        self.UpdateSurfacePage(layer, data, updateName = False)
-        
-    def OnSetVector(self, event):
-        """!Vector map selected, update properties page"""
-        name = event.GetString()
-        try:
-            data = self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'nviz')['vector']
-        except:
-            self.EnablePage('vector', False)
-            return
-        layer = self.mapWindow.GetLayerByName(name, mapType = 'vector')
-        self.EnablePage('vector', True)
-        self.UpdateVectorPage(layer, data, updateName = False)
-
-    def OnSetRaster3D(self, event):
-        """!3D Raster map selected, update surface page"""
-        name = event.GetString()
-        try:
-            data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')['volume']
-        except:
-            self.EnablePage('volume', False)
-            return
-        
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        self.EnablePage('volume', True)
-        self.UpdateVolumePage(layer, data, updateName = False)
-        
-    def OnViewChange(self, event):
-        """!Change view, render in quick mode"""
-        # find control
-        winName = self.__GetWindowName(self.win['view'], event.GetId())
-        if not winName:
-            return
-        
-        value = self.FindWindowById(event.GetId()).GetValue()
-        slider = self.FindWindowById(self.win['view'][winName]['slider'])
-        self.AdjustSliderRange(slider = slider, value = value)
-        
-        if winName == 'height':
-            view = self.mapWindow.iview # internal
-        else:
-            view = self.mapWindow.view
-        
-        if winName == 'z-exag' and value >= 0:
-            self.PostViewEvent(zExag = True)
-        else:
-            self.PostViewEvent(zExag = False)
-        
-        if winName in ('persp', 'twist'):
-            convert = int
-        else:
-            convert = float
-        
-        view[winName]['value'] = convert(value)
-            
-        for win in self.win['view'][winName].itervalues():
-            self.FindWindowById(win).SetValue(value)
-
-        self.mapWindow.iview['dir']['use'] = False
-        self.mapWindow.render['quick'] = True
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-        
-    def OnViewChanged(self, event):
-        """!View changed, render in full resolution"""
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-        self.UpdateSettings()
-        try:# when calling event = None
-            event.Skip()
-        except AttributeError:
-            pass
-            
-    def OnViewChangedText(self, event):
-        """!View changed, render in full resolution""" 
-        self.mapWindow.render['quick'] = False
-        self.OnViewChange(event)
-        self.OnViewChanged(None)
-        self.Update()
-        
-        event.Skip()
-    
-    def OnLookAt(self, event):
-        """!Look here/center"""
-        name = self.FindWindowById(event.GetId()).GetName()
-        if name == 'center':
-            self._display.LookAtCenter()
-            focus = self.mapWindow.iview['focus']
-            focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
-            self.mapWindow.saveHistory = True
-            self.mapWindow.Refresh(False)
-        elif name == 'top':
-            self.mapWindow.view['position']['x'] = 0.5
-            self.mapWindow.view['position']['y'] = 0.5
-            self.PostViewEvent(zExag = True)
-            self.UpdateSettings()
-            self.mapWindow.Refresh(False)
-        else: # here
-            if self.FindWindowById(event.GetId()).GetValue():
-                self.mapDisplay.Raise()
-                self.mapWindow.mouse['use'] = 'lookHere'
-                self.mapWindow.SetCursor(self.mapWindow.cursors["cross"])
-            else:
-                self.mapWindow.mouse['use'] = 'default'
-                self.mapWindow.SetCursor(self.mapWindow.cursors['default'])
-            
-    def OnResetView(self, event):
-        """!Reset to default view (view page)"""
-        self.mapWindow.ResetView()
-        self.UpdateSettings()
-        self.mapWindow.Refresh(False)
-        
-    def OnResetSurfacePosition(self, event):
-        """!Reset position of surface"""
-        
-        for win in self.win['surface']['position'].itervalues():
-            if win == self.win['surface']['position']['axis']:
-                self.FindWindowById(win).SetSelection(0)
-            elif win == self.win['surface']['position']['reset']:
-                continue
-            else:
-                self.FindWindowById(win).SetValue(0)
-                
-        data = self.GetLayerData('surface')
-        data['surface']['position']['x'] = 0
-        data['surface']['position']['y'] = 0
-        data['surface']['position']['z'] = 0
-        data['surface']['position']['update'] = None
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-            
-    def OnLookFrom(self, event):
-        """!Position of view/light changed by buttons"""
-        name = self.FindWindowById(event.GetId()).GetName()
-        buttonName = name.split('_')[1]
-        if name.split('_')[0] == 'view':
-            type = 'view'
-            data = self.mapWindow.view
-        else:
-            type = 'light'
-            data = self.mapWindow.light
-        if buttonName == 'n': # north
-            data['position']['x'] = 0.5
-            data['position']['y'] = 0.0
-        elif buttonName == 's': # south
-            data['position']['x'] = 0.5
-            data['position']['y'] = 1.0
-        elif buttonName == 'e': # east
-            data['position']['x'] = 1.0
-            data['position']['y'] = 0.5
-        elif buttonName =='w': # west
-            data['position']['x'] = 0.0
-            data['position']['y'] = 0.5
-        elif buttonName == 'nw': # north-west
-            data['position']['x'] = 0.0
-            data['position']['y'] = 0.0
-        elif buttonName == 'ne': # north-east
-            data['position']['x'] = 1.0
-            data['position']['y'] = 0.0
-        elif buttonName == 'se': # south-east
-            data['position']['x'] = 1.0
-            data['position']['y'] = 1.0
-        elif buttonName == 'sw': # south-west
-            data['position']['x'] = 0.0
-            data['position']['y'] = 1.0
-        if type == 'view':    
-            self.PostViewEvent(zExag = True)
-            
-            self.UpdateSettings()
-        else:
-            self.PostLightEvent()
-            lightWin = self.FindWindowById(self.win['light']['position'])
-            x, y = lightWin.UpdatePos(self.mapWindow.light['position']['x'],
-                                     self.mapWindow.light['position']['y'])
-            lightWin.Draw(pos = (x, y), scale = True)
-            lightWin.Refresh(False)
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-
-    def OnMapObjUse(self, event):
-        """!Set surface attribute -- use -- map/constant"""
-        if not self.mapWindow.init:
-            return
-        
-        wx.Yield()
-        
-        # find attribute row
-        attrb = self.__GetWindowName(self.win['surface'], event.GetId())
-        if not attrb:
-            attrb = self.__GetWindowName(self.win['volume'], event.GetId())
-            nvizType = 'volume'
-        else:
-            nvizType = 'surface'
-        
-        selection = event.GetSelection()
-        if self.win[nvizType][attrb]['required']: # no 'unset'
-            selection += 1
-        if selection == 0: # unset
-            useMap = None
-            value = ''
-        elif selection == 1: # map
-            useMap = True
-            value = self.FindWindowById(self.win[nvizType][attrb]['map']).GetValue()
-        elif selection == 2: # constant
-            useMap = False
-            if attrb == 'color':
-                value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetColour()
-                value = self._getColorString(value)
-            else:
-                value = self._getPercent(self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue(), toPercent = False)
-        
-        self.SetMapObjUseMap(nvizType = nvizType,
-                             attrb = attrb, map = useMap)
-        
-        name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
-        if nvizType == 'surface':
-            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
-            data[nvizType]['attribute'][attrb] = { 'map' : useMap,
-                                                   'value' : str(value),
-                                                   'update' : None }
-        else: # volume / isosurface
-            data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
-            list = self.FindWindowById(self.win['volume']['isosurfs'])
-            id = list.GetSelection()
-            if id != -1:
-                data[nvizType]['isosurface'][id][attrb] = { 'map' : useMap,
-                                                            'value' : str(value),
-                                                            'update' : None }
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
- 
-    def EnablePage(self, name, enabled = True):
-        """!Enable/disable all widgets on page"""
-        for key, item in self.win[name].iteritems():
-            if key in ('map', 'surface', 'new','planes'):
-                continue
-            if type(item) == types.DictType:
-                for skey, sitem in self.win[name][key].iteritems():
-                    if type(sitem) == types.DictType:
-                        for ssitem in self.win[name][key][skey].itervalues():
-                            if type(ssitem) == types.IntType:
-                                self.FindWindowById(ssitem).Enable(enabled)
-                    else:
-                        if type(sitem) == types.IntType:
-                            self.FindWindowById(sitem).Enable(enabled)
-            else:
-                if type(item) == types.IntType:
-                    self.FindWindowById(item).Enable(enabled)
-        
-    def SetMapObjUseMap(self, nvizType, attrb, map = None):
-        """!Update dialog widgets when attribute type changed"""
-        if attrb in ('topo', 'color', 'shine'):
-            incSel = -1 # decrement selection (no 'unset')
-        else:
-            incSel = 0
-        if nvizType == 'volume' and attrb == 'topo':
-            return
-        if map is True: # map
-            if attrb != 'topo': # changing map topography not allowed
-                # not sure why, but here must be disabled both ids, should be fixed!
-                self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(True)
-            if self.win[nvizType][attrb]['const']:
-                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(False)
-            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(1 + incSel)
-        elif map is False: # const
-            self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(False)
-            if self.win[nvizType][attrb]['const']:
-                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(True)
-            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(2 + incSel)
-        else: # unset
-            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(0)
-            self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(False)
-            if self.win[nvizType][attrb]['const']:
-                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(False)
-            
-        
-    def OnSurfaceMap(self, event):
-        """!Set surface attribute"""
-        if self.vetoGSelectEvt:
-            self.vetoGSelectEvt = False
-            return
-        self.SetMapObjAttrb(nvizType = 'surface', winId = event.GetId())
-        
-    def SetMapObjAttrb(self, nvizType, winId):
-        """!Set map object (surface/isosurface) attribute (map/constant)"""
-        if not self.mapWindow.init:
-            return
-        
-        attrb = self.__GetWindowName(self.win[nvizType], winId)
-        if not attrb:
-            return
-        
-        if not (nvizType == 'volume' and attrb == 'topo'):
-            selection = self.FindWindowById(self.win[nvizType][attrb]['use']).GetSelection()
-            if self.win[nvizType][attrb]['required']:
-                selection += 1
-
-            if selection == 0: # unset
-                useMap = None
-                value = ''
-            elif selection == 1: # map
-                value = self.FindWindowById(self.win[nvizType][attrb]['map']).GetValue()
-                useMap = True
-            else: # constant
-                if attrb == 'color':
-                    value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetColour()
-                    # tuple to string
-                    value = self._getColorString(value)
-                else:
-                    value = self._getPercent(
-                        self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue(), toPercent = False)
-                    
-                useMap = False
-        else:
-            useMap = None
-            value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue()
-        if not self.pageChanging:
-            name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
-            if nvizType == 'surface':
-                data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
-                data[nvizType]['attribute'][attrb] = { 'map' : useMap,
-                                                       'value' : str(value),
-                                                       'update' : None }
-            else:
-                data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
-                list = self.FindWindowById(self.win['volume']['isosurfs'])
-                id = list.GetSelection()
-                if id > -1:
-                    data[nvizType]['isosurface'][id][attrb] = { 'map' : useMap,
-                                                                'value' : str(value),
-                                                                'update' : None }
-                    if attrb == 'topo':
-                        list = self.FindWindowById(self.win['volume']['isosurfs'])
-                        sel = list.GetSelection()
-                        list.SetString(sel, "%s %s" % (_("Level"), str(value)))
-                        list.Check(sel)
-            
-            # update properties
-            event = wxUpdateProperties(data = data)
-            wx.PostEvent(self.mapWindow, event)
-            
-            if self.mapDisplay.IsAutoRendered():
-                self.mapWindow.Refresh(False)
-        
-    def OnSurfaceResolution(self, event):
-        """!Draw resolution changed"""
-        self.SetSurfaceResolution()
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-    
-
-    def SetSurfaceResolution(self):
-        """!Set draw resolution"""
-        coarse = self.FindWindowById(self.win['surface']['draw']['res-coarse']).GetValue()
-        fine = self.FindWindowById(self.win['surface']['draw']['res-fine']).GetValue()
-        
-        data = self.GetLayerData('surface')
-        data['surface']['draw']['resolution'] = { 'coarse' : coarse,
-                                                  'fine' : fine,
-                                                  'update' : None }
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-    def SetSurfaceMode(self):
-        """!Set draw mode"""
-        mode = self.FindWindowById(self.win['surface']['draw']['mode']).GetSelection()
-        style = self.FindWindowById(self.win['surface']['draw']['style']).GetSelection()
-        if style == 0: # wire
-            self.FindWindowById(self.win['surface']['draw']['wire-color']).Enable(True)
-        elif style == 1: # surface
-            self.FindWindowById(self.win['surface']['draw']['wire-color']).Enable(False)
-        
-        shade = self.FindWindowById(self.win['surface']['draw']['shading']).GetSelection()
-        
-        value, desc = self.mapWindow.nvizDefault.GetDrawMode(mode, style, shade)
-        
-        return value, desc
-
-    def OnSurfaceMode(self, event):
-        """!Set draw mode"""
-        value, desc = self.SetSurfaceMode()
-        
-        data = self.GetLayerData('surface')
-        data['surface']['draw']['mode'] = { 'value' : value,
-                                            'desc' : desc,
-                                            'update' : None }
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-
-    def OnSurfaceModeAll(self, event):
-        """!Set draw mode (including wire color) for all loaded surfaces"""
-        value, desc = self.SetSurfaceMode()
-        coarse = self.FindWindowById(self.win['surface']['draw']['res-coarse']).GetValue()
-        fine = self.FindWindowById(self.win['surface']['draw']['res-fine']).GetValue()
-        color = self.FindWindowById(self.win['surface']['draw']['wire-color']).GetColour()
-        cvalue = self._getColorString(color)
-        
-        for name in self.mapWindow.GetLayerNames(type = 'raster'):
-            
-            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
-            if not data:
-                continue # shouldy no happen
-            
-            data['surface']['draw']['all'] = True
-            data['surface']['draw']['mode'] = { 'value' : value,
-                                                'desc' : desc,
-                                                'update' : None }
-            data['surface']['draw']['resolution'] = { 'coarse' : coarse,
-                                                      'fine' : fine,
-                                                      'update' : None }
-            data['surface']['draw']['wire-color'] = { 'value' : cvalue,
-                                                      'update' : None }
-            
-            # update properties
-            event = wxUpdateProperties(data = data)
-            wx.PostEvent(self.mapWindow, event)
-            
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def _getColorString(self, color):
-        """!Convert color tuple to R:G:B format
-
-        @param color tuple
-        
-        @return string R:G:B
-        """
-        return str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
-    
-    def _getColorFromString(self, color, delim = ':'):
-        """!Convert color string (R:G:B) to wx.Color
-
-        @param color string
-        @param delim delimiter
-
-        @return wx.Color instance
-        """
-        return wx.Color(*map(int, color.split(delim)))
-    
-    def _get3dRange(self, name):
-        """!Gelper func for getting range of 3d map"""
-        ret = gcmd.RunCommand('r3.info', read = True, flags = 'r', map = name)
-        if ret:
-            range = []
-            for value in ret.strip('\n').split('\n'):
-                range.append(float(value.split('=')[1]))
-            return range
-        
-        return -1e6, 1e6
-    
-    def _getPercent(self, value, toPercent = True):
-        """!Convert values 0 - 255 to percents and vice versa"""
-        value = int(value)
-        if toPercent:
-            value = int(value/255. * 100)
-        else:
-            value = int(value/100. * 255)
-        return value
-    
-    def OnSurfaceWireColor(self, event):
-        """!Set wire color"""
-        data = self.GetLayerData('surface')
-        value = self._getColorString(event.GetValue())
-        data['surface']['draw']['wire-color'] = { 'value' : value,
-                                                  'update' : None }
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnSurfaceAxis(self, event):
-        """!Surface position, axis changed"""
-        data = self.GetLayerData('surface')
-        id = data['surface']['object']['id']
-        
-        axis = self.FindWindowById(self.win['surface']['position']['axis']).GetSelection()
-        slider = self.FindWindowById(self.win['surface']['position']['slider'])
-        text = self.FindWindowById(self.win['surface']['position']['text'])
-        xydim = self._display.GetLongDim()
-        zdim = self._display.GetZRange()
-        zdim = zdim[1] - zdim[0]
-        
-        x, y, z = self._display.GetSurfacePosition(id)
-        
-        if axis == 0: # x
-            slider.SetRange(-3 * xydim, 3 * xydim)
-            slider.SetValue(x)
-            text.SetValue(x)
-        elif axis == 1: # y
-            slider.SetRange(-3 * xydim, 3 * xydim)
-            slider.SetValue(y)
-            text.SetValue(y)
-        else: # z
-            slider.SetRange(-3 * zdim, 3 * zdim)
-            slider.SetValue(z)
-            text.SetValue(z)
-        
-    def OnSurfacePosition(self, event):
-        """!Surface position"""
-        winName = self.__GetWindowName(self.win['surface'], event.GetId())
-        if not winName:
-            return
-        axis = self.FindWindowById(self.win['surface']['position']['axis']).GetSelection()
-        
-        value = self.FindWindowById(event.GetId()).GetValue()
-        slider = self.FindWindowById(self.win['surface'][winName]['slider'])
-        self.AdjustSliderRange(slider = slider, value = value)
-        
-        for win in self.win['surface']['position'].itervalues():
-            if win in (self.win['surface']['position']['axis'],
-                       self.win['surface']['position']['reset']):
-                continue
-            else:
-                self.FindWindowById(win).SetValue(value)
-        
-        data = self.GetLayerData('surface')
-        id = data['surface']['object']['id']
-        x, y, z = self._display.GetSurfacePosition(id)
-        
-        if axis == 0: # x
-            x = value
-        elif axis == 1: # y
-            y = value
-        else: # z
-            z = value
-        
-        data['surface']['position']['x'] = x
-        data['surface']['position']['y'] = y
-        data['surface']['position']['z'] = z
-        data['surface']['position']['update'] = None
-        # update properties
-        
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        self.mapWindow.render['quick'] = True
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        #        self.UpdatePage('surface')
-        
-    def OnSurfacePositionChanged(self, event):
-        """!Surface position changed"""
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-
-    def OnSurfacePositionText(self, event):
-        """!Surface position changed by textctrl"""
-        self.OnSurfacePosition(event)
-        self.OnSurfacePositionChanged(None)
-        
-    def UpdateVectorShow(self, vecType, enabled):
-        """!Enable/disable lines/points widgets
-        
-        @param vecType vector type (lines, points)
-        """
-        if vecType != 'lines' and vecType != 'points':
-            return False
-        
-        for win in self.win['vector'][vecType].keys():
-            if win == 'show':
-                continue
-            if type(self.win['vector'][vecType][win]) == type({}):
-                for swin in self.win['vector'][vecType][win].keys():
-                    if enabled:
-                        self.FindWindowById(self.win['vector'][vecType][win][swin]).Enable(True)
-                    else:
-                        self.FindWindowById(self.win['vector'][vecType][win][swin]).Enable(False)
-            else:
-                if enabled:
-                    self.FindWindowById(self.win['vector'][vecType][win]).Enable(True)
-                else:
-                    self.FindWindowById(self.win['vector'][vecType][win]).Enable(False)
-        
-        return True
-    
-    def OnVectorShow(self, event):
-        """!Show vector lines/points"""
-        winId = event.GetId()
-        if winId == self.win['vector']['lines']['show']:
-            vecType = 'lines'
-            points = False
-        else: # points
-            vecType = 'points' 
-            points = True
-       
-        checked = event.IsChecked()
-        name = self.FindWindowById(self.win['vector']['map']).GetValue()
-        item = self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'item')
-        data = self.GetLayerData('vector')['vector']
-        
-        if checked:
-            self.mapWindow.LoadVector(item, points = points, append = False)
-        else:
-            self.mapWindow.UnloadVector(item, points = points, remove = False)
-        
-        self.UpdateVectorShow(vecType, checked)
-        
-        if checked:
-            try:
-                id = data[vecType]['object']['id']
-            except KeyError:
-                id = -1
-            
-            if id > 0:
-                self.mapWindow.SetMapObjProperties(item, id, vecType)
-                
-                # update properties
-                event = wxUpdateProperties(data = data)
-                wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-    
-    def OnVectorDisplay(self, event):
-        """!Display vector lines on surface/flat"""
-        rasters = self.mapWindow.GetLayerNames('raster')
-        if event.GetSelection() == 0: # surface
-            if len(rasters) < 1:
-                self.FindWindowById(self.win['vector']['lines']['surface']).Enable(False)
-                self.FindWindowById(self.win['vector']['lines']['flat']).SetSelection(1)
-                return
-            
-            self.FindWindowById(self.win['vector']['lines']['surface']).Enable(True)
-            # set first found surface
-            data = self.GetLayerData('vector')
-            data['vector']['lines']['mode']['surface'] = rasters[0]
-            self.FindWindowById(self.win['vector']['lines']['surface']).SetStringSelection( \
-                rasters[0])
-        else: # flat
-            self.FindWindowById(self.win['vector']['lines']['surface']).Enable(False)
-        
-        self.OnVectorLines(event)
-        
-        event.Skip()
-
-    def OnVectorLines(self, event):
-        """!Set vector lines mode, apply changes if auto-rendering is enabled"""
-        data = self.GetLayerData('vector')
-        width = self.FindWindowById(self.win['vector']['lines']['width']).GetValue()
-        
-        mode = {}
-        if self.FindWindowById(self.win['vector']['lines']['flat']).GetSelection() == 0:
-            mode['type'] = 'surface'
-            mode['surface'] = {}
-            checklist = self.FindWindowById(self.win['vector']['lines']['surface'])
-            value = list()
-            checked = list()
-            for surface in range(checklist.GetCount()):
-                value.append(checklist.GetString(surface))
-                checked.append(checklist.IsChecked(surface))
-                    
-            mode['surface']['value'] = value
-            mode['surface']['show'] = checked
-        else:
-            mode['type'] = 'flat'
-        
-        for attrb in ('width', 'mode'):
-            data['vector']['lines'][attrb]['update'] = None
-        data['vector']['lines']['width']['value'] = width
-        data['vector']['lines']['mode'] = mode
-        
-        color = self.FindWindowById(self.win['vector']['lines']['color']).GetColour()
-        
-        if isinstance(color, csel.ColourSelect):
-            pass #color picker not yet instantiated
-        else:
-            color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
-            data['vector']['lines']['color']['update'] = None
-            data['vector']['lines']['color']['value'] = color
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-                        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnVectorHeight(self, event):
-        id = event.GetId()
-        if id in self.win['vector']['lines']['height'].values():
-            vtype = 'lines'
-        else:
-            vtype = 'points'
-        
-        value = self.FindWindowById(id).GetValue()
-        slider = self.FindWindowById(self.win['vector'][vtype]['height']['slider'])
-        self.AdjustSliderRange(slider = slider, value = value)
-        
-        for win in self.win['vector'][vtype]['height'].itervalues():
-            self.FindWindowById(win).SetValue(value)
-        
-        data = self.GetLayerData('vector')
-        data['vector'][vtype]['height'] = { 'value' : value,
-                                            'update' : None }
-        
-        # update properties
-        
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        self.mapWindow.render['quick'] = True
-        self.mapWindow.render['v' + vtype] = True
-        self.mapWindow.Refresh(False)
-        
-        event.Skip()
-    
-    def OnVectorHeightFull(self, event):
-        """!Vector height changed, render in full resolution"""
-        self.OnVectorHeight(event)
-##        self.OnVectorSurface(event)
-        id = event.GetId()
-        if id in self.win['vector']['lines']['height'].values():
-            vtype = 'lines'
-        else:
-            vtype = 'points'
-        
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.render['v' + vtype] = False
-        self.mapWindow.Refresh(False)
-
-    def OnVectorHeightText(self, event):
-        """!Vector height changed, render in full resolution"""
-        
-        #        self.OnVectorHeight(event)
-        self.OnVectorHeightFull(event)
-    
-    def OnVectorSurface(self, event):
-        """!Reference surface for vector map (lines/points)"""   
-        id = event.GetId()
-        if id == self.win['vector']['lines']['surface']:
-            vtype = 'lines'
-        else:
-            vtype = 'points'
-        checkList = self.FindWindowById(self.win['vector'][vtype]['surface'])
-        checked = []
-        surfaces = []
-        for items in range(checkList.GetCount()):
-            checked.append(checkList.IsChecked(items))
-            surfaces.append(checkList.GetString(items))
-        
-        data = self.GetLayerData('vector')
-        data['vector'][vtype]['mode']['surface'] = { 'value' : surfaces,
-                                                     'show'  : checked}
-        data['vector'][vtype]['mode']['update'] = None 
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-            
-        
-    def OnVectorPoints(self, event):
-        """!Set vector points mode, apply changes if auto-rendering is enabled"""
-        data = self.GetLayerData('vector')
-        
-        size  = self.FindWindowById(self.win['vector']['points']['size']).GetValue()
-        marker = self.FindWindowById(self.win['vector']['points']['marker']).GetSelection()
-        #        width = self.FindWindowById(self.win['vector']['points']['width']).GetValue()
-        
-        for attrb in ('size', 'marker'):
-            data['vector']['points'][attrb]['update'] = None
-        data['vector']['points']['size']['value'] = size
-        #        data['vector']['points']['width']['value'] = width
-        data['vector']['points']['marker']['value'] = marker
-        
-        color = self.FindWindowById(self.win['vector']['points']['color']).GetColour()
-        if isinstance(color, csel.ColourSelect):
-            pass #color picker not yet instantiated
-        else:
-            color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
-            data['vector']['points']['color']['update'] = None
-            data['vector']['points']['color']['value'] = color
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-
-    def OnCheckThematic(self, event):
-        """!Switch on/off thematic mapping"""
-        # can be called with no event to enable/disable button
-        if not event:
-            ids = (self.win['vector']['points']['thematic']['checkcolor'],
-                  self.win['vector']['lines']['thematic']['checkcolor'],
-                  self.win['vector']['points']['thematic']['checksize'],
-                  self.win['vector']['lines']['thematic']['checkwidth'])
-        else:
-            ids = (event.GetId(),)
-        for id in ids:
-            if id in self.win['vector']['points']['thematic'].values():
-                vtype = 'points'
-                if id == self.win['vector'][vtype]['thematic']['checkcolor']:
-                    attrType = 'color'
-                else:
-                    attrType = 'size'
-            else:
-                vtype = 'lines'
-                if id == self.win['vector'][vtype]['thematic']['checkcolor']:
-                    attrType = 'color'
-                else:
-                    attrType = 'width'
-                
-            check = self.win['vector'][vtype]['thematic']['check' + attrType]
-            button = self.win['vector'][vtype]['thematic']['button' + attrType]
-            if self.FindWindowById(check).GetValue():
-                checked = True
-            else:
-                checked = False
-            self.FindWindowById(button).Enable(checked)
-            
-            data = self.GetLayerData('vector')
-            
-            # decide if use GRASSRGB column
-            if attrType == 'color':
-                name = self.FindWindowById(self.win['vector']['map']).GetValue()
-                if not data['vector'][vtype]['thematic']['rgbcolumn']:
-                    try:
-                        id =  data['vector'][vtype]['object']['id']
-                    
-                        # if GRASSRGB exists and color table doesn't, use GRGB
-                        if self.HasGRASSRGB(name)  and \
-                            not self._display.CheckColorTable(id = id, type = vtype):
-                            data['vector'][vtype]['thematic']['rgbcolumn'] = 'GRASSRGB'
-                    except KeyError:
-                        pass
-                        
-            data['vector'][vtype]['thematic']['use' + attrType] = checked
-            data['vector'][vtype]['thematic']['update'] = None
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-            
-    def HasGRASSRGB(self, name):
-        """!Check if GRASSRGB column exist."""
-        column = False
-        
-        dbInfo = VectorDBInfo(name)
-        if len(dbInfo.layers):
-            table = dbInfo.layers[1]['table']
-            if 'GRASSRGB' in dbInfo.GetTableDesc(table):
-                column = True
-                
-        return column
-        
-    def OnSetThematic(self, event):
-        """!Set options for thematic points"""
-        if event.GetId() in self.win['vector']['points']['thematic'].values():
-            vtype = 'points'
-        else:
-            vtype = 'lines'
-        if event.GetId() == self.win['vector'][vtype]['thematic']['buttoncolor']:
-            attrType = 'color'
-        elif vtype == 'points':
-            attrType = 'size'
-        else:
-            attrType = 'width'
-        ctable = colorrules.ThematicVectorTable(self, vtype, attributeType = attrType)
-        ctable.CentreOnScreen()
-        ctable.Show()
-        
-    def UpdateIsosurfButtons(self, list):
-        """!Enable/disable buttons 'add', 'delete',
-        'move up', 'move down'"""
-        nitems = list.GetCount()
-        add = self.parent.FindWindowById(self.win['volume']['btnAdd'])
-        delete = self.parent.FindWindowById(self.win['volume']['btnDelete'])
-        moveDown = self.parent.FindWindowById(self.win['volume']['btnMoveDown'])
-        moveUp = self.parent.FindWindowById(self.win['volume']['btnMoveUp'])
-        if nitems >= wxnviz.MAX_ISOSURFS:
-            # disable add button on max
-            add.Enable(False)
-        else:
-            add.Enable(True)
-        
-        if nitems < 1:
-            # disable 'delete' if only one item in the lis
-            delete.Enable(False)
-        else:
-            delete.Enable(True)
-        
-        if list.GetSelection() >= nitems - 1:
-            # disable 'move-down' if last
-            moveDown.Enable(False)
-        else:
-            moveDown.Enable(True)
-        
-        if list.GetSelection() < 1:
-            # disable 'move-up' if first
-            moveUp.Enable(False)
-        else:
-            moveUp.Enable(True)
-            
-    def OnVolumeMode(self, event):
-        """!Change mode isosurfaces/slices"""
-        mode = self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection()
-        data = self.GetLayerData('volume')['volume']
-        
-        sizer = self.isoPanel.GetContainingSizer()
-        sizer = self.slicePanel.GetContainingSizer()
-        listBox = self.FindWindowByName('listStaticBox')
-        if mode == 0:
-            sizer.Show(self.isoPanel)
-            sizer.Hide(self.slicePanel)
-            listBox.SetLabel(" %s " % _("List of isosurfaces"))
-            data['draw']['mode']['value'] = 0
-            data['draw']['mode']['desc'] = 'isosurface'
-        else:
-            sizer.Hide(self.isoPanel)
-            sizer.Show(self.slicePanel)
-            listBox.SetLabel(" %s " % _("List of slices"))
-            data['draw']['mode']['value'] = 1
-            data['draw']['mode']['desc'] = 'slice'
-        
-        if event:
-            name = self.FindWindowById(self.win['volume']['map']).GetValue()
-            layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-            self.UpdateVolumePage(layer, data, updateName = False)
-            
-        sizer.Layout()
-        listBox.GetParent().Fit()
-            
-    def OnVolumeDrawMode(self, event):
-        """!Set isosurface/slice draw mode"""
-        self.SetVolumeDrawMode(event.GetSelection())
-        
-    def SetVolumeDrawMode(self, selection):
-        """!Set isosurface draw mode"""
-        data = self.GetLayerData('volume')['volume']
-        id = data['object']['id']
-        
-        mode = 0
-        if selection == 0:
-            mode |= wxnviz.DM_FLAT
-        else:
-            mode |= wxnviz.DM_GOURAUD
-            
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            self._display.SetIsosurfaceMode(id, mode)
-            data['draw']['shading']['isosurface']['desc'] = 'gouraud'
-            data['draw']['shading']['isosurface']['value'] = mode
-        else:
-            self._display.SetSliceMode(id, mode)
-            data['draw']['shading']['slice']['desc'] = 'flat'
-            data['draw']['shading']['slice']['value'] = mode
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnVolumeResolution(self, event):
-        """!Set isosurface/slice draw resolution"""
-        self.SetVolumeResolution(event.GetInt())
-        
-    def SetVolumeResolution(self, res):
-        """!Set isosurface draw resolution"""
-        data = self.GetLayerData('volume')['volume']
-        id = data['object']['id']
-        
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            self._display.SetIsosurfaceRes(id, res)
-            data['draw']['resolution']['isosurface']['value'] = res
-        else:
-            self._display.SetSliceRes(id, res)
-            data['draw']['resolution']['slice']['value'] = res
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-    
-    def OnInOutMode(self, event):
-        """!Change isosurfaces mode inout"""
-        data = self.GetLayerData('volume')['volume']
-        id = data['object']['id']
-        isosurfId = self.FindWindowById(self.win['volume']['isosurfs']).GetSelection()
-        
-        ret = self._display.SetIsosurfaceInOut(id, isosurfId, event.GetInt())
-        if ret == 1:
-            data['isosurface'][isosurfId]['inout'] = event.GetInt()
-            
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-    
-        
-    def OnVolumeIsosurfMap(self, event):
-        """!Set surface attribute"""
-        if self.vetoGSelectEvt:
-            self.vetoGSelectEvt = False
-            return
-        self.SetMapObjAttrb(nvizType = 'volume', winId = event.GetId())
-        
-    def OnVolumeCheck(self, event):
-        """!Isosurface/slice checked (->load) or unchecked (->unload)"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-        index = event.GetSelection()
-        list = self.FindWindowById(self.win['volume'][mode + 's'])
-        
-        data = self.GetLayerData('volume')['volume']
-        vid = data['object']['id']
-        
-        id = event.GetSelection()
-        
-        if mode == 'isosurf':
-            if list.IsChecked(index):
-                if 'transp' in data['isosurface'][id] and\
-                    data['isosurface'][id]['transp']['map'] is not None:
-                    if data['isosurface'][id]['transp']['map']:
-                        map = True
-                        value = data['isosurface'][id]['transp']['value']
-                    elif data['isosurface'][id]['transp']['map'] is not None:
-                        map = False
-                        value = data['isosurface'][id]['transp']['value']
-                    self._display.SetIsosurfaceTransp(vid, id, map, value)
-                else:
-                    self._display.SetIsosurfaceTransp(vid, id, False, "0")
-            else:
-                # disable -> make transparent
-                self._display.SetIsosurfaceTransp(vid, id, False, "255")
-        else:
-            if list.IsChecked(index):
-                value = data['slice'][id]['transp']['value']
-                self._display.SetSliceTransp(vid, id, value)
-            else:
-                # disable -> make transparent
-                self._display.SetSliceTransp(vid, id, 255)
-                
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnVolumeSelect(self, event):
-        """!Isosurface/Slice item selected"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-            
-        winUp = self.FindWindowById(self.win['volume']['btnMoveUp'])
-        winDown = self.FindWindowById(self.win['volume']['btnMoveDown'])
-        selection = event.GetSelection()
-        if selection == -1:
-            return
-        elif selection == 0:
-            winUp.Enable(False)
-            if not winDown.IsEnabled():
-                winDown.Enable()
-        elif selection == self.FindWindowById(event.GetId()).GetCount() - 1:
-            winDown.Enable(False)
-            if not winUp.IsEnabled():
-                winUp.Enable()
-        else:
-            if not winDown.IsEnabled():
-                winDown.Enable()
-            if not winUp.IsEnabled():
-                winUp.Enable()
-        
-        # update dialog
-        name = self.FindWindowById(self.win['volume']['map']).GetValue()
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        
-        if mode == 'isosurf':
-            data = self.GetLayerData('volume')['volume']['isosurface'][selection]
-            self.UpdateVolumeIsosurfPage(data)
-        else:
-            data = self.GetLayerData('volume')['volume']['slice'][selection]
-            self.UpdateVolumeSlicePage(data)
-        
-        
-        
-    def OnVolumeAdd(self, event):
-        """!Add new isosurface/slice to the list"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-        list = self.FindWindowById(self.win['volume'][mode + 's'])
-        
-        name = self.FindWindowById(self.win['volume']['map']).GetValue()
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        data = self.GetLayerData('volume')['volume']
-        id = data['object']['id']
-        
-        sel = list.GetSelection()
-        if mode == 'isosurf':
-            isosurfData = self.mapWindow.nvizDefault.SetIsosurfaceDefaultProp()
-            if isosurfData['color']['map']:
-                isosurfData['color']['value'] = layer.name
-
-            level = isosurfData['topo']['value'] = round(self._get3dRange(name = layer.name)[0], 2)
-        
-            if sel < 0 or sel >= list.GetCount() - 1:
-                item = list.Append(item = "%s %s" % (_("Level"), str(level)))
-            else:
-                list.Insert(item = "%s %s" % (_("Level"), str(level)),
-                            pos = sel+1) # append
-                item = sel + 1
-        else:
-            sliceData = self.mapWindow.nvizDefault.SetSliceDefaultProp()
-            axis = ("X", "Y", "Z")[sliceData['position']['axis']]
-            if sel < 0 or sel >= list.GetCount() - 1:
-                item = list.Append(item = "%s %s" % (_("Slice parallel to"), axis))
-            else:
-                list.Insert(item = "%s" % (_("Slice parallel to"), axis),
-                            pos = sel+1) # append
-                item = sel + 1
-        
-        list.Check(item)
-        list.SetSelection(item)
-        
-        if mode == 'isosurf':
-            data['isosurface'].insert(item, isosurfData)
-            # add isosurface        
-            self._display.AddIsosurface(id, float(level))
-        else:
-            data['slice'].insert(item, sliceData)
-            # add isosurface        
-            nslice = self._display.AddSlice(id)
-            self._display.SetSlicePosition(id, nslice -1, sliceData['position']['x1'], sliceData['position']['x2'],
-                                               sliceData['position']['y1'], sliceData['position']['y2'],
-                                               sliceData['position']['z1'], sliceData['position']['z2'],
-                                               sliceData['position']['axis'])
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        # update buttons
-        self.UpdateIsosurfButtons(list)
-        if mode == 'isosurf':
-            self.UpdateVolumeIsosurfPage(isosurfData)
-        else:
-            self.UpdateVolumeSlicePage(sliceData)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-        
-    def OnVolumeDelete(self, event):
-        """!Remove isosurface/slice from list"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-        list = self.FindWindowById(self.win['volume'][mode + 's'])
-        
-        # remove item from list
-        id = list.GetSelection()
-        list.Delete(id)
-        # select last item
-        if list.GetCount() > 0:
-            list.SetSelection(list.GetCount()-1)
-        
-        name = self.FindWindowById(self.win['volume']['map']).GetValue()
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        data = self.GetLayerData('volume')['volume']
-
-        vid = data['object']['id']
-        
-        # delete isosurface
-        if mode == 'isosurf':
-            del data['isosurface'][id]
-            self._display.DeleteIsosurface(vid, id)
-        else:
-            del data['slice'][id]
-            self._display.DeleteSlice(vid, id)
-        
-        # update buttons
-        if list.GetCount() > 0:
-            if mode == 'isosurf':
-                self.UpdateVolumeIsosurfPage(data['isosurface'][list.GetSelection()])
-            else:
-                self.UpdateVolumeSlicePage(data['slice'][list.GetSelection()])
-        else:
-            if mode == 'isosurf':
-                self.UpdateVolumeIsosurfPage(data['attribute'])
-            else:
-                self.UpdateVolumeSlicePage(None)
-        self.UpdateIsosurfButtons(list)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-        
-    def OnVolumeMoveUp(self, event):
-        """!Move isosurface/slice up in the list"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-        list = self.FindWindowById(self.win['volume'][mode + 's'])
-        sel = list.GetSelection()
-        
-        if sel < 1:
-            return # this should not happen
-        
-        name = self.FindWindowById(self.win['volume']['map']).GetValue()
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        data = self.GetLayerData('volume')['volume']
-        
-        id = data['object']['id']
-        
-        # move item up
-        text = list.GetStringSelection()
-        list.Insert(item = text, pos = sel-1)
-        list.Check(sel-1)
-        list.SetSelection(sel-1)
-        list.Delete(sel+1)
-        if mode == 'isosurf':
-            data['isosurface'].insert(sel-1, data['isosurface'][sel])
-            del data['isosurface'][sel+1]
-            self._display.MoveIsosurface(id, sel, True)
-        else:
-            data['slice'].insert(sel-1, data['slice'][sel])
-            del data['slice'][sel+1]
-            self._display.MoveSlice(id, sel, True)
-        
-        # update buttons
-        self.UpdateIsosurfButtons(list)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-        
-    def OnVolumeMoveDown(self, event):
-        """!Move isosurface/slice down in the list"""
-        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
-            mode = 'isosurf'
-        else:
-            mode = 'slice'
-        list = self.FindWindowById(self.win['volume'][mode + 's'])
-        sel = list.GetSelection()
-        
-        if sel >= list.GetCount() - 1:
-            return # this should not happen
-        
-        name = self.FindWindowById(self.win['volume']['map']).GetValue()
-        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-        data = self.GetLayerData('volume')['volume']
-        
-        id = data['object']['id']
-        
-        # move item up
-        text = list.GetStringSelection()
-        list.Insert(item = text, pos = sel+2)
-        list.Check(sel+2)
-        list.SetSelection(sel+2)
-        list.Delete(sel)
-        if mode == 'isosurf':
-            data['isosurface'].insert(sel+2, data['isosurface'][sel])
-            del data['isosurface'][sel]
-            self._display.MoveIsosurface(id, sel, False)
-        else:
-            data['slice'].insert(sel+2, data['slice'][sel])
-            del data['slice'][sel]
-            self._display.MoveSlice(id, sel, False)
-        
-        # update buttons
-        self.UpdateIsosurfButtons(list)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-        event.Skip()
-    
-    def OnVolumePositionChanged(self, event):
-        """!Volume position changed"""
-        self.mapWindow.render['quick'] = False
-        self.mapWindow.Refresh(False)
-        
-    def OnVolumePosition(self, event):
-        """!Volume position"""
-        winName = self.__GetWindowName(self.win['volume'], event.GetId())
-        if not winName:
-            return
-        axis = self.FindWindowById(self.win['volume']['position']['axis']).GetSelection()
-        
-        value = self.FindWindowById(event.GetId()).GetValue()
-        slider = self.FindWindowById(self.win['volume'][winName]['slider'])
-        self.AdjustSliderRange(slider = slider, value = value)
-        
-        for win in self.win['volume']['position'].itervalues():
-            if win in (self.win['volume']['position']['axis'],
-                       self.win['volume']['position']['reset']):
-                continue
-            else:
-                self.FindWindowById(win).SetValue(value)
-        
-        data = self.GetLayerData('volume')
-        id = data['volume']['object']['id']
-        x, y, z = self._display.GetVolumePosition(id)
-        
-        if axis == 0: # x
-            x = value
-        elif axis == 1: # y
-            y = value
-        else: # z
-            z = value
-        
-        data['volume']['position']['x'] = x
-        data['volume']['position']['y'] = y
-        data['volume']['position']['z'] = z
-        data['volume']['position']['update'] = None
-        # update properties
-        
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        self.mapWindow.render['quick'] = True
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnVolumeAxis(self, event):
-        """!Volume position, axis changed"""
-        data = self.GetLayerData('volume')
-        id = data['volume']['object']['id']
-        
-        axis = self.FindWindowById(self.win['volume']['position']['axis']).GetSelection()
-        slider = self.FindWindowById(self.win['volume']['position']['slider'])
-        text = self.FindWindowById(self.win['volume']['position']['text'])
-        xydim = self._display.GetLongDim()
-        zdim = self._display.GetZRange()
-        zdim = zdim[1] - zdim[0]
-        x, y, z = self._display.GetVolumePosition(id)
-        
-        if axis == 0: # x
-            slider.SetRange(-3 * xydim, 3 * xydim)
-            slider.SetValue(x)
-            text.SetValue(x)
-        elif axis == 1: # y
-            slider.SetRange(-3 * xydim, 3 * xydim)
-            slider.SetValue(y)
-            text.SetValue(y)
-        else: # z
-            slider.SetRange(-3 * zdim, 3 * zdim)
-            slider.SetValue(z)
-            text.SetValue(z)
-            
-    def OnVolumePositionText(self, event):
-        """!Volume position changed by textctrl"""
-        self.OnVolumePosition(event)
-        self.OnVolumePositionChanged(None)
-        
-    def OnResetVolumePosition(self, event):
-        """!Reset position of volume"""
-        for win in self.win['volume']['position'].itervalues():
-            if win == self.win['volume']['position']['axis']:
-                self.FindWindowById(win).SetSelection(0)
-            elif win == self.win['volume']['position']['reset']:
-                continue
-            else:
-                self.FindWindowById(win).SetValue(0)
-                
-        data = self.GetLayerData('volume')
-        data['volume']['position']['x'] = 0
-        data['volume']['position']['y'] = 0
-        data['volume']['position']['z'] = 0
-        data['volume']['position']['update'] = None
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnVolumeSliceAxes(self, event):
-        """!Slice axis changed"""
-        self.UpdateSliceLabels()
-        data = self.GetLayerData('volume')
-        list = self.FindWindowById(self.win['volume']['slices'])
-        sel = list.GetSelection()
-        if sel < 0:
-            return
-        axis = self.FindWindowById(self.win['volume']['slice']['axes']).GetSelection()
-        data['volume']['slice'][sel]['position']['axis'] = axis
-        data['volume']['slice'][sel]['position']['update'] = None
-        
-        axis = ("X", "Y", "Z")[axis]
-        list.SetString(sel, "%s %s" % (_("Slice parallel to"), axis))
-        list.Check(sel)
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event) 
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-    
-    def OnSliceTransparency(self, event):
-        """!Slice transparency changed"""
-        data = self.GetLayerData('volume')
-        
-        list = self.FindWindowById(self.win['volume']['slices'])
-        sel = list.GetSelection()
-        if sel < 0:
-            return
-        
-        val = self.FindWindowById(self.win['volume']['slice']['transp']).GetValue()
-        data['volume']['slice'][sel]['transp']['value'] = self._getPercent(val, toPercent = False)
-        data['volume']['slice'][sel]['transp']['update'] = None
-        
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnSliceReset(self, event):
-        """!Slice position reset"""
-        data = self.GetLayerData('volume')
-        
-        list = self.FindWindowById(self.win['volume']['slices'])
-        sel = list.GetSelection()
-        if sel < 0:
-            return
-        
-        for coord, val in zip(('x1', 'x2', 'y1', 'y2', 'z1', 'z2'),(0, 1, 0, 1, 0, 1, 0)):
-            data['volume']['slice'][sel]['position'][coord] = val
-        data['volume']['slice'][sel]['position']['update'] = None
-        
-        self.UpdateVolumeSlicePage(data['volume']['slice'][sel])
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        
-    def OnSlicePositionChange(self, event):
-        """!Slice position is changing"""
-        data = self.GetLayerData('volume')
-        list = self.FindWindowById(self.win['volume']['slices'])
-        sel = list.GetSelection()
-        if sel < 0:
-            return
-        win = self.win['volume']['slice']
-        winId = event.GetId()
-        value = event.GetInt()/100.
-        
-        for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
-            if win['slider_' + coord] == winId:
-                data['volume']['slice'][sel]['position'][coord] = value
-                data['volume']['slice'][sel]['position']['update'] = None
-                break
-        self.mapWindow.render['quick'] = True
-        # update properties
-        event = wxUpdateProperties(data = data)
-        wx.PostEvent(self.mapWindow, event) 
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-               
-    def OnSlicePositionChanged(self, event):
-        """!Slice position is changed"""
-        self.mapWindow.render['quick'] = False
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-                
-    def OnCPlaneSelection(self, event):
-        """!Cutting plane selected"""
-        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
-        try:
-            planeIndex = int(plane.split()[-1]) - 1
-            self.EnablePage("cplane", enabled = True)
-        except:
-            planeIndex = -1
-            self.EnablePage("cplane", enabled = False)
-        self.mapWindow.SelectCPlane(planeIndex)
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-        self.UpdateCPlanePage(planeIndex)
-        
-    def OnCPlaneChanging(self, event):
-        """!Cutting plane is changing"""
-        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
-        try:
-            planeIndex = int(plane.split()[-1]) - 1
-        except:#TODO disabled page
-            planeIndex = -1
-    
-        if event.GetId() in (self.win['cplane']['rotation']['rot'].values() +
-                            self.win['cplane']['rotation']['tilt'].values()):
-            action = 'rotation'
-        else:
-            action = 'position'
-        data = self.mapWindow.cplanes[planeIndex][action]
-        self.OnScroll(event, self.win['cplane'][action], data)
-        
-        self.mapWindow.render['quick'] = True
-        event = wxUpdateCPlane(update = (action,), current = planeIndex)
-        wx.PostEvent(self.mapWindow, event)
-        
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-
-    def OnCPlaneChangeDone(self, event):
-        """!Cutting plane change done"""
-        self.mapWindow.render['quick'] = False
-        if self.mapDisplay.IsAutoRendered():
-            self.mapWindow.Refresh(False)
-            
-    def OnCPlaneChangeText(self, event):
-        """!Cutting plane changed by textctrl"""
-        for axis in ('x', 'y', 'z'):
-            if event.GetId() == self.win['cplane']['position'][axis]['text']:
-                value = self.FindWindowById(event.GetId()).GetValue()
-                slider = self.FindWindowById(self.win['cplane']['position'][axis]['slider'])
-                self.AdjustSliderRange(slider = slider, value = value)
-        self.OnCPlaneChanging(event = event)
-        self.OnCPlaneChangeDone(None)   
-        
-    def OnCPlaneShading(self, event):
-        """!Cutting plane shading changed"""
-        shading = self.FindWindowById(self.win['cplane']['shading']).GetSelection()
-        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
-        try:
-            planeIndex = int(plane.split()[-1]) - 1
-        except:#TODO disabled page
-            planeIndex = -1
-            
-        self.mapWindow.cplanes[planeIndex]['shading'] = shading
-        
-        event = wxUpdateCPlane(update = ('shading',), current = planeIndex)
-        wx.PostEvent(self.mapWindow, event)
-        
-        self.OnCPlaneChangeDone(None)
-        
-    def OnCPlaneReset(self, event):
-        """!Reset current cutting plane"""
-        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
-        try:
-            planeIndex = int(plane.split()[-1]) - 1
-        except:#TODO disabled page
-            planeIndex = -1
-        self.mapWindow.cplanes[planeIndex] = copy.deepcopy(UserSettings.Get(group = 'nviz',
-                                                                            key = 'cplane'))
-        event = wxUpdateCPlane(update = ('position','rotation','shading'), current = planeIndex)
-        wx.PostEvent(self.mapWindow, event)
-        self.OnCPlaneChangeDone(None)
-        self.UpdateCPlanePage(planeIndex)
-    
-    def OnDecorationPlacement(self, event):
-        """!Place an arrow/scalebar by clicking on display"""
-        if event.GetId() == self.win['decoration']['arrow']['place']:
-            type = 'arrow'
-        elif event.GetId() == self.win['decoration']['scalebar']['place']:
-            type = 'scalebar'
-        else: return
-        
-        if event.GetInt():
-            self.mapDisplay.Raise()
-            self.mapWindow.mouse['use'] = type
-            self.mapWindow.SetCursor(self.mapWindow.cursors["cross"])
-        else:
-            self.mapWindow.mouse['use'] = 'default'
-            self.mapWindow.SetCursor(self.mapWindow.cursors["default"])
-    
-    def OnArrowDelete(self, event):
-        """!Delete arrow"""
-        self._display.DeleteArrow()
-        self.mapWindow.decoration['arrow']['show'] = False
-        self.mapWindow.Refresh(False)
-    
-    def OnScalebarDelete(self, event):
-        """!Delete scalebar"""
-        try:
-            id = self.mapWindow.decoration['scalebar'][-1]['id']
-        except IndexError:
-            return
-        self._display.DeleteScalebar(id = id)
-        del self.mapWindow.decoration['scalebar'][-1]
-        
-        self.mapWindow.Refresh(False)   
-         
-    def OnDecorationProp(self, event):
-        """!Set arrow/scalebar properties"""
-        if event.GetId() in self.win['decoration']['arrow'].values():
-            type = 'arrow'
-        elif event.GetId() in self.win['decoration']['scalebar'].values():
-            type = 'scalebar'
-        else: return
-        
-        color = self.FindWindowById(self.win['decoration'][type]['color']).GetValue()
-        size = self.FindWindowById(self.win['decoration'][type]['size']).GetValue()
-        if type == 'arrow':
-            self.mapWindow.decoration[type]['color'] = self._getColorString(color)
-            self.mapWindow.decoration[type]['size'] = size
-        elif type == 'scalebar'and self.mapWindow.decoration['scalebar']:
-            self.mapWindow.decoration[type][-1]['color'] = self._getColorString(color)
-            self.mapWindow.decoration[type][-1]['size'] = size
-        
-        if type == 'arrow' and self.mapWindow.decoration['arrow']['show']:
-            self._display.SetArrow(self.mapWindow.decoration['arrow']['position']['x'],
-                                   self.mapWindow.decoration['arrow']['position']['y'],
-                                   self.mapWindow.decoration['arrow']['size'],
-                                   self.mapWindow.decoration['arrow']['color'])
-            self._display.DrawArrow()
-        elif type == 'scalebar' and self.mapWindow.decoration['scalebar']:
-            self._display.SetScalebar(self.mapWindow.decoration['scalebar'][-1]['id'],
-                                      self.mapWindow.decoration['scalebar'][-1]['position']['x'],
-                                      self.mapWindow.decoration['scalebar'][-1]['position']['y'],
-                                      self.mapWindow.decoration['scalebar'][-1]['size'],
-                                      self.mapWindow.decoration['scalebar'][-1]['color'])
-            self._display.DrawScalebar()
-            self.mapWindow.Refresh(False)
-        
-    def UpdatePage(self, pageId):
-        """!Update dialog (selected page)"""
-        self.pageChanging = True
-        Debug.msg(1, "NvizToolWindow.UpdatePage(): %s", pageId)
-        
-        if pageId == 'view':
-            self.SetPage('view')
-            hmin = self.mapWindow.iview['height']['min']
-            hmax = self.mapWindow.iview['height']['max']
-            hval = self.mapWindow.iview['height']['value']
-            zmin = self.mapWindow.view['z-exag']['min']
-            zmax = self.mapWindow.view['z-exag']['max']
-            zval = self.mapWindow.view['z-exag']['value']
-            
-            for control in ('slider','text'):
-                self.FindWindowById(self.win['view']['height'][control]).SetRange(
-                                                                        hmin,hmax)
-                self.FindWindowById(self.win['view']['z-exag'][control]).SetRange(
-                                                                        zmin, zmax) 
-                self.FindWindowById(self.win['view']['height'][control]).SetValue(hval)                                      
-                
-                self.FindWindowById(self.win['view']['z-exag'][control]).SetValue(zval)                                      
-        
-            self.FindWindowById(self.win['view']['background']['color']).SetColour(\
-                            self.mapWindow.view['background']['color'])
-                            
-            tval = self.mapWindow.view['twist']['value']
-            pval = self.mapWindow.view['persp']['value']
-            for control in ('slider','text'):
-                self.FindWindowById(self.win['view']['twist'][control]).SetValue(tval)                                      
-                
-                self.FindWindowById(self.win['view']['persp'][control]).SetValue(pval)
-            
-            
-        elif pageId in ('surface', 'vector', 'volume'):
-            name = self.FindWindowById(self.win[pageId]['map']).GetValue()
-            data = self.GetLayerData(pageId)
-            if data:
-                if pageId == 'surface':
-                    layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
-                    self.UpdateSurfacePage(layer, data['surface'])
-                elif pageId == 'vector':
-                    layer = self.mapWindow.GetLayerByName(name, mapType = 'vector')
-                    self.UpdateVectorPage(layer, data['vector'])
-                elif pageId == 'volume':
-                    layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
-                    self.UpdateVolumePage(layer, data['volume'])
-        elif pageId == 'light':
-            zval = self.mapWindow.light['position']['z']
-            bval = self.mapWindow.light['bright']
-            aval = self.mapWindow.light['ambient']
-            for control in ('slider','text'):
-                self.FindWindowById(self.win['light']['z'][control]).SetValue(zval)
-                self.FindWindowById(self.win['light']['bright'][control]).SetValue(bval)
-                self.FindWindowById(self.win['light']['ambient'][control]).SetValue(aval)
-            self.FindWindowById(self.win['light']['color']).SetColour(self.mapWindow.light['color'])
-            self.FindWindowById(self.win['light']['position']).PostDraw()
-        elif pageId == 'fringe':
-            win = self.FindWindowById(self.win['fringe']['map'])
-            win.SetValue(self.FindWindowById(self.win['surface']['map']).GetValue())
-        elif pageId == 'decoration':
-            win = self.FindWindowById(self.win['decoration']['arrow']['size'])
-            win.SetValue(self.mapWindow.decoration['arrow']['size'])
-            win = self.FindWindowById(self.win['decoration']['scalebar']['size'])
-            win.SetValue(self.mapWindow._getDecorationSize())
-        elif pageId == 'constant':
-            if self.mapWindow.constants:
-                surface = self.FindWindowById(self.win['constant']['surface'])
-                for item in self.mapWindow.constants:
-                    surface.Append(_("constant#") + str(item['constant']['object']['name']))
-                surface.SetSelection(0)
-                self.OnConstantSelection(None)
-                self.EnablePage('constant', True)
-        elif pageId == 'cplane':
-            count = self._display.GetCPlanesCount()
-            choices = [_("None"),]
-            for plane in range(count):
-                choices.append("%s %i" % (_("Plane"), plane+1))
-            self.FindWindowById(self.win['cplane']['planes']).SetItems(choices)
-            current = 0
-            for i, cplane in enumerate(self.mapWindow.cplanes):
-                if cplane['on']:
-                    current = i + 1
-            self.FindWindowById(self.win['cplane']['planes']).SetSelection(current)
-            
-            xyRange, zRange = self._display.GetXYRange(), self._display.GetZRange()
-            if xyRange > 0: # GTK warning
-                self.FindWindowById(self.win['cplane']['position']['x']['slider']).SetRange(
-                                                                    -xyRange/2., xyRange/2.)
-                self.FindWindowById(self.win['cplane']['position']['y']['slider']).SetRange(
-                                                                    -xyRange/2., xyRange/2.)
-            if zRange[0] - zRange[1] > 0:
-                self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetRange(zRange[0], zRange[1])
-            self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetValue(zRange[0])
-            self.FindWindowById(self.win['cplane']['position']['z']['text']).SetValue(zRange[0])
-            self.OnCPlaneSelection(None)
-            
-        elif pageId == 'animation':
-            self.UpdateAnimationPage()
-            
-        self.Update()
-        self.pageChanging = False
-        
-    def UpdateAnimationPage(self):
-        """!Update animation page"""
-        # wrap help text according to tool window
-        help = self.FindWindowById(self.win['anim']['help'])
-        width = help.GetGrandParent().GetSizeTuple()[0]
-        help.Wrap(width - 15)
-        anim = self.mapWindow.GetAnimation()
-        if anim.Exists():
-            self.FindWindowById(self.win['anim']['play']).Enable()
-        else:
-            self.UpdateFrameIndex(index = 0)
-            
-        self.UpdateFrameCount()
-        
-        self.FindWindowById(self.win['anim']['play']).Disable()
-        self.FindWindowById(self.win['anim']['record']).Enable()
-        self.FindWindowById(self.win['anim']['pause']).Disable()
-        self.FindWindowById(self.win['anim']['stop']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
-        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
-        
-    def UpdateCPlanePage(self, index):
-        """!Update widgets according to selected clip plane"""
-        if index == -1:   
-            return
-        data = self.mapWindow.cplanes[index]
-        for widget in ('text', 'slider'):
-            for axes in ('x', 'y', 'z'):
-                self.FindWindowById(self.win['cplane']['position'][axes][widget]).SetValue(data['position'][axes])
-            for each in ('tilt', 'rot'):
-                self.FindWindowById(self.win['cplane']['rotation'][each][widget]).SetValue(data['rotation'][each])
-        self.FindWindowById(self.win['cplane']['shading']).SetSelection(data['shading'])
-                
-    def UpdateSurfacePage(self, layer, data, updateName = True):
-        """!Update surface page"""
-        desc = grass.raster_info(layer.name)['title']
-        if updateName:
-            self.FindWindowById(self.win['surface']['map']).SetValue(layer.name)
-        self.FindWindowById(self.win['surface']['desc']).SetLabel(desc)
-        
-        # attributes
-        if layer and layer.type == 'raster':
-            self.vetoGSelectEvt = True
-            self.FindWindowById(self.win['surface']['color']['map']).SetValue(layer.name)
-        else:
-            self.FindWindowById(self.win['surface']['color']['map']).SetValue('')
-
-        self.SetMapObjUseMap(nvizType = 'surface',
-                             attrb = 'color', map = True) # -> map
-                                
-        if 'color' in data['attribute']:
-            value = data['attribute']['color']['value']
-
-            if data['attribute']['color']['map']:
-                self.FindWindowById(self.win['surface']['color']['map']).SetValue(value)
-            else: # constant
-                color = map(int, value.split(':'))
-                self.FindWindowById(self.win['surface']['color']['const']).SetColour(color)
-            self.SetMapObjUseMap(nvizType = 'surface',
-                                 attrb = 'color', map = data['attribute']['color']['map'])
-
-        self.SetMapObjUseMap(nvizType = 'surface',
-                             attrb = 'shine', map = data['attribute']['shine']['map'])
-        value = data['attribute']['shine']['value']
-        if data['attribute']['shine']['map']:
-            self.FindWindowById(self.win['surface']['shine']['map']).SetValue(value)
-        else:
-            self.FindWindowById(self.win['surface']['shine']['const']).SetValue(self._getPercent(value))
-        if 'transp' in data['attribute']:  
-            value = data['attribute']['transp']['value']  
-            if data['attribute']['transp']['map']:
-                self.FindWindowById(self.win['surface']['color']['map']).SetValue(value)
-            else:
-                self.FindWindowById(self.win['surface']['transp']['const']).SetValue(self._getPercent(value))
-            self.SetMapObjUseMap(nvizType = 'surface', attrb = 'transp', map = data['attribute']['transp']['map'])
-        else:
-            self.SetMapObjUseMap(nvizType = 'surface', attrb = 'transp', map = None)
-        #
-        # draw
-        #
-        for control, drawData in data['draw'].iteritems():
-            if control == 'all': # skip 'all' property
-                continue
-            if control == 'resolution':
-                self.FindWindowById(self.win['surface']['draw']['res-coarse']).SetValue(drawData['coarse'])
-                self.FindWindowById(self.win['surface']['draw']['res-fine']).SetValue(drawData['fine'])
-                continue
-            
-            if control == 'mode':
-                if drawData['desc']['mode'] == 'coarse':
-                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(0)
-                elif drawData['desc']['mode'] == 'fine':
-                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(1)
-                else: # both
-                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(2)
-                
-                if drawData['desc']['style'] == 'wire':
-                    self.FindWindowById(self.win['surface']['draw']['style']).SetSelection(0)
-                else: # surface
-                    self.FindWindowById(self.win['surface']['draw']['style']).SetSelection(1)
-                
-                if drawData['desc']['shading'] == 'flat':
-                    self.FindWindowById(self.win['surface']['draw']['shading']).SetSelection(0)
-                else: # gouraud
-                    self.FindWindowById(self.win['surface']['draw']['shading']).SetSelection(1)
-                
-                continue
-            
-            value = drawData['value']
-            win = self.FindWindowById(self.win['surface']['draw'][control])
-            
-            name = win.GetName()
-            
-            if name == "selection":
-                win.SetSelection(value)
-            elif name == "colour":
-                color = map(int, value.split(':'))
-                win.SetColour(color)
-            else:
-                win.SetValue(value)
-        #
-        # position
-        #
-        dim = self._display.GetLongDim()
-        self.FindWindowById(self.win['surface']['position']['slider']).SetRange(-2 * dim, 2 * dim)
-        if 'x' in data['position']:
-            xval = data['position']['x']
-            self.FindWindowById(self.win['surface']['position']['axis']).SetSelection(0)
-            for control in ('slider','text'):
-                    self.FindWindowById(self.win['surface']['position'][control]).SetValue(xval)
-        # enable/disable res widget + set draw mode
-        self.OnSurfaceMode(event = None)
-
-    def VectorInfo(self, layer):
-        """!Get number of points/lines
-        
-        @param layer MapLayer instance
-        
-        @return num of points/features (expect of points)
-        @return None
-        """
-        vInfo = grass.vector_info_topo(layer.GetName())
-        
-        if not vInfo:
-            return None
-        
-        nprimitives = 0
-        for key, value in vInfo.iteritems():
-            if key in ('points',
-                       'lines',
-                       'boundaries',
-                       'centroids',
-                       'faces',
-                       'kernels'):
-                nprimitives += value
-        
-        return (vInfo['points'], vInfo['lines'], nprimitives, vInfo['map3d'])
-        
-    def UpdateVectorPage(self, layer, data, updateName = True):
-        """!Update vector page"""
-        npoints, nlines, nfeatures, mapIs3D = self.VectorInfo(layer)
-        if mapIs3D:
-            desc = _("Vector map is 3D")
-            enable = False
-        else:
-            desc = _("Vector map is 2D")
-            enable = True
-        desc += " - " + _("%(features)d features (%(points)d points)") % \
-            { 'features' : nfeatures, 'points' : npoints }
-        
-        if updateName:
-            self.FindWindowById(self.win['vector']['map']).SetValue(layer.name)
-        self.FindWindowById(self.win['vector']['desc']).SetLabel(desc)
-        
-        self.FindWindowById(self.win['vector']['lines']['flat']).Enable(enable)
-        for v in ('lines', 'points'):
-            self.FindWindowById(self.win['vector'][v]['surface']).Enable(enable)
-            self.FindWindowById(self.win['vector'][v]['height']['slider']).Enable(enable)
-            self.FindWindowById(self.win['vector'][v]['height']['text']).Enable(enable)
-            
-            if data[v]['thematic']['usecolor']:
-                check = self.FindWindowById(self.win['vector'][v]['thematic']['checkcolor'])
-                check.SetValue(data[v]['thematic']['usecolor'])
-            if 'usesize' in data[v]['thematic'] and data[v]['thematic']['usesize']:
-                check = self.FindWindowById(self.win['vector'][v]['thematic']['checksize'])
-                check.SetValue(data[v]['thematic']['usesize'])
-            elif 'usewidth' in data[v]['thematic'] and data[v]['thematic']['usewidth']:
-                check = self.FindWindowById(self.win['vector'][v]['thematic']['checkwidth'])
-                check.SetValue(data[v]['thematic']['usewidth'])
-            self.OnCheckThematic(None)
-        #
-        # lines
-        #
-        showLines = self.FindWindowById(self.win['vector']['lines']['show'])
-        if 'object' in data['lines']:
-            showLines.SetValue(True)
-        else:
-            showLines.SetValue(False)
-            if nlines > 0:
-                showLines.Enable(True)
-            else:
-                showLines.Enable(False)
-        
-        self.UpdateVectorShow('lines',
-                              showLines.IsChecked())
-        
-        width = self.FindWindowById(self.win['vector']['lines']['width'])
-        width.SetValue(data['lines']['width']['value'])
-        
-        color = self.FindWindowById(self.win['vector']['lines']['color'])
-        color.SetValue(map(int, data['lines']['color']['value'].split(':')))
-        
-        for vtype in ('lines', 'points'):
-            if vtype == 'lines':
-                display = self.FindWindowById(self.win['vector']['lines']['flat'])
-                if data[vtype]['mode']['type'] == 'flat':
-                    display.SetSelection(1)
-                else:
-                    display.SetSelection(0)
-            if data[vtype]['mode']['type'] == 'surface':
-                rasters = self.mapWindow.GetLayerNames('raster')
-                constants = self.mapWindow.GetLayerNames('constant')
-                surfaces = rasters + constants
-                surfaceWin = self.FindWindowById(self.win['vector'][vtype]['surface'])
-                surfaceWin.SetItems(surfaces)
-                for idx, surface in enumerate(surfaces):
-                    try:# TODO fix this mess
-                        selected = data[vtype]['mode']['surface']['show'][idx]
-                    except (TypeError, IndexError, KeyError):
-                        selected = False
-                    surfaceWin.Check(idx, selected)
-
-        for type in ('slider', 'text'):
-            win = self.FindWindowById(self.win['vector']['lines']['height'][type])
-            win.SetValue(data['lines']['height']['value'])
-        
-        #
-        # points
-        #
-        showPoints = self.FindWindowById(self.win['vector']['points']['show'])
-        
-        if 'object' in data['points']:
-            showPoints.SetValue(True)
-        else:
-            showPoints.SetValue(False)
-            if npoints > 0:
-                showPoints.Enable(True)
-            else:
-                showPoints.Enable(False)
-        
-        self.UpdateVectorShow('points',
-                              showPoints.IsChecked())
-        # size, width, marker, color
-        for prop in ('size', 'marker', 'color'):
-            win = self.FindWindowById(self.win['vector']['points'][prop])
-            name = win.GetName()
-            if name == 'selection':
-                win.SetSelection(data['points'][prop]['value'])
-            elif name == 'color':
-                color = map(int, data['points'][prop]['value'].split(':'))
-                win.SetValue(color)
-            else:
-                win.SetValue(data['points'][prop]['value'])
-##        self.OnCheckThematic(None)
-        # height
-        for type in ('slider', 'text'):
-            win = self.FindWindowById(self.win['vector']['points']['height'][type])
-            win.SetValue(data['points']['height']['value'])
-        
-    def UpdateVolumePage(self, layer, data, updateName = True):
-        """!Update volume page"""
-        if updateName:
-            self.FindWindowById(self.win['volume']['map']).SetValue(layer.name)
-        
-        # draw
-        for control, idata in data['draw'].iteritems():
-            if control == 'all': # skip 'all' property
-                continue
-                
-            win = self.FindWindowById(self.win['volume']['draw'][control])
-            if control == 'mode':
-                value = data['draw']['mode']['value']
-            if control == 'shading':
-                if data['draw']['shading'][data['draw']['mode']['desc']]['desc'] == 'flat':
-                    value = 0
-                else:
-                    value = 1
-            if control == 'resolution':
-                value = idata[data['draw']['mode']['desc']]['value']
-            
-            if win.GetName() == "selection":
-                win.SetSelection(value)
-            else:
-                win.SetValue(value)
-                
-        self.OnVolumeMode(None)
-        id = data['object']['id']
-        if data['draw']['mode']['desc'] == 'isosurface':
-            self._display.SetIsosurfaceMode(id, data['draw']['shading']['isosurface']['value'])
-            self._display.SetIsosurfaceRes(id, data['draw']['resolution']['isosurface']['value'])
-        else:
-            self._display.SetSliceMode(id, data['draw']['shading']['slice']['value'])
-            self._display.SetSliceRes(id, data['draw']['resolution']['slice']['value'])
-        box = self.FindWindowById(self.win['volume']['isosurfs'])
-        
-        if data['draw']['mode']['desc'] == 'isosurface':
-            isosurfaces = []
-            for iso in data['isosurface']:
-                level = iso['topo']['value']
-                isosurfaces.append("%s %s" % (_("Level"), level))
-            box.Set(isosurfaces)
-            box.SetChecked(range(len(isosurfaces)))
-            if data['isosurface']:
-                box.SetSelection(0)
-                self.UpdateVolumeIsosurfPage(data['isosurface'][0])
-            else:
-                self.UpdateVolumeIsosurfPage(data['attribute'])
-        else:
-            slices = []
-            for slice in data['slice']:
-                axis = ("X", "Y", "Z")[slice['position']['axis']]
-                slices.append("%s %s" % (_("Slice parallel to"), axis))
-            box.Set(slices)
-            box.SetChecked(range(len(slices)))
-            if data['slice']:
-                box.SetSelection(0)
-                self.UpdateVolumeSlicePage(data['slice'][0])
-            else:
-                self.UpdateVolumeSlicePage(None)
-        #
-        # position
-        #
-        if 'x' in data['position']:
-            xval = data['position']['x']
-            self.FindWindowById(self.win['volume']['position']['axis']).SetSelection(0)
-            for control in ('slider','text'):
-                    self.FindWindowById(self.win['volume']['position'][control]).SetValue(xval)    
-        # set topo range
-        mapRange = self._get3dRange(name = layer.name)
-        desc = self.FindWindowById(self.win['volume']['desc'])
-        desc.SetLabel("%s %.2f - %.2f" % (_("range:"), mapRange[0], mapRange[1]))
-        
-    def UpdateVolumeIsosurfPage(self, data):
-        """!Update dialog -- isosurface attributes"""
-        #
-        # isosurface attributes
-        #
-        for attrb in ('topo', 'color', 'mask',
-                     'transp', 'shine'):
-            # skip empty attributes
-            if attrb not in data:
-                self.SetMapObjUseMap(nvizType = 'volume', attrb = attrb, map = None)
-                continue     
-            
-            value = data[attrb]['value']
-            if attrb == 'color':
-                if data[attrb]['map']:
-                    self.FindWindowById(self.win['volume'][attrb]['map']).SetValue(value)
-                else: # constant
-                    color = map(int, value.split(':'))
-                    self.FindWindowById(self.win['volume'][attrb]['const']).SetColour(color)
-            else:
-                if data[attrb]['map']:
-                    self.vetoGSelectEvt = True
-                    win = self.FindWindowById(self.win['volume'][attrb]['map'])
-                    win.SetValue(value)
-                else:
-                    if value:
-                        win = self.FindWindowById(self.win['volume'][attrb]['const'])
-                        if attrb == 'topo':
-                            win.SetValue(float(value))
-                        else:
-                            win.SetValue(self._getPercent(value))
-                    
-            self.SetMapObjUseMap(nvizType = 'volume',
-                                 attrb = attrb, map = data[attrb]['map'])
-        # set inout
-        if 'inout' in data:
-            self.FindWindowById(self.win['volume']['inout']).SetValue(data['inout'])
-            
-    def UpdateVolumeSlicePage(self, data):
-        """!Update dialog -- slice attributes"""
-        if data:
-            for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
-                win = self.FindWindowById(self.win['volume']['slice']['slider_' + coord])
-                win.Enable()
-                win.SetValue(data['position'][coord] * 100)
-            win = self.FindWindowById(self.win['volume']['slice']['axes'])
-            win.SetSelection(data['position']['axis'])
-            win.Enable()
-            
-            win = self.FindWindowById(self.win['volume']['slice']['transp'])
-            win.SetValue(self._getPercent(data['transp']['value']))
-            win.Enable()
-            self.FindWindowById(self.win['volume']['slice']['reset']).Enable()
-        else:
-            for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
-                self.FindWindowById(self.win['volume']['slice']['slider_' + coord]).Disable()
-            self.FindWindowById(self.win['volume']['slice']['axes']).Disable()
-            self.FindWindowById(self.win['volume']['slice']['transp']).Disable()
-            self.FindWindowById(self.win['volume']['slice']['reset']).Disable()
-        
-        self.UpdateSliceLabels()
-        
-    def UpdateSliceLabels(self):
-        """!Update text labels of slice controls according to axis"""
-        sel = self.FindWindowById(self.win['volume']['slice']['axes']).GetSelection()
-        if sel == 0:
-            self.FindWindowByName('label_edge_0').SetLabel(_("North edge:"))
-            self.FindWindowByName('label_edge_1').SetLabel(_("South edge:"))
-            self.FindWindowByName('label_edge_2').SetLabel(_("West edge:"))
-            self.FindWindowByName('label_edge_3').SetLabel(_("East edge:"))
-            
-            self.FindWindowByName('label_coord_0').SetLabel(_("Northing (Y):"))
-            self.FindWindowByName('label_coord_1').SetLabel(_("Height (Z):"))
-            self.FindWindowByName('label_coord_2').SetLabel(_("Easting (X):"))
-        elif sel == 1:
-            self.FindWindowByName('label_edge_0').SetLabel(_("West edge:"))
-            self.FindWindowByName('label_edge_1').SetLabel(_("East edge:"))
-            self.FindWindowByName('label_edge_2').SetLabel(_("North edge:"))
-            self.FindWindowByName('label_edge_3').SetLabel(_("South edge:"))
-            
-            self.FindWindowByName('label_coord_0').SetLabel(_("Easting (X):"))
-            self.FindWindowByName('label_coord_1').SetLabel(_("Height (Z):"))
-            self.FindWindowByName('label_coord_2').SetLabel(_("Northing (Y):"))
-        else:
-            self.FindWindowByName('label_edge_0').SetLabel(_("West edge:"))
-            self.FindWindowByName('label_edge_1').SetLabel(_("East edge:"))
-            self.FindWindowByName('label_edge_2').SetLabel(_("Bottom edge:"))
-            self.FindWindowByName('label_edge_3').SetLabel(_("Top edge:"))  
-            
-            self.FindWindowByName('label_coord_0').SetLabel(_("Easting (X):"))
-            self.FindWindowByName('label_coord_1').SetLabel(_("Northing (Y):"))
-            self.FindWindowByName('label_coord_2').SetLabel(_("Height (Z):")) 
-        
-    def SetPage(self, name):
-        """!Get named page"""
-        if name == 'view':
-            self.SetSelection(0)
-        elif name in ('surface', 'vector', 'volume'):
-            self.SetSelection(1)
-        else:
-            self.SetSelection(2)
-
-        win = self.FindWindowById(self.page[name]['notebook'])
-        try:
-            win.Expand(win.GetFoldPanel(self.page[name]['id']))
-            self.UpdateScrolling((win.GetFoldPanel(self.page[name]['id']).GetGrandParent(),))
-        except AttributeError:
-            win.SetSelection(self.page[name]['id'])
-
-class PositionWindow(wx.Window):
-    """!Abstract position control window, see subclasses
-    ViewPostionWindow and LightPositionWindow"""
-    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
-                 **kwargs):
-        self.mapWindow = mapwindow
-        self.quick = True
-        
-        wx.Window.__init__(self, parent, id, **kwargs)
-        
-        self.SetBackgroundColour("WHITE")
-        
-        self.pdc = wx.PseudoDC()
-        
-        self.pdc.SetBrush(wx.Brush(colour = 'dark green', style = wx.SOLID))
-        self.pdc.SetPen(wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID))
-
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        # self.Bind(wx.EVT_MOTION,       self.OnMouse)
-        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
-        
-    def Draw(self, pos, scale = False):
-        w, h = self.GetClientSize()
-        x, y = pos
-        if scale:
-            x = x * w
-            y = y * h
-        self.pdc.Clear()
-        self.pdc.BeginDrawing()
-        self.pdc.DrawLine(w / 2, h / 2, x, y)
-        self.pdc.DrawCircle(x, y, 5)
-        self.pdc.EndDrawing()
-        
-    def OnPaint(self, event):
-        dc = wx.BufferedPaintDC(self)
-        dc.SetBackground(wx.Brush("White"))
-        dc.Clear()
-        
-        self.PrepareDC(dc)
-        self.pdc.DrawToDC(dc)
-        
-    def UpdatePos(self, xcoord, ycoord):
-        """!Update position coordinates (origin: UL)"""
-        if xcoord < 0.0:
-            xcoord = 0.0
-        elif xcoord > 1.0:
-            xcoord = 1.0
-        if ycoord < 0.0:
-            ycoord = 0.0
-        elif ycoord > 1.0:
-            ycoord = 1.0
-        
-        x, y = self.TransformCoordinates(xcoord, ycoord)
-        self.data['position']['x'] = x        
-        self.data['position']['y'] = y
-        
-        return xcoord, ycoord
-    
-    def OnMouse(self, event):
-        if event.LeftIsDown():
-            x, y = event.GetPosition()
-            self.Draw(pos = (x, y))
-            w, h = self.GetClientSize()
-            x = float(x) / w
-            y = float(y) / h
-            self.UpdatePos(x, y)
-            self.Refresh(False)
-        
-        event.Skip()
-        
-    def PostDraw(self):
-        x, y = self.UpdatePos(self.data['position']['x'],
-                              self.data['position']['y'])
-        
-        self.Draw(pos = (x,y), scale = True)
-
-class ViewPositionWindow(PositionWindow):
-    """!View position control widget"""
-    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
-                 **kwargs):
-        PositionWindow.__init__(self, parent, mapwindow, id, **kwargs)
-
-        self.data = self.mapWindow.view
-        self.PostDraw()
-        
-    def UpdatePos(self, xcoord, ycoord):
-        x, y = PositionWindow.UpdatePos(self, xcoord, ycoord)
-        
-        event = wxUpdateView(zExag = True)
-        wx.PostEvent(self.mapWindow, event)
-
-        return x, y
-    
-    def TransformCoordinates(self, x, y, toLight = True):
-        return x, y
-        
-    def OnMouse(self, event):
-        self.mapWindow.iview['dir']['use'] = False # use focus instead of viewdir
-        PositionWindow.OnMouse(self, event)
-        if event.LeftIsDown():
-            self.mapWindow.render['quick'] = self.quick
-            self.mapWindow.Refresh(eraseBackground = False)
-        elif event.LeftUp():
-            self.mapWindow.render['quick'] = False
-            self.mapWindow.Refresh(eraseBackground = False)
-        
-        event.Skip()
-    
-class LightPositionWindow(PositionWindow):
-    """!Light position control widget"""
-    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
-                 **kwargs):
-        PositionWindow.__init__(self, parent, mapwindow, id, **kwargs)
-        
-        self.data = self.mapWindow.light
-        self.quick = False
-        self.PostDraw()
-
-    def UpdatePos(self, xcoord, ycoord):
-        x, y = PositionWindow.UpdatePos(self, xcoord, ycoord)
-        
-        event = wxUpdateLight(refresh = False)
-        wx.PostEvent(self.mapWindow, event)
-        
-        return x, y
-    
-    def TransformCoordinates(self, x, y, toLight = True):
-        if toLight:
-            x = 2 * x - 1
-            y = -2 * y + 1
-        else:
-            x = (x + 1)/2
-            y = (1 - y)/2
-        return x, y
-    
-    def PostDraw(self):
-        event = wxUpdateLight(refresh = True)
-        wx.PostEvent(self.mapWindow, event)
-        x, y = self.data['position']['x'], self.data['position']['y']
-        x, y = self.TransformCoordinates(x, y, toLight = False)
-        
-        self.Draw(pos = (x,y), scale = True)
-        
-    def OnMouse(self, event):
-        PositionWindow.OnMouse(self, event)
-        if event.LeftUp():
-            self.mapWindow.render['quick'] = False
-            self.mapWindow.Refresh(eraseBackground = False)

Deleted: grass/trunk/gui/wxpython/gui_modules/ogc_services.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/ogc_services.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/ogc_services.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,301 +0,0 @@
-"""!
- at package ogc_services.py
-
- at brief Dialogs for OGC services
-
-Currently only implemeted WMS.
-
-List of classes:
- - WMSDialog
- - LayersList
-
-(C) 2009 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import wx
-from wx.gizmos import TreeListCtrl
-import wx.lib.mixins.listctrl as listmix
-
-import gcmd
-
-from preferences import globalSettings as UserSettings
-
-class WMSDialog(wx.Dialog):
-    def __init__(self, parent, service = 'wms',
-                 id=wx.ID_ANY,
-                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        """!Dialog to import data from WMS server"""
-        self.parent  = parent  # GMFrame 
-        self.service = service # currently only WMS is implemented
-        
-        wx.Dialog.__init__(self, parent, id, style=style)
-        if self.service == 'wms':
-            self.SetTitle(_("Import data from WMS server"))
-            
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.__createWidgets()
-        
-        self.__doLayout()
-
-        self.SetMinSize((550, 400))
-        
-    def __createWidgets(self):
-        """!Create dialog widgets"""
-        #
-        # settings
-        #
-        self.settingsBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                        label = _(" Server settings "))
-
-        self.serverText = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = _("Server:"))
-        self.server  = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
-        
-        #
-        # list of layers
-        #
-        self.layersBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                label=_(" List of layers "))
-
-        self.list = LayersList(self.panel)
-        self.list.LoadData()
-
-        self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
-                               label=_("Add imported layers into layer tree"))
-        self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
-                
-        #
-        # buttons
-        #
-        # cancel
-        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
-        self.btn_cancel.SetToolTipString(_("Close dialog"))
-        # connect
-        self.btn_connect = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Connect"))
-        self.btn_connect.SetToolTipString(_("Connect to the server"))
-        self.btn_connect.SetDefault()
-        if not self.server.GetValue():
-            self.btn_connect.Enable(False)
-        # import
-        self.btn_import = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
-        self.btn_import.SetToolTipString(_("Import selected layers"))
-        self.btn_import.Enable(False)
-        
-        #
-        # bindings
-        #
-        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        self.btn_connect.Bind(wx.EVT_BUTTON, self.OnConnect)
-        self.server.Bind(wx.EVT_TEXT, self.OnServer)
-        
-    def __doLayout(self):
-        """!Do dialog layout"""
-        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-        
-        #
-        # settings
-        #
-        settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
-        
-        gridSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
-
-        gridSizer.Add(item=self.serverText,
-                      flag=wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.AddGrowableCol(1)
-        gridSizer.Add(item=self.server,
-                      flag=wx.EXPAND | wx.ALL)
-        
-        settingsSizer.Add(item=gridSizer, proportion=1,
-                       flag=wx.EXPAND | wx.ALL)
-        
-        dialogSizer.Add(item=settingsSizer, proportion=0,
-                        flag=wx.ALL | wx.EXPAND, border=5)
-        
-        #
-        # list of layers
-        #
-        layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)
-
-        layersSizer.Add(item=self.list, proportion=1,
-                        flag=wx.ALL | wx.EXPAND, border=5)
-        
-        dialogSizer.Add(item=layersSizer, proportion=1,
-                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-
-        dialogSizer.Add(item=self.add, proportion=0,
-                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-        
-        #
-        # buttons
-        #
-        btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL)
-
-        btnsizer.Add(item=self.btn_cancel, proportion=0,
-                     flag=wx.ALL | wx.ALIGN_CENTER,
-                     border=10)
-        
-        btnsizer.Add(item=self.btn_connect, proportion=0,
-                     flag=wx.ALL | wx.ALIGN_CENTER,
-                     border=10)
-        
-        btnsizer.Add(item=self.btn_import, proportion=0,
-                     flag=wx.ALL | wx.ALIGN_CENTER,
-                     border=10)
-        
-        dialogSizer.Add(item=btnsizer, proportion=0,
-                        flag=wx.ALIGN_CENTER)
-        
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(dialogSizer)
-        dialogSizer.Fit(self.panel)
-        self.Layout()
-
-    def OnCancel(self, event):
-        """!Button 'Cancel' pressed -> close the dialog"""
-        self.Close()
-
-    def OnConnect(self, event):
-        """!Button 'Connect' pressed"""
-        server = self.server.GetValue()
-        if not server:
-            self.btn_import.Enable(False)
-            return # not reachable
-
-        layers = {}
-        ret = gcmd.RunCommand('r.in.wms',
-                              quiet = True,
-                              parent = self,
-                              read = True,
-                              flags = 'l',
-                              mapserver = server)
-        
-        if not ret:
-            self.list.LoadData()
-            self.btn_import.Enable(False)
-            return # no layers found
-        
-        lastLayer = lastStyle = ''
-        for line in ret.splitlines():
-            try:
-                key, value = line.split(':', 1)
-            except ValueError:
-                continue
-            key = key.strip().lower()
-            value = value.strip()
-            
-            if key == 'layer':
-                layers[value] = {}
-                lastLayer = value
-            elif key == 'title':
-                layers[lastLayer][key] = value
-            elif key == 'style':
-                if 'style' not in layers[lastLayer]:
-                    layers[lastLayer]['style'] = {}
-                layers[lastLayer]['style'][value] = ''
-                lastStyle = value
-            elif key == 'style title':
-                layers[lastLayer]['style'][lastStyle] = value
-        
-        # update list of layers
-        self.list.LoadData(layers)
-        
-        if len(layers.keys()) > 0:
-            self.btn_import.Enable(True)
-        else:
-            self.btn_import.Enable(False)
-        
-    def OnServer(self, event):
-        """!Server settings changed"""
-        value = event.GetString()
-        if value:
-            self.btn_connect.Enable(True)
-        else:
-            self.btn_connect.Enable(False)
-        
-    def GetLayers(self):
-        """!Get list of selected layers/styles to be imported"""
-        return self.list.GetSelectedLayers()
-
-    def GetSettings(self):
-        """!Get connection settings"""
-        return { 'server' : self.server.GetValue() }
-    
-class LayersList(TreeListCtrl, listmix.ListCtrlAutoWidthMixin):
-    def __init__(self, parent, pos=wx.DefaultPosition):
-        """!List of layers to be imported (dxf, shp...)"""
-        self.parent = parent
-        
-        TreeListCtrl.__init__(self, parent, wx.ID_ANY,
-                              style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT |
-                              wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_MULTIPLE)
-        
-        # setup mixins
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        
-        self.AddColumn(_('Layer / Style'))
-        self.AddColumn(_('Title'))
-        self.SetMainColumn(0) # column with the tree
-        self.SetColumnWidth(0, 175)
-        
-        self.root = None
-        
-    def LoadData(self, data = {}):
-        """!Load data into list"""
-        # detete first all items
-        self.DeleteAllItems()
-        self.root = self.AddRoot(_("Layers"))
-
-        layers = data.keys()
-        if not layers:
-            return
-        
-        layers.sort()
-
-        for layer in layers:
-            title = data[layer]['title']
-            lchild = self.AppendItem(self.root, layer)
-            self.SetItemText(lchild, title, 1)
-            if 'style' in data[layer]:
-                styles = data[layer]['style'].keys()
-                if not styles:
-                    continue
-                styles.sort()
-                for style in styles:
-                    title = data[layer]['style'][style]
-                    schild = self.AppendItem(lchild, style)
-                    self.SetItemText(schild, title, 1)
-        
-        self.Expand(self.root)
-        
-    def GetItemCount(self):
-        """!Required for listmix.ListCtrlAutoWidthMixin"""
-        return 0
-
-    def GetCountPerPage(self):
-        """!Required for listmix.ListCtrlAutoWidthMixin"""
-        return 0
-
-    def GetSelectedLayers(self):
-        """!Get selected layers/styles"""
-        layers = dict()
-
-        for item in self.GetSelections():
-            parent = self.GetItemParent(item)
-            if parent == self.root: # -> layer
-                layer = self.GetItemText(item, 0)
-                layers[layer] = list()
-                sitem, cookie = self.GetFirstChild(item)
-                while sitem:
-                    layers[layer].append(self.GetItemText(sitem, 0))
-                    sitem, cookie = self.GetNextChild(item, cookie)
-            else: # -> style
-                layer = self.GetItemText(parent, 0)
-                layers[layer] = list()
-                layers[layer].append(self.GetItemText(item, 0))
-        
-        return layers

Deleted: grass/trunk/gui/wxpython/gui_modules/preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/preferences.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2533 +0,0 @@
-"""!
- at package preferences
-
- at brief User preferences dialog
-
-Sets default display font, etc.
-If you want to add some value to settings you have to add default value 
-to defaultSettings and set constraints in internalSettings in Settings class.
-Everything can be used in PreferencesDialog.
-
-Classes:
- - Settings
- - PreferencesBaseDialog
- - PreferencesDialog
- - DefaultFontDialog
- - MapsetAccess
- - NvizPreferencesDialog
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Michael Barton (Arizona State University)
- at author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
-"""
-
-import os
-import sys
-import copy
-import stat
-import types
-try:
-    import pwd
-    havePwd = True
-except ImportError:
-    havePwd = False
-
-import wx
-import wx.lib.filebrowsebutton as filebrowse
-import wx.lib.colourselect as csel
-import wx.lib.mixins.listctrl as listmix
-
-from grass.script import core as grass
-
-import gcmd
-import utils
-import globalvar
-from debug import Debug as Debug
-
-from wx.lib.newevent import NewEvent
-
-wxSettingsChanged, EVT_SETTINGS_CHANGED = NewEvent()
-
-class Settings:
-    """!Generic class where to store settings"""
-    def __init__(self):
-        # settings file
-        self.filePath = os.path.join(utils.GetSettingsPath(), 'wx')
-        
-        # key/value separator
-        self.sep = ';'
-        
-        try:
-            projFile = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
-        except KeyError:
-            projFile = ''
-        
-        #
-        # default settings
-        #
-        self.defaultSettings = {
-            #
-            # general
-            #
-            'general': {
-                # use default window layout (layer manager, displays, ...)
-                'defWindowPos' : {
-                    'enabled' : True,
-                    'dim' : '0,0,%d,%d,%d,0,%d,%d' % \
-                        (globalvar.GM_WINDOW_SIZE[0],
-                         globalvar.GM_WINDOW_SIZE[1],
-                         globalvar.GM_WINDOW_SIZE[0],
-                         globalvar.MAP_WINDOW_SIZE[0],
-                         globalvar.MAP_WINDOW_SIZE[1])
-                    },
-                # workspace
-                'workspace' : {
-                    'posDisplay' : {
-                        'enabled' : False
-                        },
-                    'posManager' : {
-                        'enabled' : False
-                        },
-                    },
-                },
-            'manager' : {
-                # show opacity level widget
-                'changeOpacityLevel' : {
-                    'enabled' : False
-                    }, 
-                # ask when removing layer from layer tree
-                'askOnRemoveLayer' : {
-                    'enabled' : True
-                    },
-                # ask when quiting wxGUI or closing display
-                'askOnQuit' : {
-                    'enabled' : True
-                    },
-                # hide tabs
-                'hideTabs' : {
-                    'search' : False,
-                    'pyshell' : False,
-                    },
-                'copySelectedTextToClipboard' : {
-                    'enabled' : False
-                    },
-                },
-            #
-            # appearance
-            #
-            'appearance': {
-                'outputfont' : {
-                    'type' : 'Courier New',
-                    'size': '10',
-                    },
-                # expand/collapse element list
-                'elementListExpand' : {
-                    'selection' : 0 
-                    },
-                'menustyle' : {
-                    'selection' : 1
-                    },
-                'gSelectPopupHeight' : {
-                    'value' : 200
-                    },
-                'iconTheme' : {
-                    'type' : 'grass'
-                    },
-                },
-            #
-            # display
-            #
-            'display': {
-                'font' : {
-                    'type' : '',
-                    'encoding': 'ISO-8859-1',
-                    },
-                'driver': {
-                    'type': 'cairo'
-                    },
-                'alignExtent' : {
-                    'enabled' : True
-                    },
-                'compResolution' : {
-                    'enabled' : False
-                    },
-                'autoRendering': {
-                    'enabled' : True
-                    },
-                'autoZooming' : {
-                    'enabled' : False
-                    },
-                'statusbarMode': {
-                    'selection' : 0
-                    },
-                'bgcolor': {
-                    'color' : (255, 255, 255, 255),
-                    },
-                },
-            #
-            # projection
-            #
-            'projection' : {
-                'statusbar' : {
-                    'proj4'    : '',
-                    'epsg'     : '',
-                    'projFile' : projFile,
-                    },
-                'format' : {
-                    'll'  : 'DMS',
-                    'precision' : 2,
-                    },
-                },
-            #
-            # Attribute Table Manager
-            #
-            'atm' : {
-                'highlight' : {
-                    'color' : (255, 255, 0, 255),
-                    'width' : 2
-                    },
-                'leftDbClick' : {
-                    'selection' : 1 # draw selected
-                    },
-                'askOnDeleteRec' : {
-                    'enabled' : True
-                    },
-                'keycolumn' : {
-                    'value' : 'cat'
-                    },
-                'encoding' : {
-                    'value' : '',
-                    }
-                },
-            #
-            # Command
-            #
-            'cmd': {
-                'overwrite' : {
-                    'enabled' : False
-                    },
-                'closeDlg' : {
-                    'enabled' : False
-                    },
-                'verbosity' : {
-                    'selection' : 'grassenv'
-                    },
-                # d.rast
-                'rasterOpaque' : {
-                    'enabled' : False
-                    },
-                'rasterColorTable' : {
-                    'enabled'   : False,
-                    'selection' : 'rainbow',
-                    },
-                # d.vect
-                'showType': {
-                    'point' : {
-                        'enabled' : True
-                        },
-                    'line' : {
-                        'enabled' : True
-                        },
-                    'centroid' : {
-                        'enabled' : True
-                        },
-                    'boundary' : {
-                        'enabled' : True
-                        },
-                    'area' : {
-                        'enabled' : True
-                        },
-                    'face' : {
-                        'enabled' : True
-                        },
-                    },
-                'addNewLayer' : {
-                    'enabled' : True,
-                    },
-                'interactiveInput' : {
-                    'enabled' : True,
-                    },
-                },
-            #
-            # vdigit
-            #
-            'vdigit' : {
-                # symbology
-                'symbol' : {
-                    'highlight' : {
-                        'enabled' : None,
-                        'color' : (255, 255, 0, 255)
-                        }, # yellow
-                    'highlightDupl' : {
-                        'enabled' : None,
-                        'color' : (255, 72, 0, 255)
-                        }, # red
-                    'point' : {
-                        'enabled' : True,
-                        'color' : (0, 0, 0, 255)
-                        }, # black
-                    'line' : {
-                        'enabled' : True,
-                        'color' : (0, 0, 0, 255)
-                        }, # black
-                    'boundaryNo' : {
-                        'enabled' : True,
-                        'color' : (126, 126, 126, 255)
-                        }, # grey
-                    'boundaryOne' : {
-                        'enabled' : True,
-                        'color' : (0, 255, 0, 255)
-                        }, # green
-                    'boundaryTwo' : {
-                        'enabled' : True,
-                        'color' : (255, 135, 0, 255)
-                        }, # orange
-                    'centroidIn' : {
-                        'enabled' : True,
-                        'color' : (0, 0, 255, 255)
-                        }, # blue
-                    'centroidOut' : {
-                        'enabled' : True,
-                        'color' : (165, 42, 42, 255)
-                        }, # brown
-                    'centroidDup' : {
-                        'enabled' : True,
-                        'color' : (156, 62, 206, 255)
-                        }, # violet
-                    'nodeOne' : {
-                        'enabled' : True,
-                        'color' : (255, 0, 0, 255)
-                        }, # red
-                    'nodeTwo' : {
-                        'enabled' : True,
-                        'color' : (0, 86, 45, 255)
-                        }, # dark green
-                    'vertex' : {
-                        'enabled' : False,
-                        'color' : (255, 20, 147, 255)
-                        }, # deep pink
-                    'area' : {
-                        'enabled' : False,
-                        'color' : (217, 255, 217, 255)
-                        }, # green
-                    'direction' : {
-                        'enabled' : False,
-                        'color' : (255, 0, 0, 255)
-                        }, # red
-                    },
-                # display
-                'lineWidth' : {
-                    'value' : 2,
-                    'units' : 'screen pixels'
-                    },
-                # snapping
-                'snapping' : {
-                    'value' : 10,
-                    'units' : 'screen pixels'
-                    },
-                'snapToVertex' : {
-                    'enabled' : False
-                    },
-                # digitize new record
-                'addRecord' : {
-                    'enabled' : True
-                    },
-                'layer' :{
-                    'value' : 1
-                    },
-                'category' : {
-                    'value' : 1
-                    },
-                'categoryMode' : {
-                    'selection' : 0
-                    },
-                # delete existing feature(s)
-                'delRecord' : {
-                    'enabled' : True
-                    },
-                # query tool
-                'query' : {
-                    'selection' : 0,
-                    'box' : True
-                    },
-                'queryLength' : {
-                    'than-selection' : 0,
-                    'thresh' : 0
-                    },
-                'queryDangle' : {
-                    'than-selection' : 0,
-                    'thresh' : 0
-                    },
-                # select feature (point, line, centroid, boundary)
-                'selectType': {
-                    'point' : {
-                        'enabled' : True
-                        },
-                    'line' : {
-                        'enabled' : True
-                        },
-                    'centroid' : {
-                        'enabled' : True
-                        },
-                    'boundary' : {
-                        'enabled' : True
-                        },
-                    },
-                'selectThresh' : {
-                    'value' : 10,
-                    'units' : 'screen pixels'
-                    },
-                'checkForDupl' : {
-                    'enabled' : False
-                    },
-                'selectInside' : {
-                    'enabled' : False
-                    },
-                # exit
-                'saveOnExit' : {
-                    'enabled' : False,
-                    },
-                # break lines on intersection
-                'breakLines' : {
-                    'enabled' : False,
-                    },
-                },
-             # 
-             # plots for profiles, histograms, and scatterplots
-             #
-            'profile': {
-                'raster' : {
-                    'pcolor'        : (0, 0, 255, 255), # line color
-                    'pwidth'        : 1, # line width
-                    'pstyle'        : 'solid', # line pen style
-                    'datatype'      : 'cell', # raster type
-                    },
-                'font' : {
-                    'titleSize' : 12,
-                    'axisSize' : 11,
-                    'legendSize' : 10,
-                    },
-                'marker' : {
-                    'color' : (0, 0, 0, 255),
-                    'fill' : 'transparent',
-                    'size' : 2,
-                    'type' : 'triangle',
-                    'legend' : _('Segment break'),
-                    },
-                'grid' : {
-                    'color' : (200, 200, 200, 255),
-                    'enabled' : True,
-                    },
-                'x-axis' : {
-                    'type' : 'auto', # axis format
-                    'min' : 0, # axis min for custom axis range
-                    'max': 0, # axis max for custom axis range
-                    'log' : False,
-                    },
-                'y-axis' : {
-                    'type' : 'auto', # axis format
-                    'min' : 0, # axis min for custom axis range
-                    'max': 0, # axis max for custom axis range
-                    'log' : False,
-                    },
-                'legend' : {
-                    'enabled' : True
-                    },
-                },
-             'histogram': {
-                'raster' : {
-                    'pcolor'        : (0, 0, 255, 255), # line color
-                    'pwidth'        : 1, # line width
-                    'pstyle'        : 'solid', # line pen style
-                    'datatype'      : 'cell', # raster type
-                    },
-                'font' : {
-                    'titleSize'     : 12,
-                    'axisSize'      : 11,
-                    'legendSize'    : 10,
-                    },
-                'grid' : {
-                    'color'         : (200, 200, 200, 255),
-                    'enabled'       : True,
-                    },
-                'x-axis' : {
-                    'type'          : 'auto', # axis format
-                    'min'           : 0, # axis min for custom axis range
-                    'max'           : 0, # axis max for custom axis range
-                    'log'           : False,
-                    },
-                'y-axis' : {
-                    'type'          : 'auto', # axis format
-                    'min'           : 0, # axis min for custom axis range
-                    'max'           : 0, # axis max for custom axis range
-                    'log'           : False,
-                    },
-                'legend' : {
-                    'enabled'       : True
-                    },
-                },
-             'scatter': {
-                'rasters' : {
-                    'pcolor' : (0, 0, 255, 255),
-                    'pfill' : 'solid',
-                    'psize' : 1,
-                    'ptype' : 'dot',
-                    'plegend' : _('Data point'),
-                    0 : {'datatype' : 'CELL'},
-                    1 : {'datatype' : 'CELL'},
-                    },
-                'font' : {
-                    'titleSize'     : 12,
-                    'axisSize'      : 11,
-                    'legendSize'    : 10,
-                    },
-                'grid' : {
-                    'color'         : (200, 200, 200, 255),
-                    'enabled'       : True,
-                    },
-                'x-axis' : {
-                    'type'          : 'auto', # axis format
-                    'min'           : 0, # axis min for custom axis range
-                    'max'           : 0, # axis max for custom axis range
-                    'log'           : False,
-                    },
-                'y-axis' : {
-                    'type'          : 'auto', # axis format
-                    'min'           : 0, # axis min for custom axis range
-                    'max'           : 0, # axis max for custom axis range
-                    'log'           : False,
-                    },
-                'legend' : {
-                    '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,
-                    },
-                },
-            'nviz' : {
-                'view' : {
-                    'persp' : {
-                        'value' : 20,
-                        'step' : 2,
-                        },
-                    'position' : {
-                        'x' : 0.84,
-                        'y' : 0.16,
-                        },
-                    'twist' : {
-                        'value' : 0,
-                        },
-                    'z-exag' : {
-                        'min' : 0,
-                        'max' : 10,
-                        'value': 1,
-                        },
-                    'background' : {
-                        'color' : (255, 255, 255, 255), # white
-                        },
-                    },
-                'fly' : {
-                    'exag' : {
-                        'move' : 5,
-                        'turn' : 5,
-                        }
-                    },
-                'animation' : {
-                    'fps' : 24,
-                    'prefix' : _("animation")
-                    },
-                'surface' : {
-                    'shine': {
-                        'map' : False,
-                        'value' : 60.0,
-                        },
-                    'color' : {
-                        'map' : True,
-                        'value' : (100, 100, 100, 255), # constant: grey
-                        },
-                    'draw' : {
-                        'wire-color' : (136, 136, 136, 255),
-                        'mode' : 1, # fine
-                        'style' : 1, # surface
-                        'shading' : 1, # gouraud
-                        'res-fine' : 6,
-                        'res-coarse' : 9,
-                        },
-                    'position' : {
-                        'x' : 0,
-                        'y' : 0,
-                        'z' : 0,
-                        },
-                    },
-                'constant' : {
-                    'color' : (100, 100, 100, 255),
-                    'value' : 0.0,
-                    'transp' : 0,
-                    'resolution': 6
-                },
-                'vector' : {
-                    'lines' : {
-                        'show' : False,
-                        'width' : 2,
-                        'color' : (0, 0, 255, 255), # blue
-                        'flat' : False,
-                        'height' : 0,
-                        'rgbcolumn': None,
-                        'sizecolumn': None,
-                        },
-                    'points' : {
-                        'show' : False,
-                        'size' : 100,
-                        'width' : 2,
-                        'marker' : 2,
-                        'color' : (0, 0, 255, 255), # blue
-                        'height' : 0,
-                        'rgbcolumn': None,
-                        'sizecolumn': None,
-                        }
-                    },
-                'volume' : {
-                    'color' : {
-                        'map' : True,
-                        'value' : (100, 100, 100, 255), # constant: grey
-                        },
-                    'draw' : {
-                        'mode'       : 0, # isosurfaces
-                        'shading'    : 1, # gouraud
-                        'resolution' : 3, # polygon resolution
-                        },
-                    'shine': {
-                        'map' : False,
-                        'value' : 60,
-                        },
-                    'topo': {
-                        'map' : None,
-                        'value' : 0.0
-                        },
-                    'transp': {
-                        'map' : None,
-                        'value': 0
-                        },
-                    'mask': {
-                        'map' : None,
-                        'value': ''
-                        },
-                    'slice_position': {
-                        'x1' : 0,
-                        'x2' : 1,
-                        'y1' : 0,
-                        'y2' : 1,
-                        'z1' : 0,
-                        'z2' : 1,
-                        'axis' : 0,
-                        }
-                    },
-                'cplane' : {
-                    'shading': 4,
-                    'rotation':{
-                        'rot': 0, 
-                        'tilt': 0
-                        }, 
-                    'position':{
-                        'x' : 0,
-                        'y' : 0,
-                        'z' : 0
-                    }   
-                },
-                'light' : {
-                    'position' : {
-                        'x' : 0.68,
-                        'y' : -0.68,
-                        'z' : 80,
-                        },
-                    'bright'  : 80,
-                    'color'   : (255, 255, 255, 255), # white
-                    'ambient' : 20,
-                    },
-                'fringe' : {
-                    'elev'   : 55,
-                    'color'  : (128, 128, 128, 255), # grey
-                    },
-                'arrow': {
-                    'color': (0, 0, 0),
-                    },
-                'scalebar': {
-                    'color': (0, 0, 0),
-                    }
-                },
-            'modeler' : {
-                'disabled': {
-                    'color': (211, 211, 211, 255), # light grey
-                    },
-                'action' : {
-                    'color' : {
-                        'valid'   :  (180, 234, 154, 255), # light green
-                        'invalid' :  (255, 255, 255, 255), # white
-                        'running' :  (255, 0, 0, 255),     # red
-                        },
-                    'size' : {
-                        'width'  : 100,
-                        'height' : 50,
-                        },
-                    'width': {
-                        'parameterized' : 2,
-                        'default'       : 1,
-                        },
-                    },
-                'data' : { 
-                    'color': {
-                        'raster'   : (215, 215, 248, 255), # light blue
-                        'raster3d' : (215, 248, 215, 255), # light green
-                        'vector'   : (248, 215, 215, 255), # light red
-                        },
-                    'size' : {
-                        'width' : 175,
-                        'height' : 50,
-                        },
-                    },
-                'loop' : {
-                    'color' : {
-                        'valid'   :  (234, 226, 154, 255), # light yellow
-                        },
-                    'size' : {
-                        'width' : 175,
-                        'height' : 40,
-                        },
-                    },
-                'if-else' : {
-                    'size' : {
-                        'width' : 150,
-                        'height' : 40,
-                        },
-                    },
-                },
-            }
-
-        # quick fix, http://trac.osgeo.org/grass/ticket/1233
-        # TODO
-        if sys.platform == 'darwin':
-            self.defaultSettings['general']['defWindowPos']['enabled'] = False
-        
-        #
-        # user settings
-        #
-        self.userSettings = copy.deepcopy(self.defaultSettings)
-        try:
-            self.ReadSettingsFile()
-        except gcmd.GException, e:
-            print >> sys.stderr, e.value
-
-        #
-        # internal settings (based on user settings)
-        #
-        self.internalSettings = {}
-        for group in self.userSettings.keys():
-            self.internalSettings[group] = {}
-            for key in self.userSettings[group].keys():
-                self.internalSettings[group][key] = {}
-
-        # self.internalSettings['general']["mapsetPath"]['value'] = self.GetMapsetPath()
-        self.internalSettings['appearance']['elementListExpand']['choices'] = \
-            (_("Collapse all except PERMANENT and current"),
-             _("Collapse all except PERMANENT"),
-             _("Collapse all except current"),
-             _("Collapse all"),
-             _("Expand all"))
-        self.internalSettings['atm']['leftDbClick']['choices'] = (_('Edit selected record'),
-                                                                  _('Display selected'))
-        
-        self.internalSettings['cmd']['verbosity']['choices'] = ('grassenv',
-                                                                'verbose',
-                                                                'quiet')
-                                                                
-        self.internalSettings['appearance']['iconTheme']['choices'] = ('grass',)
-        self.internalSettings['appearance']['menustyle']['choices'] = \
-                   (_("Classic (labels only)"),
-                    _("Combined (labels and module names)"),
-                    _("Professional (module names only)"))
-        self.internalSettings['appearance']['gSelectPopupHeight']['min'] = 50
-        # there is also maxHeight given to TreeCtrlComboPopup.GetAdjustedSize
-        self.internalSettings['appearance']['gSelectPopupHeight']['max'] = 1000
-        
-        self.internalSettings['display']['driver']['choices'] = ['cairo', 'png']
-        self.internalSettings['display']['statusbarMode']['choices'] = None # set during MapFrame init
-
-        self.internalSettings['nviz']['view'] = {}
-        self.internalSettings['nviz']['view']['twist'] = {}
-        self.internalSettings['nviz']['view']['twist']['min'] = -180
-        self.internalSettings['nviz']['view']['twist']['max'] = 180
-        self.internalSettings['nviz']['view']['persp'] = {}
-        self.internalSettings['nviz']['view']['persp']['min'] = 1
-        self.internalSettings['nviz']['view']['persp']['max'] = 100
-        self.internalSettings['nviz']['view']['height'] = {}
-        self.internalSettings['nviz']['view']['height']['value'] = -1
-        self.internalSettings['nviz']['view']['z-exag'] = {}
-        self.internalSettings['nviz']['view']['z-exag']['original'] = 1
-        self.internalSettings['nviz']['view']['rotation'] = None
-        self.internalSettings['nviz']['view']['focus'] = {}
-        self.internalSettings['nviz']['view']['focus']['x'] = -1
-        self.internalSettings['nviz']['view']['focus']['y'] = -1
-        self.internalSettings['nviz']['view']['focus']['z'] = -1
-        self.internalSettings['nviz']['view']['dir'] = {}
-        self.internalSettings['nviz']['view']['dir']['x'] = -1
-        self.internalSettings['nviz']['view']['dir']['y'] = -1
-        self.internalSettings['nviz']['view']['dir']['z'] = -1
-        self.internalSettings['nviz']['view']['dir']['use'] = False
-        
-        for decor in ('arrow', 'scalebar'):
-            self.internalSettings['nviz'][decor] = {}
-            self.internalSettings['nviz'][decor]['position'] = {}
-            self.internalSettings['nviz'][decor]['position']['x'] = 0
-            self.internalSettings['nviz'][decor]['position']['y'] = 0
-            self.internalSettings['nviz'][decor]['size'] = 100
-        self.internalSettings['nviz']['vector'] = {}
-        self.internalSettings['nviz']['vector']['points'] = {}
-        self.internalSettings['nviz']['vector']['points']['marker'] = ("x",
-                                                                       _("box"),
-                                                                       _("sphere"),
-                                                                       _("cube"),
-                                                                       _("diamond"),
-                                                                       _("dtree"),
-                                                                       _("ctree"),
-                                                                       _("aster"),
-                                                                       _("gyro"),
-                                                                       _("histogram"))
-        self.internalSettings['vdigit']['bgmap'] = {}
-        self.internalSettings['vdigit']['bgmap']['value'] = ''
-        
-    def ReadSettingsFile(self, settings = None):
-        """!Reads settings file (mapset, location, gisdbase)"""
-        if settings is None:
-            settings = self.userSettings
-        
-        self._readFile(self.filePath, settings)
-        
-        # set environment variables
-        font = self.Get(group = 'display', key = 'font', subkey = 'type')
-        enc  = self.Get(group = 'display', key = 'font', subkey = 'encoding')
-        if font:
-            os.environ["GRASS_FONT"] = font
-        if enc:
-            os.environ["GRASS_ENCODING"] = enc
-        
-    def _readFile(self, filename, settings = None):
-        """!Read settings from file to dict
-
-        @param filename settings file path
-        @param settings dict where to store settings (None for self.userSettings)
-        """
-        if settings is None:
-            settings = self.userSettings
-        
-        if not os.path.exists(filename):
-            return
-        
-        try:
-            fd = open(filename, "r")
-        except IOError:
-            sys.stderr.write(_("Unable to read settings file <%s>\n") % filename)
-            return
-        
-        try:
-            line = ''
-            for line in fd.readlines():
-                line = line.rstrip('%s' % os.linesep)
-                group, key = line.split(self.sep)[0:2]
-                kv = line.split(self.sep)[2:]
-                subkeyMaster = None
-                if len(kv) % 2 != 0: # multiple (e.g. nviz)
-                    subkeyMaster = kv[0]
-                    del kv[0]
-                idx = 0
-                while idx < len(kv):
-                    if subkeyMaster:
-                        subkey = [subkeyMaster, kv[idx]]
-                    else:
-                        subkey = kv[idx]
-                    value = kv[idx+1]
-                    value = self._parseValue(value, read = True)
-                    self.Append(settings, group, key, subkey, value)
-                    idx += 2
-        except ValueError, e:
-            print >> sys.stderr, _("Error: Reading settings from file <%(file)s> failed.\n"
-                                   "\t\tDetails: %(detail)s\n"
-                                   "\t\tLine: '%(line)s'\n") % { 'file' : filename,
-                                                               'detail' : e,
-                                                               'line' : line }
-            fd.close()
-        
-        fd.close()
-        
-    def SaveToFile(self, settings = None):
-        """!Save settings to the file"""
-        if settings is None:
-            settings = self.userSettings
-        
-        dirPath = utils.GetSettingsPath()
-        if not os.path.exists(dirPath):
-            try:
-                os.mkdir(dirPath)
-            except:
-                gcmd.GError(_('Unable to create settings directory'))
-                return
-        
-        try:
-            file = open(self.filePath, "w")
-            for group in settings.keys():
-                for key in settings[group].keys():
-                    subkeys = settings[group][key].keys()
-                    file.write('%s%s%s%s' % (group, self.sep, key, self.sep))
-                    for idx in range(len(subkeys)):
-                        value = settings[group][key][subkeys[idx]]
-                        if type(value) == types.DictType:
-                            if idx > 0:
-                                file.write('%s%s%s%s%s' % (os.linesep, group, self.sep, key, self.sep))
-                            file.write('%s%s' % (subkeys[idx], self.sep))
-                            kvalues = settings[group][key][subkeys[idx]].keys()
-                            srange = range(len(kvalues))
-                            for sidx in srange:
-                                svalue = self._parseValue(settings[group][key][subkeys[idx]][kvalues[sidx]])
-                                file.write('%s%s%s' % (kvalues[sidx], self.sep,
-                                                       svalue))
-                                if sidx < len(kvalues) - 1:
-                                    file.write('%s' % self.sep)
-                        else:
-                            if idx > 0 and \
-                                    type(settings[group][key][subkeys[idx - 1]]) == types.DictType:
-                                file.write('%s%s%s%s%s' % (os.linesep, group, self.sep, key, self.sep))
-                            value = self._parseValue(settings[group][key][subkeys[idx]])
-                            file.write('%s%s%s' % (subkeys[idx], self.sep, value))
-                            if idx < len(subkeys) - 1 and \
-                                    type(settings[group][key][subkeys[idx + 1]]) != types.DictType:
-                                file.write('%s' % self.sep)
-                    file.write(os.linesep)
-        except IOError, e:
-            raise gcmd.GException(e)
-        except StandardError, e:
-            raise gcmd.GException(_('Writing settings to file <%(file)s> failed.'
-                                    '\n\nDetails: %(detail)s') % { 'file' : self.filePath,
-                                                                   'detail' : e })
-        
-        file.close()
-        
-    def _parseValue(self, value, read = False):
-        """!Parse value to be store in settings file"""
-        if read: # -> read settings (cast values)
-            if value == 'True':
-                value = True
-            elif value == 'False':
-                value = False
-            elif value == 'None':
-                value = None
-            elif ':' in value: # -> color
-                try:
-                    value = tuple(map(int, value.split(':')))
-                except ValueError: # -> string
-                    pass
-            else:
-                try:
-                    value = int(value)
-                except ValueError:
-                    try:
-                        value = float(value)
-                    except ValueError:
-                        pass
-        else: # -> write settings
-            if type(value) == type(()): # -> color
-                value = str(value[0]) + ':' +\
-                    str(value[1]) + ':' + \
-                    str(value[2])
-                
-        return value
-
-    def Get(self, group, key = None, subkey = None, internal = False):
-        """!Get value by key/subkey
-
-        Raise KeyError if key is not found
-        
-        @param group settings group
-        @param key (value, None)
-        @param subkey (value, list or None)
-        @param internal use internal settings instead
-
-        @return value
-        """
-        if internal is True:
-            settings = self.internalSettings
-        else:
-            settings = self.userSettings
-            
-        try:
-            if subkey is None:
-                if key is None:
-                    return settings[group]
-                else:
-                    return settings[group][key]
-            else:
-                if type(subkey) == type(tuple()) or \
-                        type(subkey) == type(list()):
-                    return settings[group][key][subkey[0]][subkey[1]]
-                else:
-                    return settings[group][key][subkey]  
-
-        except KeyError:
-            print >> sys.stderr, "Settings: unable to get value '%s:%s:%s'\n" % \
-                (group, key, subkey)
-        
-    def Set(self, group, value, key = None, subkey = None, internal = False):
-        """!Set value of key/subkey
-        
-        Raise KeyError if group/key is not found
-        
-        @param group settings group
-        @param key key (value, None)
-        @param subkey subkey (value, list or None)
-        @param value value
-        @param internal use internal settings instead
-        """
-        if internal is True:
-            settings = self.internalSettings
-        else:
-            settings = self.userSettings
-        
-        try:
-            if subkey is None:
-                if key is None:
-                    settings[group] = value
-                else:
-                    settings[group][key] = value
-            else:
-                if type(subkey) == type(tuple()) or \
-                        type(subkey) == type(list()):
-                    settings[group][key][subkey[0]][subkey[1]] = value
-                else:
-                    settings[group][key][subkey] = value
-        except KeyError:
-            raise gcmd.GException("%s '%s:%s:%s'" % (_("Unable to set "), group, key, subkey))
-        
-    def Append(self, dict, group, key, subkey, value):
-        """!Set value of key/subkey
-
-        Create group/key/subkey if not exists
-        
-        @param dict settings dictionary to use
-        @param group settings group
-        @param key key
-        @param subkey subkey (value or list)
-        @param value value
-        """
-        if group not in dict:
-            dict[group] = {}
-
-        if key not in dict[group]:
-            dict[group][key] = {}
-
-        if type(subkey) == types.ListType:
-            # TODO: len(subkey) > 2
-            if subkey[0] not in dict[group][key]:
-                dict[group][key][subkey[0]] = {}
-            try:
-                dict[group][key][subkey[0]][subkey[1]] = value
-            except TypeError:
-                print >> sys.stderr, _("Unable to parse settings '%s'") % value + \
-                    ' (' + group + ':' + key + ':' + subkey[0] + ':' + subkey[1] + ')'
-        else:
-            try:
-                dict[group][key][subkey] = value
-            except TypeError:
-                print >> sys.stderr, _("Unable to parse settings '%s'") % value + \
-                    ' (' + group + ':' + key + ':' + subkey + ')'
-        
-    def GetDefaultSettings(self):
-        """!Get default user settings"""
-        return self.defaultSettings
-
-    def Reset(self, key = None):
-        """!Reset to default settings
-
-        @key key in settings dict (None for all keys)
-        """
-        if not key:
-            self.userSettings = copy.deepcopy(self.defaultSettings)
-        else:
-            self.userSettings[key] = copy.deepcopy(self.defaultSettings[key])
-        
-globalSettings = Settings()
-
-class PreferencesBaseDialog(wx.Dialog):
-    """!Base preferences dialog"""
-    def __init__(self, parent, settings, title = _("User settings"),
-                 size = (500, 375),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-        self.parent = parent # ModelerFrame
-        self.title  = title
-        self.size   = size
-        self.settings = settings
-        
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
-                           style = style)
-        
-        # notebook
-        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-        
-        # dict for window ids
-        self.winId = {}
-        
-        # create notebook pages
-        
-        # buttons
-        self.btnDefault = wx.Button(self, wx.ID_ANY, _("Set to default"))
-        self.btnSave = wx.Button(self, wx.ID_SAVE)
-        self.btnApply = wx.Button(self, wx.ID_APPLY)
-        self.btnCancel = wx.Button(self, wx.ID_CANCEL)
-        self.btnSave.SetDefault()
-        
-        # bindigs
-        self.btnDefault.Bind(wx.EVT_BUTTON, self.OnDefault)
-        self.btnDefault.SetToolTipString(_("Revert settings to default and apply changes"))
-        self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        self.btnApply.SetToolTipString(_("Apply changes for the current session"))
-        self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        self.btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
-        self.btnSave.SetDefault()
-        self.btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        self.btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-
-        self._layout()
-        
-    def _layout(self):
-        """!Layout window"""
-        # sizers
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = self.btnDefault, proportion = 1,
-                     flag = wx.ALL, border = 5)
-        btnStdSizer = wx.StdDialogButtonSizer()
-        btnStdSizer.AddButton(self.btnCancel)
-        btnStdSizer.AddButton(self.btnSave)
-        btnStdSizer.AddButton(self.btnApply)
-        btnStdSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND, border = 0)
-        mainSizer.Add(item = btnStdSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        
-    def OnDefault(self, event):
-        """!Button 'Set to default' pressed"""
-        self.settings.userSettings = copy.deepcopy(self.settings.defaultSettings)
-        
-        # update widgets
-        for gks in self.winId.keys():
-            try:
-                group, key, subkey = gks.split(':')
-                value = self.settings.Get(group, key, subkey)
-            except ValueError:
-                group, key, subkey, subkey1 = gks.split(':')
-                value = self.settings.Get(group, key, [subkey, subkey1])
-            win = self.FindWindowById(self.winId[gks])
-            if win.GetName() in ('GetValue', 'IsChecked'):
-                value = win.SetValue(value)
-            elif win.GetName() == 'GetSelection':
-                value = win.SetSelection(value)
-            elif win.GetName() == 'GetStringSelection':
-                value = win.SetStringSelection(value)
-            else:
-                value = win.SetValue(value)
-        
-    def OnApply(self, event):
-        """!Button 'Apply' pressed
-        Posts event EVT_SETTINGS_CHANGED.
-        """
-        if self._updateSettings():
-            self.parent.goutput.WriteLog(_('Settings applied to current session but not saved'))
-            event = wxSettingsChanged()
-            wx.PostEvent(self, event)
-            self.Close()
-
-    def OnCloseWindow(self, event):
-        self.Hide()
-        
-    def OnCancel(self, event):
-        """!Button 'Cancel' pressed"""
-        self.Close()
-        
-    def OnSave(self, event):
-        """!Button 'Save' pressed
-        Posts event EVT_SETTINGS_CHANGED.
-        """
-        if self._updateSettings():
-            self.settings.SaveToFile()
-            self.parent.goutput.WriteLog(_('Settings saved to file \'%s\'.') % self.settings.filePath)
-            event = wxSettingsChanged()
-            wx.PostEvent(self, event)
-            self.Close()
-
-    def _updateSettings(self):
-        """!Update user settings"""
-        for item in self.winId.keys():
-            try:
-                group, key, subkey = item.split(':')
-                subkey1 = None
-            except ValueError:
-                group, key, subkey, subkey1 = item.split(':')
-            
-            id = self.winId[item]
-            win = self.FindWindowById(id)
-            if win.GetName() == 'GetValue':
-                value = win.GetValue()
-            elif win.GetName() == 'GetSelection':
-                value = win.GetSelection()
-            elif win.GetName() == 'IsChecked':
-                value = win.IsChecked()
-            elif win.GetName() == 'GetStringSelection':
-                value = win.GetStringSelection()
-            elif win.GetName() == 'GetColour':
-                value = tuple(win.GetValue())
-            else:
-                value = win.GetValue()
-
-            if key == 'keycolumn' and value == '':
-                wx.MessageBox(parent = self,
-                              message = _("Key column cannot be empty string."),
-                              caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
-                win.SetValue(self.settings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
-                return False
-
-            if subkey1:
-                self.settings.Set(group, value, key, [subkey, subkey1])
-            else:
-                self.settings.Set(group, value, key, subkey)
-        
-        if self.parent.GetName() == 'Modeler':
-            return True
-        
-        #
-        # update default window dimension
-        #
-        if self.settings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled') is True:
-            dim = ''
-            # layer manager
-            pos = self.parent.GetPosition()
-            size = self.parent.GetSize()
-            dim = '%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
-            # opened displays
-            for page in range(0, self.parent.gm_cb.GetPageCount()):
-                pos = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetPosition()
-                size = self.parent.gm_cb.GetPage(page).maptree.mapdisplay.GetSize()
-
-                dim += ',%d,%d,%d,%d' % (pos[0], pos[1], size[0], size[1])
-
-            self.settings.Set(group = 'general', key = 'defWindowPos', subkey = 'dim', value = dim)
-        else:
-            self.settings.Set(group = 'general', key = 'defWindowPos', subkey = 'dim', value = '')
-
-        return True
-
-class PreferencesDialog(PreferencesBaseDialog):
-    """!User preferences dialog"""
-    def __init__(self, parent, title = _("GUI Settings"),
-                 settings = globalSettings):
-        
-        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
-                                       settings = settings)
-        
-        # create notebook pages
-        self._createGeneralPage(self.notebook)
-        self._createAppearancePage(self.notebook)
-        self._createDisplayPage(self.notebook)
-        self._createCmdPage(self.notebook)
-        self._createAttributeManagerPage(self.notebook)
-        self._createProjectionPage(self.notebook)
-        
-        self.SetMinSize(self.GetBestSize())
-        self.SetSize(self.size)
-        
-    def _createGeneralPage(self, notebook):
-        """!Create notebook page for general settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("General"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        #
-        # Layer Manager settings
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Layer Manager settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        #
-        # ask when removing map layer from layer tree
-        #
-        row = 0
-        askOnRemoveLayer = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                       label = _("Ask when removing map layer from layer tree"),
-                                       name = 'IsChecked')
-        askOnRemoveLayer.SetValue(self.settings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'))
-        self.winId['manager:askOnRemoveLayer:enabled'] = askOnRemoveLayer.GetId()
-        
-        gridSizer.Add(item = askOnRemoveLayer,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1
-        askOnQuit = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                label = _("Ask when quiting wxGUI or closing display"),
-                                name = 'IsChecked')
-        askOnQuit.SetValue(self.settings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'))
-        self.winId['manager:askOnQuit:enabled'] = askOnQuit.GetId()
-        
-        gridSizer.Add(item = askOnQuit,
-                      pos = (row, 0), span = (1, 2))
-
-        row += 1
-        hideSearch = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                 label = _("Hide '%s' tab (requires GUI restart)") % _("Search module"),
-                                 name = 'IsChecked')
-        hideSearch.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'))
-        self.winId['manager:hideTabs:search'] = hideSearch.GetId()
-        
-        gridSizer.Add(item = hideSearch,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1
-        hidePyShell = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                  label = _("Hide '%s' tab (requires GUI restart)") % _("Python shell"),
-                                  name = 'IsChecked')
-        hidePyShell.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'))
-        self.winId['manager:hideTabs:pyshell'] = hidePyShell.GetId()
-        
-        gridSizer.Add(item = hidePyShell,
-                      pos = (row, 0), span = (1, 2))
-        
-        #
-        # Selected text is copied to clipboard
-        #
-        row += 1
-        copySelectedTextToClipboard = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                                  label = _("Automatically copy selected text to clipboard (in Command console)"),
-                                                  name = 'IsChecked')
-        copySelectedTextToClipboard.SetValue(self.settings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled'))
-        self.winId['manager:copySelectedTextToClipboard:enabled'] = copySelectedTextToClipboard.GetId()
-        
-        gridSizer.Add(item = copySelectedTextToClipboard,
-                      pos = (row, 0), span = (1, 2))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        #
-        # workspace
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Workspace settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        row = 0
-        posDisplay = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                 label = _("Suppress positioning Map Display Window(s)"),
-                                 name = 'IsChecked')
-        posDisplay.SetValue(self.settings.Get(group = 'general', key = 'workspace',
-                                              subkey = ['posDisplay', 'enabled']))
-        self.winId['general:workspace:posDisplay:enabled'] = posDisplay.GetId()
-        
-        gridSizer.Add(item = posDisplay,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1 
-        
-        posManager = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                 label = _("Suppress positioning Layer Manager window"),
-                                 name = 'IsChecked')
-        posManager.SetValue(self.settings.Get(group = 'general', key = 'workspace',
-                                              subkey = ['posManager', 'enabled']))
-        self.winId['general:workspace:posManager:enabled'] = posManager.GetId()
-        
-        gridSizer.Add(item = posManager,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1
-        defaultPos = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                 label = _("Save current window layout as default"),
-                                 name = 'IsChecked')
-        defaultPos.SetValue(self.settings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'))
-        defaultPos.SetToolTip(wx.ToolTip (_("Save current position and size of Layer Manager window and opened "
-                                            "Map Display window(s) and use as default for next sessions.")))
-        self.winId['general:defWindowPos:enabled'] = defaultPos.GetId()
-        
-        gridSizer.Add(item = defaultPos,
-                      pos = (row, 0), span = (1, 2))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        panel.SetSizer(border)
-        
-        return panel
-    
-
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createAppearancePage(self, notebook):
-        """!Create notebook page for display settings"""
-   
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Appearance"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-
-        #
-        # font settings
-        #
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Font for command output:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        outfontButton = wx.Button(parent = panel, id = wx.ID_ANY,
-                               label = _("Set font"), size = (100, -1))
-        gridSizer.Add(item = outfontButton,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        #
-        # appearence
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Appearance settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer  =  wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-
-        #
-        # element list
-        #
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Element list:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        elementList = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
-                                choices = self.settings.Get(group = 'appearance', key = 'elementListExpand',
-                                                            subkey = 'choices', internal = True),
-                                name = "GetSelection")
-        elementList.SetSelection(self.settings.Get(group = 'appearance', key = 'elementListExpand',
-                                                   subkey = 'selection'))
-        self.winId['appearance:elementListExpand:selection'] = elementList.GetId()
-
-        gridSizer.Add(item = elementList,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        #
-        # menu style
-        #
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Menu style (requires GUI restart):")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        listOfStyles = self.settings.Get(group = 'appearance', key = 'menustyle',
-                                         subkey = 'choices', internal = True)
-        
-        menuItemText = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
-                                 choices = listOfStyles,
-                                 name = "GetSelection")
-        menuItemText.SetSelection(self.settings.Get(group = 'appearance', key = 'menustyle', subkey = 'selection'))
-        
-        self.winId['appearance:menustyle:selection'] = menuItemText.GetId()
-        
-        gridSizer.Add(item = menuItemText,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-        
-        #
-        # gselect.TreeCtrlComboPopup height
-        #
-        row += 1
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Height of map selection popup window (in pixels):")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        min = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'min', internal = True)
-        max = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'max', internal = True)
-        value = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
-        
-        popupHeightSpin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1))
-        popupHeightSpin.SetRange(min,max)
-        popupHeightSpin.SetValue(value)
-        
-        self.winId['appearance:gSelectPopupHeight:value'] = popupHeightSpin.GetId()
-        
-        gridSizer.Add(item = popupHeightSpin,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-        
-        
-        #
-        # icon theme
-        #
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = _("Icon theme (requires GUI restart):")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        iconTheme = wx.Choice(parent = panel, id = wx.ID_ANY, size = (100, -1),
-                              choices = self.settings.Get(group = 'appearance', key = 'iconTheme',
-                                                        subkey = 'choices', internal = True),
-                              name = "GetStringSelection")
-        iconTheme.SetStringSelection(self.settings.Get(group = 'appearance', key = 'iconTheme', subkey = 'type'))
-        self.winId['appearance:iconTheme:type'] = iconTheme.GetId()
-
-        gridSizer.Add(item = iconTheme,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        panel.SetSizer(border)
-                
-        # bindings
-        outfontButton.Bind(wx.EVT_BUTTON, self.OnSetOutputFont)
-        
-        return panel
-    
-    def _createDisplayPage(self, notebook):
-        """!Create notebook page for display settings"""
-   
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Map Display"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-
-        #
-        # font settings
-        #
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Default font for GRASS displays:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        fontButton = wx.Button(parent = panel, id = wx.ID_ANY,
-                               label = _("Set font"), size = (100, -1))
-        gridSizer.Add(item = fontButton,
-                      flag = wx.ALIGN_RIGHT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 1))
-
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        #
-        # display settings
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Default display settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-
-        
-        #
-        # display driver
-        #
-        row = 0
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Display driver:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        listOfDrivers = self.settings.Get(group = 'display', key = 'driver', subkey = 'choices', internal = True)
-        driver = wx.Choice(parent = panel, id = wx.ID_ANY, size = (150, -1),
-                           choices = listOfDrivers,
-                           name = "GetStringSelection")
-        driver.SetStringSelection(self.settings.Get(group = 'display', key = 'driver', subkey = 'type'))
-        self.winId['display:driver:type'] = driver.GetId()
-        
-        gridSizer.Add(item = driver,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-        
-        #
-        # Statusbar mode
-        #
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Statusbar mode:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        listOfModes = self.settings.Get(group = 'display', key = 'statusbarMode', subkey = 'choices', internal = True)
-        statusbarMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (150, -1),
-                                  choices = listOfModes,
-                                  name = "GetSelection")
-        statusbarMode.SetSelection(self.settings.Get(group = 'display', key = 'statusbarMode', subkey = 'selection'))
-        self.winId['display:statusbarMode:selection'] = statusbarMode.GetId()
-
-        gridSizer.Add(item = statusbarMode,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-
-        #
-        # Background color
-        #
-        row += 1
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Background color:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        bgColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                    colour = self.settings.Get(group = 'display', key = 'bgcolor', subkey = 'color'),
-                                    size = globalvar.DIALOG_COLOR_SIZE)
-        bgColor.SetName('GetColour')
-        self.winId['display:bgcolor:color'] = bgColor.GetId()
-        
-        gridSizer.Add(item = bgColor,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-        
-        #
-        # Align extent to display size
-        #
-        row += 1
-        alignExtent = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                  label = _("Align region extent based on display size"),
-                                  name = "IsChecked")
-        alignExtent.SetValue(self.settings.Get(group = 'display', key = 'alignExtent', subkey = 'enabled'))
-        self.winId['display:alignExtent:enabled'] = alignExtent.GetId()
-
-        gridSizer.Add(item = alignExtent,
-                      pos = (row, 0), span = (1, 2))
-        
-        #
-        # Use computation resolution
-        #
-        row += 1
-        compResolution = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                     label = _("Constrain display resolution to computational settings"),
-                                     name = "IsChecked")
-        compResolution.SetValue(self.settings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
-        self.winId['display:compResolution:enabled'] = compResolution.GetId()
-
-        gridSizer.Add(item = compResolution,
-                      pos = (row, 0), span = (1, 2))
-
-        #
-        # auto-rendering
-        #
-        row += 1
-        autoRendering = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                    label = _("Enable auto-rendering"),
-                                    name = "IsChecked")
-        autoRendering.SetValue(self.settings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled'))
-        self.winId['display:autoRendering:enabled'] = autoRendering.GetId()
-
-        gridSizer.Add(item = autoRendering,
-                      pos = (row, 0), span = (1, 2))
-        
-        #
-        # auto-zoom
-        #
-        row += 1
-        autoZooming = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                  label = _("Enable auto-zooming to selected map layer"),
-                                  name = "IsChecked")
-        autoZooming.SetValue(self.settings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'))
-        self.winId['display:autoZooming:enabled'] = autoZooming.GetId()
-
-        gridSizer.Add(item = autoZooming,
-                      pos = (row, 0), span = (1, 2))
-
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        panel.SetSizer(border)
-                
-        # bindings
-        fontButton.Bind(wx.EVT_BUTTON, self.OnSetFont)
-        
-        return panel
-
-    def _createCmdPage(self, notebook):
-        """!Create notebook page for commad dialog settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Command"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Command dialog settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        #
-        # command dialog settings
-        #
-        row = 0
-        # overwrite
-        overwrite = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                label = _("Allow output files to overwrite existing files"),
-                                name = "IsChecked")
-        overwrite.SetValue(self.settings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
-        self.winId['cmd:overwrite:enabled'] = overwrite.GetId()
-        
-        gridSizer.Add(item = overwrite,
-                      pos = (row, 0), span = (1, 2))
-        row += 1
-        # close
-        close = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                            label = _("Close dialog when command is successfully finished"),
-                            name = "IsChecked")
-        close.SetValue(self.settings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
-        self.winId['cmd:closeDlg:enabled'] = close.GetId()
-        
-        gridSizer.Add(item = close,
-                      pos = (row, 0), span = (1, 2))
-        row += 1
-        # add layer
-        add = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                          label = _("Add created map into layer tree"),
-                          name = "IsChecked")
-        add.SetValue(self.settings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
-        self.winId['cmd:addNewLayer:enabled'] = add.GetId()
-    
-        gridSizer.Add(item = add,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1
-        # interactive input
-        interactive = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                  label = _("Allow interactive input"),
-                                  name = "IsChecked")
-        interactive.SetValue(self.settings.Get(group = 'cmd', key = 'interactiveInput', subkey = 'enabled'))
-        self.winId['cmd:interactiveInput:enabled'] = interactive.GetId()
-        gridSizer.Add(item = interactive,
-                      pos = (row, 0), span = (1, 2))
-        
-        row += 1
-        # verbosity
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Verbosity level:")),
-                      flag = wx.ALIGN_LEFT |
-                      wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 0))
-        verbosity = wx.Choice(parent = panel, id = wx.ID_ANY, size = (200, -1),
-                              choices = self.settings.Get(group = 'cmd', key = 'verbosity', subkey = 'choices', internal = True),
-                              name = "GetStringSelection")
-        verbosity.SetStringSelection(self.settings.Get(group = 'cmd', key = 'verbosity', subkey = 'selection'))
-        self.winId['cmd:verbosity:selection'] = verbosity.GetId()
-        
-        gridSizer.Add(item = verbosity,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        #
-        # raster settings
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Raster settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        
-        #
-        # raster overlay
-        #
-        row = 0
-        rasterOpaque = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                    label = _("Make null cells opaque"),
-                                    name = 'IsChecked')
-        rasterOpaque.SetValue(self.settings.Get(group = 'cmd', key = 'rasterOpaque', subkey = 'enabled'))
-        self.winId['cmd:rasterOpaque:enabled'] = rasterOpaque.GetId()
-        
-        gridSizer.Add(item = rasterOpaque,
-                      pos = (row, 0), span = (1, 2))
-
-        # default color table
-        row += 1
-        rasterCTCheck = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                    label = _("Default color table"),
-                                    name = 'IsChecked')
-        rasterCTCheck.SetValue(self.settings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'enabled'))
-        self.winId['cmd:rasterColorTable:enabled'] = rasterCTCheck.GetId()
-        rasterCTCheck.Bind(wx.EVT_CHECKBOX, self.OnCheckColorTable)
-        
-        gridSizer.Add(item = rasterCTCheck,
-                      pos = (row, 0))
-        
-        rasterCTName = wx.Choice(parent = panel, id = wx.ID_ANY, size = (200, -1),
-                               choices = utils.GetColorTables(),
-                               name = "GetStringSelection")
-        rasterCTName.SetStringSelection(self.settings.Get(group = 'cmd', key = 'rasterColorTable', subkey = 'selection'))
-        self.winId['cmd:rasterColorTable:selection'] = rasterCTName.GetId()
-        if not rasterCTCheck.IsChecked():
-            rasterCTName.Enable(False)
-        
-        gridSizer.Add(item = rasterCTName,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        #
-        # vector settings
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Vector settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.FlexGridSizer (cols = 7, hgap = 3, vgap = 3)
-        
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Display:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        for type in ('point', 'line', 'centroid', 'boundary',
-                     'area', 'face'):
-            chkbox = wx.CheckBox(parent = panel, label = type)
-            checked = self.settings.Get(group = 'cmd', key = 'showType',
-                                        subkey = [type, 'enabled'])
-            chkbox.SetValue(checked)
-            self.winId['cmd:showType:%s:enabled' % type] = chkbox.GetId()
-            gridSizer.Add(item = chkbox)
-
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createAttributeManagerPage(self, notebook):
-        """!Create notebook page for 'Attribute Table Manager' settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Attributes"))
-
-        pageSizer = wx.BoxSizer(wx.VERTICAL)
-
-        #
-        # highlighting
-        #
-        highlightBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Highlighting"))
-        highlightSizer = wx.StaticBoxSizer(highlightBox, wx.VERTICAL)
-
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Color:"))
-        hlColor = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
-                                    colour = self.settings.Get(group = 'atm', key = 'highlight', subkey = 'color'),
-                                    size = globalvar.DIALOG_COLOR_SIZE)
-        hlColor.SetName('GetColour')
-        self.winId['atm:highlight:color'] = hlColor.GetId()
-
-        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(hlColor, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width (in pixels):"))
-        hlWidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (50, -1),
-                              initial = self.settings.Get(group = 'atm', key = 'highlight',subkey = 'width'),
-                              min = 1, max = 1e6)
-        self.winId['atm:highlight:width'] = hlWidth.GetId()
-
-        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(hlWidth, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        highlightSizer.Add(item = flexSizer,
-                           proportion = 0,
-                           flag = wx.ALL | wx.EXPAND,
-                           border = 5)
-
-        pageSizer.Add(item = highlightSizer,
-                      proportion = 0,
-                      flag = wx.ALL | wx.EXPAND,
-                      border = 5)
-
-        #
-        # data browser related settings
-        #
-        dataBrowserBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Data browser"))
-        dataBrowserSizer = wx.StaticBoxSizer(dataBrowserBox, wx.VERTICAL)
-
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Left mouse double click:"))
-        leftDbClick = wx.Choice(parent = panel, id = wx.ID_ANY,
-                                choices = self.settings.Get(group = 'atm', key = 'leftDbClick', subkey = 'choices', internal = True),
-                                name = "GetSelection")
-        leftDbClick.SetSelection(self.settings.Get(group = 'atm', key = 'leftDbClick', subkey = 'selection'))
-        self.winId['atm:leftDbClick:selection'] = leftDbClick.GetId()
-
-        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(leftDbClick, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        # encoding
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("Encoding (e.g. utf-8, ascii, iso8859-1, koi8-r):"))
-        encoding = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
-                               value = self.settings.Get(group = 'atm', key = 'encoding', subkey = 'value'),
-                               name = "GetValue", size = (200, -1))
-        self.winId['atm:encoding:value'] = encoding.GetId()
-
-        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(encoding, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        # ask on delete record
-        askOnDeleteRec = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                     label = _("Ask when deleting data record(s) from table"),
-                                     name = 'IsChecked')
-        askOnDeleteRec.SetValue(self.settings.Get(group = 'atm', key = 'askOnDeleteRec', subkey = 'enabled'))
-        self.winId['atm:askOnDeleteRec:enabled'] = askOnDeleteRec.GetId()
-
-        flexSizer.Add(askOnDeleteRec, proportion = 0)
-
-        dataBrowserSizer.Add(item = flexSizer,
-                           proportion = 0,
-                           flag = wx.ALL | wx.EXPAND,
-                           border = 5)
-
-        pageSizer.Add(item = dataBrowserSizer,
-                      proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-                      border = 3)
-
-        #
-        # create table
-        #
-        createTableBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Create table"))
-        createTableSizer = wx.StaticBoxSizer(createTableBox, wx.VERTICAL)
-
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("Key column:"))
-        keyColumn = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
-                                size = (250, -1))
-        keyColumn.SetValue(self.settings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
-        self.winId['atm:keycolumn:value'] = keyColumn.GetId()
-        
-        flexSizer.Add(label, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(keyColumn, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        createTableSizer.Add(item = flexSizer,
-                             proportion = 0,
-                             flag = wx.ALL | wx.EXPAND,
-                             border = 5)
-
-        pageSizer.Add(item = createTableSizer,
-                      proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-                      border = 3)
-        
-        panel.SetSizer(pageSizer)
-
-        return panel
-
-    def _createProjectionPage(self, notebook):
-        """!Create notebook page for workspace settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Projection"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #
-        # projections statusbar settings
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Projection statusbar settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(1)
-
-        # epsg
-        row = 0
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("EPSG code:"))
-        epsgCode = wx.ComboBox(parent = panel, id = wx.ID_ANY,
-                               name = "GetValue",
-                               size = (150, -1))
-        self.epsgCodeDict = dict()
-        epsgCode.SetValue(str(self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')))
-        self.winId['projection:statusbar:epsg'] = epsgCode.GetId()
-        
-        gridSizer.Add(item = label,
-                      pos = (row, 0),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = epsgCode,
-                      pos = (row, 1), span = (1, 2))
-        
-        # proj
-        row += 1
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("Proj.4 string (required):"))
-        projString = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
-                                 value = self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'),
-                                 name = "GetValue", size = (400, -1))
-        self.winId['projection:statusbar:proj4'] = projString.GetId()
-
-        gridSizer.Add(item = label,
-                      pos = (row, 0),
-                      flag  =  wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = projString,
-                      pos = (row, 1), span = (1, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        # epsg file
-        row += 1
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("EPSG file:"))
-        projFile = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
-                               value  =  self.settings.Get(group = 'projection', key = 'statusbar', subkey = 'projFile'),
-                               name = "GetValue", size = (400, -1))
-        self.winId['projection:statusbar:projFile'] = projFile.GetId()
-        gridSizer.Add(item = label,
-                      pos = (row, 0),
-                      flag  =  wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = projFile,
-                      pos = (row, 1),
-                      flag  =  wx.ALIGN_CENTER_VERTICAL)
-        
-        # note + button
-        row += 1
-        note = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                             label = _("Load EPSG codes (be patient), enter EPSG code or "
-                                       "insert Proj.4 string directly."))
-        gridSizer.Add(item = note,
-                      span = (1, 2),
-                      pos = (row, 0))
-
-        row += 1
-        epsgLoad = wx.Button(parent = panel, id = wx.ID_ANY,
-                             label = _("&Load EPSG codes"))
-        gridSizer.Add(item = epsgLoad,
-                      flag = wx.ALIGN_RIGHT,
-                      pos = (row, 1))
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        #
-        # format
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Coordinates format"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(2)
-
-        row = 0
-        # ll format
-        ll = wx.RadioBox(parent = panel, id = wx.ID_ANY,
-                         label = " %s " % _("LL projections"),
-                         choices = ["DMS", "DEG"],
-                         name = "GetStringSelection")
-        self.winId['projection:format:ll'] = ll.GetId()
-        if self.settings.Get(group = 'projection', key = 'format', subkey = 'll') == 'DMS':
-            ll.SetSelection(0)
-        else:
-            ll.SetSelection(1)
-        
-        # precision
-        precision =  wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
-                                 min = 0, max = 12,
-                                 name = "GetValue")
-        precision.SetValue(int(self.settings.Get(group = 'projection', key = 'format', subkey = 'precision')))
-        self.winId['projection:format:precision'] = precision.GetId()
-                
-        gridSizer.Add(item = ll,
-                      pos = (row, 0))
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                         label = _("Precision:")),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
-                      border = 20,
-                      pos = (row, 1))
-        gridSizer.Add(item = precision,
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (row, 2))
-        
-        
-        sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-        
-        panel.SetSizer(border)
-
-        # bindings
-        epsgLoad.Bind(wx.EVT_BUTTON, self.OnLoadEpsgCodes)
-        epsgCode.Bind(wx.EVT_COMBOBOX, self.OnSetEpsgCode)
-        epsgCode.Bind(wx.EVT_TEXT_ENTER, self.OnSetEpsgCode)
-        
-        return panel
-
-    def OnCheckColorTable(self, event):
-        """!Set/unset default color table"""
-        win = self.FindWindowById(self.winId['cmd:rasterColorTable:selection'])
-        if event.IsChecked():
-            win.Enable()
-        else:
-            win.Enable(False)
-        
-    def OnLoadEpsgCodes(self, event):
-        """!Load EPSG codes from the file"""
-        win = self.FindWindowById(self.winId['projection:statusbar:projFile'])
-        path = win.GetValue()
-
-        self.epsgCodeDict = utils.ReadEpsgCodes(path)
-        list = self.FindWindowById(self.winId['projection:statusbar:epsg'])
-        if type(self.epsgCodeDict) == type(''):
-            wx.MessageBox(parent = self,
-                          message = _("Unable to read EPSG codes: %s") % self.epsgCodeDict,
-                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            self.epsgCodeDict = dict()
-            list.SetItems([])
-            list.SetValue('')
-            self.FindWindowById(self.winId['projection:statusbar:proj4']).SetValue('')
-            return
-        
-        choices = map(str, self.epsgCodeDict.keys())
-
-        list.SetItems(choices)
-        try:
-            code = int(list.GetValue())
-        except ValueError:
-            code = -1
-        win = self.FindWindowById(self.winId['projection:statusbar:proj4'])
-        if code in self.epsgCodeDict:
-            win.SetValue(self.epsgCodeDict[code][1])
-        else:
-            list.SetSelection(0)
-            code = int(list.GetStringSelection())
-            win.SetValue(self.epsgCodeDict[code][1])
-    
-    def OnSetEpsgCode(self, event):
-        """!EPSG code selected"""
-        winCode = self.FindWindowById(event.GetId())
-        win = self.FindWindowById(self.winId['projection:statusbar:proj4'])
-        if not self.epsgCodeDict:
-            wx.MessageBox(parent = self,
-                          message = _("EPSG code %s not found") % event.GetString(),
-                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            winCode.SetValue('')
-            win.SetValue('')
-        
-        try:
-            code = int(event.GetString())
-        except ValueError:
-            wx.MessageBox(parent = self,
-                          message = _("EPSG code %s not found") % str(code),
-                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            winCode.SetValue('')
-            win.SetValue('')
-        
-        
-        try:
-            win.SetValue(self.epsgCodeDict[code][1].replace('<>', '').strip())
-        except KeyError:
-            wx.MessageBox(parent = self,
-                          message = _("EPSG code %s not found") % str(code),
-                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-            winCode.SetValue('')
-            win.SetValue('')
-        
-    def OnSetFont(self, event):
-        """'Set font' button pressed"""
-        dlg = DefaultFontDialog(parent = self,
-                                title = _('Select default display font'),
-                                style = wx.DEFAULT_DIALOG_STYLE,
-                                type = 'font')
-        
-        if dlg.ShowModal() == wx.ID_OK:
-            # set default font and encoding environmental variables
-            if dlg.font:
-                os.environ["GRASS_FONT"] = dlg.font
-                self.settings.Set(group = 'display', value = dlg.font,
-                                  key = 'font', subkey = 'type')
-
-            if dlg.encoding and \
-                    dlg.encoding != "ISO-8859-1":
-                os.environ["GRASS_ENCODING"] = dlg.encoding
-                self.settings.Set(group = 'display', value = dlg.encoding,
-                                  key = 'font', subkey = 'encoding')
-                
-        dlg.Destroy()
-        
-        event.Skip()
-
-    def OnSetOutputFont(self, event):
-        """'Set output font' button pressed
-        """
-
-        type = self.settings.Get(group = 'appearance', key = 'outputfont', subkey = 'type')   
-                           
-        size = self.settings.Get(group = 'appearance', key = 'outputfont', subkey = 'size')
-        if size == None or size == 0: size = 11
-        size = float(size)
-        if type == None or type == '': type = 'Courier'
-        
-        outfont = wx.Font(size, wx.FONTFAMILY_MODERN, wx.NORMAL, 0, faceName = type)
-        
-        fontdata = wx.FontData()
-        fontdata.EnableEffects(True)
-        fontdata.SetColour('black')
-        fontdata.SetInitialFont(outfont)
-        
-        dlg = wx.FontDialog(self, fontdata)
-        
-        'FIXME: native font dialog does not initialize with current font'
-
-        if dlg.ShowModal() == wx.ID_OK:
-            outdata = dlg.GetFontData()
-            font = outdata.GetChosenFont()
-
-            self.settings.Set(group = 'appearance', value = font.GetFaceName(),
-                                  key = 'outputfont', subkey = 'type')
-            self.settings.Set(group = 'appearance', value = font.GetPointSize(),
-                                  key = 'outputfont', subkey = 'size')
-        dlg.Destroy()
-
-        event.Skip()
-
-class DefaultFontDialog(wx.Dialog):
-    """
-    Opens a file selection dialog to select default font
-    to use in all GRASS displays
-    """
-    def __init__(self, parent, title, id = wx.ID_ANY,
-                 style = wx.DEFAULT_DIALOG_STYLE |
-                 wx.RESIZE_BORDER,
-                 settings = globalSettings,
-                 type = 'font'):
-        
-        self.settings = settings
-        self.type = type
-        
-        wx.Dialog.__init__(self, parent, id, title, style = style)
-
-        panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        self.fontlist = self.GetFonts()
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridSizer.AddGrowableCol(0)
-
-        label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("Select font:"))
-        gridSizer.Add(item = label,
-                      flag = wx.ALIGN_TOP,
-                      pos = (0,0))
-        
-        self.fontlb = wx.ListBox(parent = panel, id = wx.ID_ANY, pos = wx.DefaultPosition,
-                                 choices = self.fontlist,
-                                 style = wx.LB_SINGLE|wx.LB_SORT)
-        self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.fontlb)
-        self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.fontlb)
-
-        gridSizer.Add(item = self.fontlb,
-                flag = wx.EXPAND, pos = (1, 0))
-
-        if self.type == 'font':
-            if "GRASS_FONT" in os.environ:
-                self.font = os.environ["GRASS_FONT"]
-            else:
-                self.font = self.settings.Get(group = 'display',
-                                              key = 'font', subkey = 'type')
-            self.encoding = self.settings.Get(group = 'display',
-                                          key = 'font', subkey = 'encoding')
-
-            label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                  label = _("Character encoding:"))
-            gridSizer.Add(item = label,
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (2, 0))
-
-            self.textentry = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
-                                         value = self.encoding)
-            gridSizer.Add(item = self.textentry,
-                    flag = wx.EXPAND, pos = (3, 0))
-
-            self.textentry.Bind(wx.EVT_TEXT, self.OnEncoding)
-
-        elif self.type == 'outputfont':
-            self.font = self.settings.Get(group = 'appearance',
-                                              key = 'outputfont', subkey = 'type')
-            self.fontsize = self.settings.Get(group = 'appearance',
-                                          key = 'outputfont', subkey = 'size')
-            label = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                              label = _("Font size:"))
-            gridSizer.Add(item = label,
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (2, 0))
-                      
-            self.spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY)
-            if self.fontsize:
-                self.spin.SetValue(self.fontsize)
-            self.spin.Bind(wx.EVT_SPINCTRL, self.OnSizeSpin)
-            self.spin.Bind(wx.EVT_TEXT, self.OnSizeSpin)
-            gridSizer.Add(item = self.spin,
-                      flag = wx.ALIGN_CENTER_VERTICAL,
-                      pos = (3, 0))
-
-        else: 
-            return
-
-        if self.font:
-            self.fontlb.SetStringSelection(self.font, True)
-
-        sizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.EXPAND | wx.ALL,
-                  border = 5)
-
-        border.Add(item = sizer, proportion = 1,
-                   flag = wx.ALL | wx.EXPAND, border = 3)
-        
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(parent = panel, id = wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(parent = panel, id = wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        border.Add(item = btnsizer, proportion = 0,
-                   flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        
-        panel.SetAutoLayout(True)
-        panel.SetSizer(border)
-        border.Fit(self)
-        
-        self.Layout()
-        
-    def EvtRadioBox(self, event):
-        if event.GetInt() == 0:
-            self.fonttype = 'grassfont'
-        elif event.GetInt() == 1:
-            self.fonttype = 'truetype'
-
-        self.fontlist = self.GetFonts(self.fonttype)
-        self.fontlb.SetItems(self.fontlist)
-
-    def OnEncoding(self, event):
-        self.encoding = event.GetString()
-
-    def EvtListBox(self, event):
-        self.font = event.GetString()
-        event.Skip()
-
-    def EvtListBoxDClick(self, event):
-        self.font = event.GetString()
-        event.Skip()
-        
-    def OnSizeSpin(self, event):
-        self.fontsize = self.spin.GetValue()
-        event.Skip()
-    
-    def GetFonts(self):
-        """
-        parses fonts directory or fretypecap file to get a list of fonts for the listbox
-        """
-        fontlist = []
-
-        cmd = ["d.font", "-l"]
-
-        ret = gcmd.RunCommand('d.font',
-                              read = True,
-                              flags = 'l')
-
-        if not ret:
-            return fontlist
-
-        dfonts = ret.splitlines()
-        dfonts.sort(lambda x,y: cmp(x.lower(), y.lower()))
-        for item in range(len(dfonts)):
-           # ignore duplicate fonts and those starting with #
-           if not dfonts[item].startswith('#') and \
-                  dfonts[item] != dfonts[item-1]:
-              fontlist.append(dfonts[item])
-
-        return fontlist
-
-class MapsetAccess(wx.Dialog):
-    """!Controls setting options and displaying/hiding map overlay
-    decorations
-    """
-    def __init__(self, parent, id = wx.ID_ANY,
-                 title = _('Manage access to mapsets'),
-                 size  =  (350, 400),
-                 style  =  wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        wx.Dialog.__init__(self, parent, id, title, size = size, style = style)
-
-        self.all_mapsets_ordered = utils.ListOfMapsets(get = 'ordered')
-        self.accessible_mapsets  = utils.ListOfMapsets(get = 'accessible')
-        self.curr_mapset = grass.gisenv()['MAPSET']
-
-        # make a checklistbox from available mapsets and check those that are active
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        label = wx.StaticText(parent = self, id = wx.ID_ANY,
-                              label = _("Check a mapset to make it accessible, uncheck it to hide it.\n"
-                                        "  Notes:\n"
-                                        "    - The current mapset is always accessible.\n"
-                                        "    - You may only write to the current mapset.\n"
-                                        "    - You may only write to mapsets which you own."))
-        
-        sizer.Add(item = label, proportion = 0,
-                  flag = wx.ALL, border = 5)
-
-        self.mapsetlb = CheckListMapset(parent = self)
-        self.mapsetlb.LoadData()
-        
-        sizer.Add(item = self.mapsetlb, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 5)
-
-        # check all accessible mapsets
-        for mset in self.accessible_mapsets:
-            self.mapsetlb.CheckItem(self.all_mapsets_ordered.index(mset), True)
-
-        # FIXME (howto?): grey-out current mapset
-        #self.mapsetlb.Enable(0, False)
-
-        # dialog buttons
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY,
-                             style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-        okbtn = wx.Button(self, wx.ID_OK)
-        okbtn.SetDefault()
-        btnsizer.AddButton(okbtn)
-
-        cancelbtn = wx.Button(self, wx.ID_CANCEL)
-        btnsizer.AddButton(cancelbtn)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0,
-                  flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        # do layout
-        self.Layout()
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-        self.SetMinSize(size)
-        
-    def GetMapsets(self):
-        """!Get list of checked mapsets"""
-        ms = []
-        i = 0
-        for mset in self.all_mapsets_ordered:
-            if self.mapsetlb.IsChecked(i):
-                ms.append(mset)
-            i += 1
-
-        return ms
-
-class CheckListMapset(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
-    """!List of mapset/owner/group"""
-    def __init__(self, parent, pos = wx.DefaultPosition,
-                 log = None):
-        self.parent = parent
-        
-        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
-                             style = wx.LC_REPORT)
-        listmix.CheckListCtrlMixin.__init__(self)
-        self.log = log
-
-        # setup mixins
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-
-    def LoadData(self):
-        """!Load data into list"""
-        self.InsertColumn(0, _('Mapset'))
-        self.InsertColumn(1, _('Owner'))
-        ### self.InsertColumn(2, _('Group'))
-        gisenv = grass.gisenv()
-        locationPath = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'])
-
-        for mapset in self.parent.all_mapsets_ordered:
-            index = self.InsertStringItem(sys.maxint, mapset)
-            mapsetPath = os.path.join(locationPath,
-                                      mapset)
-            stat_info = os.stat(mapsetPath)
-            if havePwd:
-                self.SetStringItem(index, 1, "%s" % pwd.getpwuid(stat_info.st_uid)[0])
-                # FIXME: get group name
-                ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid) 
-            else:
-                # FIXME: no pwd under MS Windows (owner: 0, group: 0)
-                self.SetStringItem(index, 1, "%-8s" % stat_info.st_uid)
-                ### self.SetStringItem(index, 2, "%-8s" % stat_info.st_gid)
-                
-        self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE)
-        ### self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE)
-        
-    def OnCheckItem(self, index, flag):
-        """!Mapset checked/unchecked"""
-        mapset = self.parent.all_mapsets_ordered[index]
-        if mapset == self.parent.curr_mapset:
-            self.CheckItem(index, True)

Deleted: grass/trunk/gui/wxpython/gui_modules/prompt.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/prompt.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/prompt.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1156 +0,0 @@
-"""!
- at package prompt.py
-
- at brief wxGUI command prompt
-
-Classes:
- - PromptListCtrl
- - TextCtrlAutoComplete
- - GPrompt
- - GPromptPopUp
- - GPromptSTC
-
-(C) 2009-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
- at author Michael Barton <michael.barton at asu.edu>
- at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
-"""
-
-import os
-import sys
-import copy
-import difflib
-import codecs
-
-import wx
-import wx.stc
-import wx.lib.mixins.listctrl as listmix
-
-from grass.script import core as grass
-from grass.script import task as gtask
-
-import globalvar
-import menudata
-import menuform
-import gcmd
-import utils
-
-class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
-    """!PopUp window used by GPromptPopUp"""
-    def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition,
-                 size = wx.DefaultSize, style = 0):
-        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        
-class TextCtrlAutoComplete(wx.ComboBox, listmix.ColumnSorterMixin):
-    """!Auto complete text area used by GPromptPopUp"""
-    def __init__ (self, parent, statusbar,
-                  id = wx.ID_ANY, choices = [], **kwargs):
-        """!Constructor works just like wx.TextCtrl except you can pass in a
-        list of choices.  You can also change the choice list at any time
-        by calling setChoices.
-        
-        Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete
-        """
-        self.statusbar = statusbar
-        
-        if 'style' in kwargs:
-            kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']
-        else:
-            kwargs['style'] = wx.TE_PROCESS_ENTER
-        
-        wx.ComboBox.__init__(self, parent, id, **kwargs)
-        
-        # some variables
-        self._choices = choices
-        self._hideOnNoMatch = True
-        self._module = None      # currently selected module
-        self._choiceType = None  # type of choice (module, params, flags, raster, vector ...)
-        self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
-        self._historyItem = 0   # last item
-        
-        # sort variable needed by listmix
-        self.itemDataMap = dict()
-        
-        # widgets
-        try:
-            self.dropdown = wx.PopupWindow(self)
-        except NotImplementedError:
-            self.Destroy()
-            raise NotImplementedError
-        
-        # create the list and bind the events
-        self.dropdownlistbox = PromptListCtrl(parent = self.dropdown,
-                                              style = wx.LC_REPORT | wx.LC_SINGLE_SEL | \
-                                                  wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER,
-                                              pos = wx.Point(0, 0))
-        
-        listmix.ColumnSorterMixin.__init__(self, 1)
-        
-        # set choices (list of GRASS modules)
-        self._choicesCmd = globalvar.grassCmd['all']
-        self._choicesMap = dict()
-        for type in ('raster', 'vector'):
-            self._choicesMap[type] = grass.list_strings(type = type[:4])
-        # first search for GRASS module
-        self.SetChoices(self._choicesCmd)
-        
-        self.SetMinSize(self.GetSize())
-        
-        # bindings...
-        self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
-        self.Bind(wx.EVT_TEXT, self.OnEnteredText)
-        self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
-        self.Bind(wx.EVT_KEY_DOWN , self.OnKeyDown)
-        ### self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
-
-        # if need drop down on left click
-        self.dropdown.Bind(wx.EVT_LISTBOX , self.OnListItemSelected, self.dropdownlistbox)
-        self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.OnListClick)
-        self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.OnListDClick)
-        self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.OnListColClick)
-
-        self.Bind(wx.EVT_COMBOBOX, self.OnCommandSelect)
-        
-    def _updateDataList(self, choices):
-        """!Update data list"""
-        # delete, if need, all the previous data
-        if self.dropdownlistbox.GetColumnCount() != 0:
-            self.dropdownlistbox.DeleteAllColumns()
-            self.dropdownlistbox.DeleteAllItems()
-        # and update the dict
-        if choices:
-            for numVal, data in enumerate(choices):
-                self.itemDataMap[numVal] = data
-        else:
-            numVal = 0
-        self.SetColumnCount(numVal)
-    
-    def _setListSize(self):
-        """!Set list size"""
-        choices = self._choices
-        longest = 0
-        for choice in choices:
-            longest = max(len(choice), longest)
-        longest += 3
-        itemcount = min(len( choices ), 7) + 2
-        charheight = self.dropdownlistbox.GetCharHeight()
-        charwidth = self.dropdownlistbox.GetCharWidth()
-        self.popupsize = wx.Size(charwidth*longest, charheight*itemcount)
-        self.dropdownlistbox.SetSize(self.popupsize)
-        self.dropdown.SetClientSize(self.popupsize)
-        
-    def _showDropDown(self, show = True):
-        """!Either display the drop down list (show = True) or hide it
-        (show = False).
-        """
-        if show:
-            size = self.dropdown.GetSize()
-            width, height = self.GetSizeTuple()
-            x, y = self.ClientToScreenXY(0, height)
-            if size.GetWidth() != width:
-                size.SetWidth(width)
-                self.dropdown.SetSize(size)
-                self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
-            if (y + size.GetHeight()) < self._screenheight:
-                self.dropdown.SetPosition(wx.Point(x, y))
-            else:
-                self.dropdown.SetPosition(wx.Point(x, y - height - size.GetHeight()))
-        
-        self.dropdown.Show(show)
-    
-    def _listItemVisible(self):
-        """!Moves the selected item to the top of the list ensuring it is
-        always visible.
-        """
-        toSel = self.dropdownlistbox.GetFirstSelected()
-        if toSel == -1:
-            return
-        self.dropdownlistbox.EnsureVisible(toSel)
-
-    def _setModule(self, name):
-        """!Set module's choices (flags, parameters)""" 
-        # get module's description
-        if name in self._choicesCmd and not self._module:
-            try:
-                self._module = gtask.parse_interface(name)
-            except IOError:
-                self._module = None
-             
-        # set choices (flags)
-        self._choicesMap['flag'] = self._module.get_list_flags()
-        for idx in range(len(self._choicesMap['flag'])):
-            item = self._choicesMap['flag'][idx]
-            desc = self._module.get_flag(item)['label']
-            if not desc:
-                desc = self._module.get_flag(item)['description']
-            
-            self._choicesMap['flag'][idx] = '%s (%s)' % (item, desc)
-        
-        # set choices (parameters)
-        self._choicesMap['param'] = self._module.get_list_params()
-        for idx in range(len(self._choicesMap['param'])):
-            item = self._choicesMap['param'][idx]
-            desc = self._module.get_param(item)['label']
-            if not desc:
-                desc = self._module.get_param(item)['description']
-            
-            self._choicesMap['param'][idx] = '%s (%s)' % (item, desc)
-    
-    def _setValueFromSelected(self):
-         """!Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
-         Will do nothing if no item is selected in the wx.ListCtrl.
-         """
-         sel = self.dropdownlistbox.GetFirstSelected()
-         if sel < 0:
-             return
-         
-         if self._colFetch != -1:
-             col = self._colFetch
-         else:
-             col = self._colSearch
-         itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
-         
-         cmd = utils.split(str(self.GetValue()))
-         if len(cmd) > 0 and cmd[0] in self._choicesCmd:
-             # -> append text (skip last item)
-             if self._choiceType == 'param':
-                 itemtext = itemtext.split(' ')[0]
-                 self.SetValue(' '.join(cmd) + ' ' + itemtext + '=')
-                 optType = self._module.get_param(itemtext)['prompt']
-                 if optType in ('raster', 'vector'):
-                     # -> raster/vector map
-                     self.SetChoices(self._choicesMap[optType], optType)
-             elif self._choiceType == 'flag':
-                 itemtext = itemtext.split(' ')[0]
-                 if len(itemtext) > 1:
-                     prefix = '--'
-                 else:
-                     prefix = '-'
-                 self.SetValue(' '.join(cmd[:-1]) + ' ' + prefix + itemtext)
-             elif self._choiceType in ('raster', 'vector'):
-                 self.SetValue(' '.join(cmd[:-1]) + ' ' + cmd[-1].split('=', 1)[0] + '=' + itemtext)
-         else:
-             # -> reset text
-             self.SetValue(itemtext + ' ')
-             
-             # define module
-             self._setModule(itemtext)
-             
-             # use parameters as default choices
-             self._choiceType = 'param'
-             self.SetChoices(self._choicesMap['param'], type = 'param')
-         
-         self.SetInsertionPointEnd()
-         
-         self._showDropDown(False)
-         
-    def GetListCtrl(self):
-        """!Method required by listmix.ColumnSorterMixin"""
-        return self.dropdownlistbox
-    
-    def SetChoices(self, choices, type = 'module'):
-        """!Sets the choices available in the popup wx.ListBox.
-        The items will be sorted case insensitively.
-
-        @param choices list of choices
-        @param type type of choices (module, param, flag, raster, vector)
-        """
-        self._choices = choices
-        self._choiceType = type
-        
-        self.dropdownlistbox.SetWindowStyleFlag(wx.LC_REPORT | wx.LC_SINGLE_SEL |
-                                                wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER)
-        if not isinstance(choices, list):
-            self._choices = [ x for x in choices ]
-        if self._choiceType not in ('raster', 'vector'):
-            # do not sort raster/vector maps
-            utils.ListSortLower(self._choices)
-        
-        self._updateDataList(self._choices)
-        
-        self.dropdownlistbox.InsertColumn(0, "")
-        for num, colVal in enumerate(self._choices):
-            index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
-            self.dropdownlistbox.SetStringItem(index, 0, colVal)
-            self.dropdownlistbox.SetItemData(index, num)
-        self._setListSize()
-        
-        # there is only one choice for both search and fetch if setting a single column:
-        self._colSearch = 0
-        self._colFetch = -1
-
-    def OnClick(self, event):
-        """Left mouse button pressed"""
-        sel = self.dropdownlistbox.GetFirstSelected()
-        if not self.dropdown.IsShown():
-            if sel > -1:
-                self.dropdownlistbox.Select(sel)
-            else:
-                self.dropdownlistbox.Select(0)
-            self._listItemVisible()
-            self._showDropDown()
-        else:
-            self.dropdown.Hide()
-        
-    def OnCommandSelect(self, event):
-        """!Command selected from history"""
-        self._historyItem = event.GetSelection() - len(self.GetItems())
-        self.SetFocus()
-        
-    def OnListClick(self, evt):
-        """!Left mouse button pressed"""
-        toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
-        #no values on poition, return
-        if toSel == -1: return
-        self.dropdownlistbox.Select(toSel)
-
-    def OnListDClick(self, evt):
-        """!Mouse button double click"""
-        self._setValueFromSelected()
-
-    def OnListColClick(self, evt):
-        """!Left mouse button pressed on column"""
-        col = evt.GetColumn()
-        # reverse the sort
-        if col == self._colSearch:
-            self._ascending = not self._ascending
-        self.SortListItems( evt.GetColumn(), ascending=self._ascending )
-        self._colSearch = evt.GetColumn()
-        evt.Skip()
-
-    def OnListItemSelected(self, event):
-        """!Item selected"""
-        self._setValueFromSelected()
-        event.Skip()
-
-    def OnEnteredText(self, event):
-        """!Text entered"""
-        text = event.GetString()
-        
-        if not text:
-            # control is empty; hide dropdown if shown:
-            if self.dropdown.IsShown():
-                self._showDropDown(False)
-            event.Skip()
-            return
-        
-        try:
-            cmd = utils.split(str(text))
-        except ValueError, e:
-            self.statusbar.SetStatusText(str(e))
-            cmd = text.split(' ')
-        pattern = str(text)
-        
-        if len(cmd) > 0 and cmd[0] in self._choicesCmd and not self._module:
-            self._setModule(cmd[0])
-        elif len(cmd) > 1 and cmd[0] in self._choicesCmd:
-            if self._module:
-                if len(cmd[-1].split('=', 1)) == 1:
-                    # new option
-                    if cmd[-1][0] == '-':
-                        # -> flags
-                        self.SetChoices(self._choicesMap['flag'], type = 'flag')
-                        pattern = cmd[-1].lstrip('-')
-                    else:
-                        # -> options
-                        self.SetChoices(self._choicesMap['param'], type = 'param')
-                        pattern = cmd[-1]
-                else:
-                    # value
-                    pattern = cmd[-1].split('=', 1)[1]
-        else:
-            # search for GRASS modules
-            if self._module:
-                # -> switch back to GRASS modules list
-                self.SetChoices(self._choicesCmd)
-                self._module = None
-                self._choiceType = None
-        
-        self._choiceType
-        self._choicesMap
-        found = False
-        choices = self._choices
-        for numCh, choice in enumerate(choices):
-            if choice.lower().startswith(pattern):
-                found = True
-            if found:
-                self._showDropDown(True)
-                item = self.dropdownlistbox.GetItem(numCh)
-                toSel = item.GetId()
-                self.dropdownlistbox.Select(toSel)
-                break
-        
-        if not found:
-            self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
-            if self._hideOnNoMatch:
-                self._showDropDown(False)
-                if self._module and '=' not in cmd[-1]:
-                    message = ''
-                    if cmd[-1][0] == '-': # flag
-                        message = _("Warning: flag <%(flag)s> not found in '%(module)s'") % \
-                            { 'flag' : cmd[-1][1:], 'module' : self._module.name }
-                    else: # option
-                        message = _("Warning: option <%(param)s> not found in '%(module)s'") % \
-                            { 'param' : cmd[-1], 'module' : self._module.name }
-                    self.statusbar.SetStatusText(message)
-        
-        if self._module and len(cmd[-1]) == 2 and cmd[-1][-2] == '=':
-            optType = self._module.get_param(cmd[-1][:-2])['prompt']
-            if optType in ('raster', 'vector'):
-                # -> raster/vector map
-                self.SetChoices(self._choicesMap[optType], optType)
-        
-        self._listItemVisible()
-        
-        event.Skip()
-        
-    def OnKeyDown (self, event):
-        """!Do some work when the user press on the keys: up and down:
-        move the cursor left and right: move the search
-        """
-        skip = True
-        sel = self.dropdownlistbox.GetFirstSelected()
-        visible = self.dropdown.IsShown()
-        KC = event.GetKeyCode()
-        
-        if KC == wx.WXK_RIGHT:
-            # right -> show choices
-            if sel < (self.dropdownlistbox.GetItemCount() - 1):
-                self.dropdownlistbox.Select(sel + 1)
-                self._listItemVisible()
-            self._showDropDown()
-            skip = False
-        elif KC == wx.WXK_UP:
-            if visible:
-                if sel > 0:
-                    self.dropdownlistbox.Select(sel - 1)
-                    self._listItemVisible()
-                self._showDropDown()
-                skip = False
-            else:
-                self._historyItem -= 1
-                try:
-                    self.SetValue(self.GetItems()[self._historyItem])
-                except IndexError:
-                    self._historyItem += 1
-        elif KC == wx.WXK_DOWN:
-            if visible:
-                if sel < (self.dropdownlistbox.GetItemCount() - 1):
-                    self.dropdownlistbox.Select(sel + 1)
-                    self._listItemVisible()
-                self._showDropDown()
-                skip = False
-            else:
-                if self._historyItem < -1:
-                    self._historyItem += 1
-                    self.SetValue(self.GetItems()[self._historyItem])
-        
-        if visible:
-            if event.GetKeyCode() == wx.WXK_RETURN:
-                self._setValueFromSelected()
-                skip = False
-            if event.GetKeyCode() == wx.WXK_ESCAPE:
-                self._showDropDown(False)
-                skip = False
-        if skip:
-            event.Skip()
-        
-    def OnControlChanged(self, event):
-        """!Control changed"""
-        if self.IsShown():
-            self._showDropDown(False)
-        
-        event.Skip()
-
-class GPrompt(object):
-    """!Abstract class for interactive wxGUI prompt
-
-    See subclass GPromptPopUp and GPromptSTC.
-    """
-    def __init__(self, parent):
-        self.parent = parent                 # GMConsole
-        self.panel  = self.parent.GetPanel()
-        
-        if self.parent.parent.GetName() not in ("LayerManager", "Modeler"):
-            self.standAlone = True
-        else:
-            self.standAlone = False
-        
-        # dictionary of modules (description, keywords, ...)
-        if not self.standAlone:
-            if self.parent.parent.GetName() == 'Modeler':
-                self.moduleDesc = menudata.ManagerData().GetModules()
-            else:
-                self.moduleDesc = parent.parent.menubar.GetData().GetModules()
-            self.moduleList = self._getListOfModules()
-            self.mapList = self._getListOfMaps()
-            self.mapsetList = utils.ListOfMapsets()
-        else:
-            self.moduleDesc = self.moduleList = self.mapList = None
-        
-        # auto complete items
-        self.autoCompList   = list()
-        self.autoCompFilter = None
-        
-        # command description (gtask.grassTask)
-        self.cmdDesc = None
-        self.cmdbuffer = self._readHistory()
-        self.cmdindex = len(self.cmdbuffer)
-        
-    def _readHistory(self):
-        """!Get list of commands from history file"""
-        hist = list()
-        env = grass.gisenv()
-        try:
-            fileHistory = codecs.open(os.path.join(env['GISDBASE'],
-                                                   env['LOCATION_NAME'],
-                                                   env['MAPSET'],
-                                                   '.bash_history'),
-                                      encoding = 'utf-8', mode = 'r', errors='replace')
-        except IOError:
-            return hist
-        
-        try:
-            for line in fileHistory.readlines():
-                hist.append(line.replace('\n', ''))
-        finally:
-            fileHistory.close()
-        
-        return hist
-
-    def GetCommandDesc(self, cmd):
-        """!Get description for given command"""
-        if cmd in self.moduleDesc:
-            return self.moduleDesc[cmd]['desc']
-        
-        return ''
-    
-    def GetCommandItems(self):
-        """!Get list of available commands"""
-        items = list()
-        
-        if self.autoCompFilter is not None:
-            mList = self.autoCompFilter
-        else:
-            mList = self.moduleList
-            
-        if not mList:
-            return items
-        
-        prefixes = mList.keys()
-        prefixes.sort()
-        
-        for prefix in prefixes:
-            for command in mList[prefix]:
-                name = prefix + '.' + command
-                if name not in items:
-                    items.append(name)
-                
-        items.sort()
-        
-        return items
-    
-    def _getListOfModules(self):
-        """!Get list of modules"""
-        result = dict()
-        for module in globalvar.grassCmd['all']:
-            try:
-                group, name = module.split('.',1)
-            except ValueError:
-                continue # TODO
-            
-            if group not in result:
-                result[group] = list()
-            result[group].append(name)
-            
-            # for better auto-completion: 
-            # not only result['r']={...,'colors.out',...}, but also result['r.colors']={'out',...}
-            for i in range(len(name.split('.'))-1):
-                group = '.'.join([group,name.split('.',1)[0]])
-                name = name.split('.',1)[1]
-                if group not in result:
-                    result[group] = list()
-                result[group].append(name)
-      
-        # sort list of names
-        for group in result.keys():
-            result[group].sort()
-        
-        return result
-    
-    def _getListOfMaps(self):
-        """!Get list of maps"""
-        result = dict()
-        result['raster'] = grass.list_strings('rast')
-        result['vector'] = grass.list_strings('vect')
-        
-        return result
-
-    def OnRunCmd(self, event):
-        """!Run command"""
-        cmdString = event.GetString()
-        
-        if self.standAlone:
-            return
-        
-        if cmdString[:2] == 'd.' and not self.parent.curr_page:
-            self.parent.NewDisplay(show=True)
-        
-        cmd = utils.split(cmdString)
-        if len(cmd) > 1:
-            self.parent.RunCmd(cmd, switchPage = True)
-        else:
-            self.parent.RunCmd(cmd, switchPage = False)
-        
-        self.OnUpdateStatusBar(None)
-        
-    def OnUpdateStatusBar(self, event):
-        """!Update Layer Manager status bar"""
-        if self.standAlone:
-            return
-        
-        if event is None:
-            self.parent.parent.statusbar.SetStatusText("")
-        else:
-            self.parent.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
-            event.Skip()
-        
-    def GetPanel(self):
-        """!Get main widget panel"""
-        return self.panel
-
-    def GetInput(self):
-        """!Get main prompt widget"""
-        return self.input
-    
-    def SetFilter(self, data, module = True):
-        """!Set filter
-
-        @param data data dict
-        @param module True to filter modules, otherwise data
-        """
-        if module:
-            if data:
-                self.moduleList = data
-            else:
-                self.moduleList = self._getListOfModules()
-        else:
-            if data:
-                self.dataList = data
-            else:
-                self.dataList = self._getListOfMaps()
-        
-class GPromptPopUp(GPrompt, TextCtrlAutoComplete):
-    """!Interactive wxGUI prompt - popup version"""
-    def __init__(self, parent):
-        GPrompt.__init__(self, parent)
-        
-        ### todo: fix TextCtrlAutoComplete to work also on Macs
-        ### reason: missing wx.PopupWindow()
-        try:
-            TextCtrlAutoComplete.__init__(self, parent = self.panel, id = wx.ID_ANY,
-                                          value = "",
-                                          style = wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
-                                          statusbar = self.parent.parent.statusbar)
-            self.SetItems(self._readHistory())
-        except NotImplementedError:
-            # wx.PopupWindow may be not available in wxMac
-            # see http://trac.wxwidgets.org/ticket/9377
-            wx.TextCtrl.__init__(parent = self.panel, id = wx.ID_ANY,
-                                 value = "",
-                                 style=wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
-                                 size = (-1, 25))
-            self.searchBy.Enable(False)
-            self.search.Enable(False)
-        
-        self.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, ''))
-        
-        wx.CallAfter(self.SetInsertionPoint, 0)
-        
-        # bidnings
-        self.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
-        self.Bind(wx.EVT_TEXT,       self.OnUpdateStatusBar)
-        
-    def OnCmdErase(self, event):
-        """!Erase command prompt"""
-        self.input.SetValue('')
-
-class GPromptSTC(GPrompt, wx.stc.StyledTextCtrl):
-    """!Styled wxGUI prompt with autocomplete and calltips"""    
-    def __init__(self, parent, id = wx.ID_ANY, margin = False):
-        GPrompt.__init__(self, parent)
-        wx.stc.StyledTextCtrl.__init__(self, self.panel, id)
-        
-        #
-        # styles
-        #                
-        self.SetWrapMode(True)
-        self.SetUndoCollection(True)        
-        
-        #
-        # create command and map lists for autocompletion
-        #
-        self.AutoCompSetIgnoreCase(False) 
-        
-        #
-        # line margins
-        #
-        # TODO print number only from cmdlog
-        self.SetMarginWidth(1, 0)
-        self.SetMarginWidth(2, 0)
-        if margin:
-            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
-            self.SetMarginWidth(0, 30)
-        else:
-            self.SetMarginWidth(0, 0)
-        
-        #
-        # miscellaneous
-        #
-        self.SetViewWhiteSpace(False)
-        self.SetUseTabs(False)
-        self.UsePopUp(True)
-        self.SetSelBackground(True, "#FFFF00")
-        self.SetUseHorizontalScrollBar(True)
-        
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
-        self.Bind(wx.stc.EVT_STC_AUTOCOMP_SELECTION, self.OnItemSelected)
-        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemChanged)
-        
-    def OnTextSelectionChanged(self, event):
-        """!Copy selected text to clipboard and skip event.
-        The same function is in GMStc class (goutput.py).
-        """
-        self.Copy()
-        event.Skip()
-        
-    def OnItemChanged(self, event):
-        """!Change text in statusbar 
-        if the item selection in the auto-completion list is changed"""
-        # list of commands
-        if self.toComplete['entity'] == 'command':
-            item = self.toComplete['cmd'].rpartition('.')[0] + '.' + self.autoCompList[event.GetIndex()] 
-            try:
-                desc = self.moduleDesc[item]['desc']        
-            except KeyError:
-                desc = '' 
-            self.ShowStatusText(desc)
-        # list of flags    
-        elif self.toComplete['entity'] == 'flags':
-            desc = self.cmdDesc.get_flag(self.autoCompList[event.GetIndex()])['description']
-            self.ShowStatusText(desc)
-        # list of parameters
-        elif self.toComplete['entity'] == 'params':
-            item = self.cmdDesc.get_param(self.autoCompList[event.GetIndex()])
-            desc = item['name'] + '=' + item['type']
-            if not item['required']:
-                desc = '[' + desc + ']'
-            desc += ': ' + item['description']
-            self.ShowStatusText(desc)
-        # list of flags and commands       
-        elif self.toComplete['entity'] == 'params+flags':
-            if self.autoCompList[event.GetIndex()][0] == '-':
-                desc = self.cmdDesc.get_flag(self.autoCompList[event.GetIndex()].strip('-'))['description']
-            else:
-                item = self.cmdDesc.get_param(self.autoCompList[event.GetIndex()])
-                desc = item['name'] + '=' + item['type']
-                if not item['required']:
-                    desc = '[' + desc + ']'
-                desc += ': ' + item['description']
-            self.ShowStatusText(desc)
-        else:
-            self.ShowStatusText('')
-            
-    def OnItemSelected(self, event):
-        """!Item selected from the list"""
-        lastWord = self.GetWordLeft()
-        # to insert selection correctly if selected word partly matches written text
-        match = difflib.SequenceMatcher(None, event.GetText(), lastWord)
-        matchTuple = match.find_longest_match(0, len(event.GetText()), 0, len(lastWord))
-    
-        compl = event.GetText()[matchTuple[2]:]
-        text = self.GetTextLeft() + compl
-        # add space or '=' at the end
-        end = '='
-        for char in ('.','-','='):
-            if text.split(' ')[-1].find(char) >= 0:
-                end = ' '
-        
-        compl += end
-        text += end
-
-        self.AddText(compl)
-        pos = len(text)
-        self.SetCurrentPos(pos)
-        
-        cmd = text.strip().split(' ')[0]
-
-        if not self.cmdDesc or cmd != self.cmdDesc.get_name():
-            if cmd in ('r.mapcalc', 'r3.mapcalc') and \
-                    self.parent.parent.GetName() == 'LayerManager':
-                self.parent.parent.OnMapCalculator(event = None, cmd = [cmd])
-                # add command to history & clean prompt
-                self.UpdateCmdHistory([cmd])
-                self.OnCmdErase(None)
-            else:
-                try:
-                    self.cmdDesc = gtask.parse_interface(cmd)
-                except IOError:
-                    self.cmdDesc = None
-        
-    def UpdateCmdHistory(self, cmd):
-        """!Update command history
-        
-        @param cmd command given as a list
-        """
-        # add command to history    
-        self.cmdbuffer.append(' '.join(cmd))
-        
-        # keep command history to a managable size
-        if len(self.cmdbuffer) > 200:
-            del self.cmdbuffer[0]
-        self.cmdindex = len(self.cmdbuffer)
-        
-    def EntityToComplete(self):
-        """!Determines which part of command (flags, parameters) should
-        be completed at current cursor position"""
-        entry = self.GetTextLeft()
-        toComplete = dict()
-        try:
-            cmd = entry.split()[0].strip()
-        except IndexError:
-            return None
-        
-        if len(utils.split(str(entry))) > 1:
-            if cmd in globalvar.grassCmd['all']:
-                toComplete['cmd'] = cmd
-                if entry[-1] == ' ':
-                    words = entry.split(' ')
-                    if any(word.startswith('-') for word in words):
-                        toComplete['entity'] = 'params'
-                    else:
-                        toComplete['entity'] = 'params+flags'
-                else:
-                    # get word left from current position
-                    word = self.GetWordLeft(withDelimiter = True)
-                    
-                    if word[0] == '=' and word[-1] == '@':
-                        toComplete['entity'] = 'mapsets'
-                    elif word[0] == '=':
-                        # get name of parameter
-                        paramName = self.GetWordLeft(withDelimiter = False, ignoredDelimiter = '=').strip('=')
-                        if paramName:
-                            try:
-                                param = self.cmdDesc.get_param(paramName)
-                            except (ValueError, AttributeError):
-                                return None
-                        else:
-                            return None
-                        
-                        if param['values']:
-                            toComplete['entity'] = 'param values'
-                        elif param['prompt'] == 'raster' and param['element'] == 'cell':
-                            toComplete['entity'] = 'raster map'
-                        elif param['prompt'] == 'vector' and param['element'] == 'vector':
-                            toComplete['entity'] = 'vector map'
-                    elif word[0] == '-':
-                        toComplete['entity'] = 'flags'
-                    elif word[0] == ' ':
-                        toComplete['entity'] = 'params'
-            else:
-                return None
-        else:
-            toComplete['entity'] = 'command'
-            toComplete['cmd'] = cmd
-        
-        return toComplete
-    
-    def GetWordLeft(self, withDelimiter = False, ignoredDelimiter = None):
-        """!Get word left from current cursor position. The beginning
-        of the word is given by space or chars: .,-= 
-        
-        @param withDelimiter returns the word with the initial delimeter
-        @param ignoredDelimiter finds the word ignoring certain delimeter
-        """
-        textLeft = self.GetTextLeft()
-        
-        parts = list()
-        if ignoredDelimiter is None:
-            ignoredDelimiter = ''
-        
-        for char in set(' .,-=') - set(ignoredDelimiter):
-            if not withDelimiter:
-                delimiter = ''
-            else:
-                delimiter = char
-            parts.append(delimiter + textLeft.rpartition(char)[2])
-        return min(parts, key=lambda x: len(x))
-         
-    def ShowList(self):
-        """!Show sorted auto-completion list if it is not empty"""
-        if len(self.autoCompList) > 0:
-            self.autoCompList.sort()
-            self.AutoCompShow(lenEntered = 0, itemList = ' '.join(self.autoCompList))    
-        
-    def OnKeyPressed(self, event):
-        """!Key press capture for autocompletion, calltips, and command history
-
-        @todo event.ControlDown() for manual autocomplete
-        """
-        # keycodes used: "." = 46, "=" = 61, "-" = 45 
-        pos = self.GetCurrentPos()
-        #complete command after pressing '.'
-        if event.GetKeyCode() == 46 and not event.ShiftDown():
-            self.autoCompList = list()
-            entry = self.GetTextLeft()
-            self.InsertText(pos, '.')
-            self.CharRight()
-            self.toComplete = self.EntityToComplete()
-            try:
-                if self.toComplete['entity'] == 'command': 
-                    self.autoCompList = self.moduleList[entry.strip()]
-            except (KeyError, TypeError):
-                return
-            self.ShowList()
-
-        # complete flags after pressing '-'       
-        elif event.GetKeyCode() == 45 and not event.ShiftDown(): 
-            self.autoCompList = list()
-            entry = self.GetTextLeft()
-            self.InsertText(pos, '-')
-            self.CharRight()
-            self.toComplete = self.EntityToComplete()
-            if self.toComplete['entity'] == 'flags' and self.cmdDesc:
-                if self.GetTextLeft()[-2:] == ' -': # complete e.g. --quite
-                    for flag in self.cmdDesc.get_options()['flags']:
-                        if len(flag['name']) == 1:
-                            self.autoCompList.append(flag['name'])
-                else:
-                    for flag in self.cmdDesc.get_options()['flags']:
-                        if len(flag['name']) > 1:
-                            self.autoCompList.append(flag['name'])            
-            self.ShowList()
-            
-        # complete map or values after parameter
-        elif event.GetKeyCode() == 61 and not event.ShiftDown():
-            self.autoCompList = list()
-            self.InsertText(pos, '=')
-            self.CharRight()
-            self.toComplete = self.EntityToComplete()
-            if self.toComplete and 'entity' in self.toComplete:
-                if self.toComplete['entity'] == 'raster map':
-                    self.autoCompList = self.mapList['raster']
-                elif self.toComplete['entity'] == 'vector map':
-                    self.autoCompList = self.mapList['vector']
-                elif self.toComplete['entity'] == 'param values':
-                    param = self.GetWordLeft(withDelimiter = False, ignoredDelimiter='=').strip(' =')
-                    self.autoCompList = self.cmdDesc.get_param(param)['values']
-            self.ShowList()
-        
-        # complete mapset ('@')
-        elif event.GetKeyCode() == 50 and event.ShiftDown():
-            self.autoCompList = list()
-            self.InsertText(pos, '@')
-            self.CharRight()
-            self.toComplete = self.EntityToComplete()
-            
-            if self.toComplete and self.toComplete['entity'] == 'mapsets':
-                self.autoCompList = self.mapsetList
-            self.ShowList()
-            
-        # complete after pressing CTRL + Space          
-        elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
-            self.autoCompList = list()
-            self.toComplete = self.EntityToComplete()
-            if self.toComplete is None:
-                return 
-
-            #complete command
-            if self.toComplete['entity'] == 'command':
-                for command in globalvar.grassCmd['all']:
-                    if command.find(self.toComplete['cmd']) == 0:
-                        dotNumber = list(self.toComplete['cmd']).count('.') 
-                        self.autoCompList.append(command.split('.',dotNumber)[-1])
-                
-            
-            # complete flags in such situations (| is cursor):
-            # r.colors -| ...w, q, l
-            # r.colors -w| ...w, q, l  
-            elif self.toComplete['entity'] == 'flags' and self.cmdDesc:
-                for flag in self.cmdDesc.get_options()['flags']:
-                    if len(flag['name']) == 1:
-                        self.autoCompList.append(flag['name'])
-                    
-            # complete parameters in such situations (| is cursor):
-            # r.colors -w | ...color, map, rast, rules
-            # r.colors col| ...color
-            elif self.toComplete['entity'] == 'params' and self.cmdDesc:
-                for param in self.cmdDesc.get_options()['params']:
-                    if param['name'].find(self.GetWordLeft(withDelimiter=False)) == 0:
-                        self.autoCompList.append(param['name'])           
-            
-            # complete flags or parameters in such situations (| is cursor):
-            # r.colors | ...-w, -q, -l, color, map, rast, rules
-            # r.colors color=grey | ...-w, -q, -l, color, map, rast, rules
-            elif self.toComplete['entity'] == 'params+flags' and self.cmdDesc:
-                self.autoCompList = list()
-                
-                for param in self.cmdDesc.get_options()['params']:
-                    self.autoCompList.append(param['name'])
-                for flag in self.cmdDesc.get_options()['flags']:
-                    if len(flag['name']) == 1:
-                        self.autoCompList.append('-' + flag['name'])
-                    else:
-                        self.autoCompList.append('--' + flag['name'])
-                    
-                self.ShowList() 
-                   
-            # complete map or values after parameter  
-            # r.buffer input=| ...list of raster maps
-            # r.buffer units=| ... feet, kilometers, ...   
-            elif self.toComplete['entity'] == 'raster map':
-                self.autoCompList = list()
-                self.autoCompList = self.mapList['raster']
-            elif self.toComplete['entity'] == 'vector map':
-                self.autoCompList = list()
-                self.autoCompList = self.mapList['vector']
-            elif self.toComplete['entity'] == 'param values':
-                self.autoCompList = list()
-                param = self.GetWordLeft(withDelimiter = False, ignoredDelimiter='=').strip(' =')
-                self.autoCompList = self.cmdDesc.get_param(param)['values']
-                
-            self.ShowList()
-
-        elif event.GetKeyCode() == wx.WXK_TAB:
-            # show GRASS command calltips (to hide press 'ESC')
-            entry = self.GetTextLeft()
-            try:
-                cmd = entry.split()[0].strip()
-            except IndexError:
-                cmd = ''
-            
-            if cmd not in globalvar.grassCmd['all']:
-                return
-            
-            info = gtask.command_info(cmd)
-            
-            self.CallTipSetBackground("#f4f4d1")
-            self.CallTipSetForeground("BLACK")
-            self.CallTipShow(pos, info['usage'] + '\n\n' + info['description'])
-            
-            
-        elif event.GetKeyCode() in [wx.WXK_UP, wx.WXK_DOWN] and \
-                 not self.AutoCompActive():
-            # Command history using up and down   
-            if len(self.cmdbuffer) < 1:
-                return
-            
-            self.DocumentEnd()
-            
-            # move through command history list index values
-            if event.GetKeyCode() == wx.WXK_UP:
-                self.cmdindex = self.cmdindex - 1
-            if event.GetKeyCode() == wx.WXK_DOWN:
-                self.cmdindex = self.cmdindex + 1
-            if self.cmdindex < 0:
-                self.cmdindex = 0
-            if self.cmdindex > len(self.cmdbuffer) - 1:
-                self.cmdindex = len(self.cmdbuffer) - 1
-            
-            try:
-                txt = self.cmdbuffer[self.cmdindex]
-            except:
-                txt = ''
-            
-            # clear current line and insert command history    
-            self.DelLineLeft()
-            self.DelLineRight()
-            pos = self.GetCurrentPos()            
-            self.InsertText(pos,txt)
-            self.LineEnd()
-            self.parent.parent.statusbar.SetStatusText('')
-            
-        elif event.GetKeyCode() == wx.WXK_RETURN and \
-                self.AutoCompActive() == False:
-            # run command on line when <return> is pressed
-            
-            if self.parent.GetName() == "ModelerDialog":
-                self.parent.OnOk(None)
-                return
-            
-            # find the command to run
-            line = self.GetCurLine()[0].strip()
-            if len(line) == 0:
-                return
-            
-            # parse command into list
-            try:
-                cmd = utils.split(str(line))
-            except UnicodeError:
-                cmd = utils.split(utils.EncodeString((line)))
-            cmd = map(utils.DecodeString, cmd)
-            
-            #  send the command list to the processor 
-            if cmd[0] in ('r.mapcalc', 'r3.mapcalc') and len(cmd) == 1:
-                self.parent.parent.OnMapCalculator(event = None, cmd = cmd)
-            else:
-                self.parent.RunCmd(cmd)
-            
-            # add command to history & clean prompt
-            self.UpdateCmdHistory(cmd)
-            self.OnCmdErase(None)
-            self.parent.parent.statusbar.SetStatusText('')
-            
-        elif event.GetKeyCode() == wx.WXK_SPACE:
-            items = self.GetTextLeft().split()
-            if len(items) == 1:
-                cmd = items[0].strip()
-                if cmd in globalvar.grassCmd['all'] and \
-                        cmd != 'r.mapcalc' and \
-                        (not self.cmdDesc or cmd != self.cmdDesc.get_name()):
-                    try:
-                        self.cmdDesc = gtask.parse_interface(cmd)
-                    except IOError:
-                        self.cmdDesc = None
-            event.Skip()
-        
-        else:
-            event.Skip()
-
-    def ShowStatusText(self, text):
-        """!Sets statusbar text, if it's too long, it is cut off"""
-        maxLen = self.parent.parent.statusbar.GetFieldRect(0).GetWidth()/ 7 # any better way?
-        if len(text) < maxLen:
-            self.parent.parent.statusbar.SetStatusText(text)
-        else:
-            self.parent.parent.statusbar.SetStatusText(text[:maxLen]+'...')
-        
-        
-    def GetTextLeft(self):
-        """!Returns all text left of the caret"""
-        pos = self.GetCurrentPos()
-        self.HomeExtend()
-        entry = self.GetSelectedText()
-        self.SetCurrentPos(pos)
-        
-        return entry
-    
-    def OnDestroy(self, event):
-        """!The clipboard contents can be preserved after
-        the app has exited"""
-        wx.TheClipboard.Flush()
-        event.Skip()
-
-    def OnCmdErase(self, event):
-        """!Erase command prompt"""
-        self.Home()
-        self.DelLineRight()

Deleted: grass/trunk/gui/wxpython/gui_modules/psmap.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/psmap.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/psmap.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1806 +0,0 @@
-"""!
- at package psmap.py
-
- at brief GUI for ps.map
-
-Classes:
- - PsMapFrame
- - PsMapBufferedWindow
-
-(C) 2011 by Anna Kratochvilova, and 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 Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
- at author Martin Landa <landa.martin gmail.com> (mentor)
-"""
-
-import os
-import sys
-import textwrap
-import Queue
-try:
-    import Image as PILImage
-    havePILImage = True
-except ImportError:
-    havePILImage = False
-from math import sin, cos, pi
-
-import grass.script as grass
-if int(grass.version()['version'].split('.')[0]) > 6:
-    sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython',
-                                 'gui_modules'))
-else:
-    sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython',
-                                 'gui_modules'))
-import globalvar
-import menu
-from   goutput    import CmdThread, EVT_CMD_DONE
-from   menudata   import PsMapData
-from   toolbars   import PsMapToolbar
-from   icon       import Icons, MetaIcon, iconSet
-from   gcmd       import RunCommand, GError, GMessage
-from   menuform   import GUI
-from psmap_dialogs import *
-
-import wx
-
-try:
-    import wx.lib.agw.flatnotebook as fnb
-except ImportError:
-    import wx.lib.flatnotebook as fnb
-    
-class PsMapFrame(wx.Frame):
-    def __init__(self, parent = None, id = wx.ID_ANY,
-                 title = _("GRASS GIS Cartographic Composer"), **kwargs):
-        """!Main window of ps.map GUI
-        
-        @param parent parent window
-        @param id window id
-        @param title window title
-        
-        @param kwargs wx.Frames' arguments
-        """
-        self.parent = parent
-
-        wx.Frame.__init__(self, parent = parent, id = id, title = title, name = "PsMap", **kwargs)
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        #menubar
-        self.menubar = menu.Menu(parent = self, data = PsMapData())
-        self.SetMenuBar(self.menubar)
-        #toolbar
-
-        self.toolbar = PsMapToolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-        
-        self.actionOld = self.toolbar.action['id']
-        self.iconsize = (16, 16)
-        #satusbar
-        self.statusbar = self.CreateStatusBar(number = 1)
-        
-        # mouse attributes -- position on the screen, begin and end of
-        # dragging, and type of drawing
-        self.mouse = {
-            'begin': [0, 0], # screen coordinates
-            'end'  : [0, 0],
-            'use'  : "pointer",
-            }
-        # available cursors
-        self.cursors = {
-            "default" : wx.StockCursor(wx.CURSOR_ARROW),
-            "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
-            "hand"    : wx.StockCursor(wx.CURSOR_HAND),
-            "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
-            }
-        # pen and brush
-        self.pen = {
-            'paper': wx.Pen(colour = "BLACK", width = 1),
-            'margins': wx.Pen(colour = "GREY", width = 1),
-            'map': wx.Pen(colour = wx.Color(86, 122, 17), width = 2),
-            'rasterLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
-            'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
-            'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
-            'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
-            'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
-            'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
-            'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
-            'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
-            'resize': wx.Pen(colour = 'BLACK', width = 1)
-            }
-        self.brush = {
-            'paper': wx.WHITE_BRUSH,
-            'margins': wx.TRANSPARENT_BRUSH,
-            'map': wx.Brush(wx.Color(151, 214, 90)),
-            'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
-            'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
-            'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
-            'scalebar': wx.Brush(wx.Color(200, 200, 200)),
-            'image': wx.Brush(wx.Color(255, 200, 50)),
-            'northArrow': wx.Brush(wx.Color(255, 255, 255)),
-            'box': wx.TRANSPARENT_BRUSH,
-            'select':wx.TRANSPARENT_BRUSH,
-            'resize': wx.BLACK_BRUSH
-            } 
-        
-
-        # list of objects to draw
-        self.objectId = []
-        
-        # instructions
-        self.instruction = Instruction(parent = self, objectsToDraw = self.objectId)
-        # open dialogs
-        self.openDialogs = dict()
-        
-        self.pageId = wx.NewId()
-        #current page of flatnotebook
-        self.currentPage = 0
-        #canvas for draft mode
-        self.canvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, pen = self.pen,
-                                          brush = self.brush, cursors = self.cursors, 
-                                          instruction = self.instruction, openDialogs = self.openDialogs,
-                                          pageId = self.pageId, objectId = self.objectId,
-                                          preview = False)
-        
-        self.canvas.SetCursor(self.cursors["default"])
-        self.getInitMap()
-        
-        
-        # image path
-        env = grass.gisenv()
-        self.imgName = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], '.tmp', 'tmpImage.png')
-        
-        #canvas for preview
-        self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
-                                                 pen = self.pen, brush = self.brush, preview = True)
-        
-        # set WIND_OVERRIDE
-        grass.use_temp_region()
-        
-        # create queues
-        self.requestQ = Queue.Queue()
-        self.resultQ = Queue.Queue()
-        # thread
-        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
-        
-        self._layout()
-        self.SetMinSize(wx.Size(750, 600))
-        
-        self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
-        self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
-        
-        if not havePILImage:
-            wx.CallAfter(self._showErrMsg)
-        
-    def _showErrMsg(self):
-        """!Show error message (missing preview)
-        """
-        GError(parent = self,
-               message = _("Python Imaging Library is not available.\n"
-                           "'Preview' functionality won't work."),
-               showTraceback = False)
-        
-    def _layout(self):
-        """!Do layout
-        """
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        if globalvar.hasAgw:
-            self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
-                                         agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
-                                         fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
-        else:
-            self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
-                                         style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
-                                         fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
-        #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
-        self.book.AddPage(self.canvas, "Draft mode")
-        self.book.AddPage(self.previewCanvas, "Preview")
-        self.book.SetSelection(0)
-        
-        mainSizer.Add(self.book,1, wx.EXPAND)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-        
-    def InstructionFile(self):
-        """!Creates mapping instructions"""
-        
-        return str(self.instruction)
-
-    def OnPSFile(self, event):
-        """!Generate PostScript"""
-        filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
-        if filename:
-            self.PSFile(filename)
-    
-    def OnPsMapDialog(self, event):
-        """!Launch ps.map dialog
-        """
-        GUI(parent = self).ParseCommand(cmd = ['ps.map'])
-
-    def OnPDFFile(self, event):
-        """!Generate PDF from PS with ps2pdf if available"""
-        try:
-            p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
-            p.stderr.close()
-        
-        except OSError:
-            GMessage(parent = self,
-                     message = _("Program ps2pdf is not available. Please install it first to create PDF."))
-            return
-        
-        filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
-        if filename:  
-            self.PSFile(filename, pdf = True)   
-            
-    def OnPreview(self, event):
-        """!Run ps.map and show result"""
-        self.PSFile()
-        
-    def PSFile(self, filename = None, pdf = False):
-        """!Create temporary instructions file and run ps.map with output = filename"""
-        instrFile = grass.tempfile()
-        instrFileFd = open(instrFile, mode = 'w')
-        instrFileFd.write(self.InstructionFile())
-        instrFileFd.flush()
-        instrFileFd.close()
-        
-        temp = False
-        regOld = grass.region()
-        
-        if pdf:
-            pdfname = filename
-        else:
-            pdfname = None
-        #preview or pdf
-        if not filename or (filename and pdf):
-            temp = True
-            filename = grass.tempfile()
-            if not pdf: # lower resolution for preview
-                if self.instruction.FindInstructionByType('map'):
-                    mapId = self.instruction.FindInstructionByType('map').id
-                    SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
-                                  height = self.instruction[mapId]['rect'][3])
-        
-        cmd = ['ps.map', '--overwrite']
-        if os.path.splitext(filename)[1] == '.eps':
-            cmd.append('-e')
-        if self.instruction[self.pageId]['Orientation'] == 'Landscape':
-            cmd.append('-r')
-        cmd.append('input=%s' % instrFile)
-        cmd.append('output=%s' % filename)
-        if pdf:
-            self.SetStatusText(_('Generating PDF...'), 0)
-        elif not temp:
-            self.SetStatusText(_('Generating PostScript...'), 0)
-        else:
-            self.SetStatusText(_('Generating preview...'), 0)
-            
-        self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
-                                               'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
-        
-    def OnCmdDone(self, event):
-        """!ps.map process finished"""
-        
-        if event.returncode != 0:
-            GMessage(parent = self,
-                     message = _("Ps.map exited with return code %s") % event.returncode)
-            
-            grass.try_remove(event.userData['instrFile'])
-            if event.userData['temp']:
-                grass.try_remove(event.userData['filename']) 
-            return
-        
-        if event.userData['pdfname']:
-            try:
-                proc = grass.Popen(['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200', 
-                                    event.userData['filename'], event.userData['pdfname']])
-                
-                ret = proc.wait()                        
-                if ret > 0:
-                    GMessage(parent = self,
-                             message = _("ps2pdf exited with return code %s") % ret)
-
-            except OSError, e:
-                GError(parent = self,
-                       message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
-                
-        # show preview only when user doesn't want to create ps or pdf 
-        if havePILImage and event.userData['temp'] and not event.userData['pdfname']:
-            RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
-## wx.BusyInfo does not display the message
-##            busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
-
-            try:
-                im = PILImage.open(event.userData['filename'])
-                if self.instruction[self.pageId]['Orientation'] == 'Landscape':
-                    im = im.rotate(270)
-                
-                im.save(self.imgName, format = 'png')
-                
-            except IOError, e:
-                GError(parent = self,
-                       message = _("Unable to generate preview. %s") % e)
-            
-            
-                
-            rect = self.previewCanvas.ImageRect()
-            self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
-            self.previewCanvas.DrawImage(rect = rect)
-            
-##            busy.Destroy()
-            self.SetStatusText(_('Preview generated'), 0)
-            self.book.SetSelection(1)
-            self.currentPage = 1
-        
-        grass.try_remove(event.userData['instrFile'])
-        if event.userData['temp']:
-            grass.try_remove(event.userData['filename'])
-        
-    def getFile(self, wildcard):
-        suffix = []
-        for filter in wildcard.split('|')[1::2]:
-            s = filter.strip('*').split('.')[1]
-            if s:
-                s = '.' + s
-            suffix.append(s)
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            rasterId = raster.id 
-        else:
-            rasterId = None
-
-
-        if rasterId and self.instruction[rasterId]['raster']:
-            mapName = self.instruction[rasterId]['raster'].split('@')[0] + suffix[0]
-        else:
-            mapName = ''
-            
-        filename = ''
-        dlg = wx.FileDialog(self, message = _("Save file as"), defaultDir = "", 
-                            defaultFile = mapName, wildcard = wildcard,
-                            style = wx.CHANGE_DIR | wx.SAVE | wx.OVERWRITE_PROMPT)
-        if dlg.ShowModal() == wx.ID_OK:
-            filename = dlg.GetPath()
-            suffix = suffix[dlg.GetFilterIndex()]
-            if not os.path.splitext(filename)[1]:
-                filename = filename + suffix
-            elif os.path.splitext(filename)[1] != suffix and suffix != '':
-                filename = os.path.splitext(filename)[0] + suffix
-            
-        dlg.Destroy()
-        return filename
-    
-    def OnInstructionFile(self, event):
-        filename = self.getFile(wildcard = "*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")        
-        if filename:    
-            instrFile = open(filename, "w")
-            instrFile.write(self.InstructionFile())
-            instrFile.close()   
-            
-    def OnLoadFile(self, event):
-        """!Load file and read instructions"""
-        #find file
-        filename = ''
-        dlg = wx.FileDialog(self, message = "Find instructions file", defaultDir = "", 
-                            defaultFile = '', wildcard = "All files (*.*)|*.*",
-                            style = wx.CHANGE_DIR|wx.OPEN)
-        if dlg.ShowModal() == wx.ID_OK:
-            filename = dlg.GetPath()
-        dlg.Destroy()
-        if not filename:
-            return
-        # load instructions
-        readObjectId = []
-        readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
-        ok = readInstruction.Read(filename)
-        if not ok:
-            GMessage(_("Failed to read file %s.") % filename)
-        else:
-            self.instruction = self.canvas.instruction = readInstruction
-            self.objectId = self.canvas.objectId = readObjectId
-            self.pageId = self.canvas.pageId = self.instruction.FindInstructionByType('page').id
-            self.canvas.UpdateMapLabel()
-            self.canvas.dragId = -1
-            self.canvas.Clear()
-            self.canvas.SetPage()
-            #self.canvas.ZoomAll()
-            
-            self.DialogDataChanged(self.objectId)
-            
-    def OnPageSetup(self, event = None):
-        """!Specify paper size, margins and orientation"""
-        id = self.instruction.FindInstructionByType('page').id
-        dlg = PageSetupDialog(self, id = id, settings = self.instruction) 
-        dlg.CenterOnScreen()
-        val = dlg.ShowModal()
-        if val == wx.ID_OK:
-            self.canvas.SetPage()
-            self.getInitMap()
-            self.canvas.RecalculatePosition(ids = self.objectId)
-        dlg.Destroy()
-        
-    def OnPointer(self, event):
-        self.toolbar.OnTool(event)
-        self.mouse["use"] = "pointer"
-        self.canvas.SetCursor(self.cursors["default"])
-        self.previewCanvas.SetCursor(self.cursors["default"])
-        
-    def OnPan(self, event):
-        self.toolbar.OnTool(event)
-        self.mouse["use"] = "pan"
-        self.canvas.SetCursor(self.cursors["hand"])
-        self.previewCanvas.SetCursor(self.cursors["hand"])
-        
-    def OnZoomIn(self, event):
-        self.toolbar.OnTool(event)
-        self.mouse["use"] = "zoomin"
-        self.canvas.SetCursor(self.cursors["cross"])
-        self.previewCanvas.SetCursor(self.cursors["cross"])
-        
-    def OnZoomOut(self, event):
-        self.toolbar.OnTool(event)
-        self.mouse["use"] = "zoomout"
-        self.canvas.SetCursor(self.cursors["cross"])
-        self.previewCanvas.SetCursor(self.cursors["cross"])
-        
-    def OnZoomAll(self, event):
-        self.mouseOld = self.mouse['use']
-        if self.currentPage == 0:
-            self.cursorOld = self.canvas.GetCursor() 
-        else:
-            self.cursorOld = self.previewCanvas.GetCursor()
-            self.previewCanvas.GetCursor()
-        self.mouse["use"] = "zoomin"
-        if self.currentPage == 0:
-            self.canvas.ZoomAll()
-        else:
-            self.previewCanvas.ZoomAll()
-        self.mouse["use"] = self.mouseOld 
-        if self.currentPage == 0:
-            self.canvas.SetCursor(self.cursorOld)
-        else:
-            self.previewCanvas.SetCursor(self.cursorOld)
-        
-        
-    def OnAddMap(self, event, notebook = False):
-        """!Add or edit map frame"""
-        if event is not None:
-            if event.GetId() != self.toolbar.action['id']:
-                self.actionOld = self.toolbar.action['id']
-                self.mouseOld = self.mouse['use']
-                self.cursorOld = self.canvas.GetCursor()
-            self.toolbar.OnTool(event)
-        
-        if self.instruction.FindInstructionByType('map'):
-            mapId = self.instruction.FindInstructionByType('map').id
-        else: mapId = None
-        id = [mapId, None, None]
-        
-        if notebook:
-            if self.instruction.FindInstructionByType('vector'):
-                vectorId = self.instruction.FindInstructionByType('vector').id
-            else: vectorId = None
-            if self.instruction.FindInstructionByType('raster'):
-                rasterId = self.instruction.FindInstructionByType('raster').id
-            else: rasterId = None
-            id[1] = rasterId
-            id[2] = vectorId
-        
-        
-        if mapId: # map exists
-            
-            self.toolbar.ToggleTool(self.actionOld, True)
-            self.toolbar.ToggleTool(self.toolbar.action['id'], False)
-            self.toolbar.action['id'] = self.actionOld
-            try:
-                self.canvas.SetCursor(self.cursorOld) 
-            except AttributeError:
-                pass
-            
-##            dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
-##                            notebook = notebook)
-##            dlg.ShowModal()  
-            if notebook:
-                #check map, raster, vector and save, destroy them
-                if 'map' in self.openDialogs:
-                    self.openDialogs['map'].OnOK(event = None)
-                if 'raster' in self.openDialogs:
-                    self.openDialogs['raster'].OnOK(event = None)
-                if 'vector' in self.openDialogs:
-                    self.openDialogs['vector'].OnOK(event = None)
-                    
-                if 'mapNotebook' not in self.openDialogs:
-                    dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
-                                    notebook = notebook)
-                    self.openDialogs['mapNotebook'] = dlg
-                self.openDialogs['mapNotebook'].Show()
-            else:
-                if 'mapNotebook' in self.openDialogs:
-                    self.openDialogs['mapNotebook'].notebook.ChangeSelection(0)
-                else:
-                    if 'map' not in self.openDialogs:
-                        dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
-                                        notebook = notebook)
-                        self.openDialogs['map'] = dlg
-                    self.openDialogs['map'].Show()
-                    
-
-        else:    # sofar no map
-            self.mouse["use"] = "addMap"
-            self.canvas.SetCursor(self.cursors["cross"])
-            if self.currentPage == 1:
-                self.book.SetSelection(0)
-                self.currentPage = 0
-                
-    def OnAddRaster(self, event):
-        """!Add raster map"""
-        if self.instruction.FindInstructionByType('raster'):
-            id = self.instruction.FindInstructionByType('raster').id
-        else: id = None
-        if self.instruction.FindInstructionByType('map'):
-            mapId = self.instruction.FindInstructionByType('map').id
-        else: mapId = None
-
-        if not id:
-            if not mapId:
-                GMessage(message = _("Please, create map frame first."))
-                return
-            
-##        dlg = RasterDialog(self, id = id, settings = self.instruction)
-##        dlg.ShowModal()
-        if 'mapNotebook' in self.openDialogs:
-            self.openDialogs['mapNotebook'].notebook.ChangeSelection(1)
-        else:
-            if 'raster' not in self.openDialogs:
-                dlg = RasterDialog(self, id = id, settings = self.instruction)
-                self.openDialogs['raster'] = dlg
-            self.openDialogs['raster'].Show()
-            
-    def OnAddVect(self, event):
-        """!Add vector map"""
-        if self.instruction.FindInstructionByType('vector'):
-            id = self.instruction.FindInstructionByType('vector').id
-        else: id = None
-        if self.instruction.FindInstructionByType('map'):
-            mapId = self.instruction.FindInstructionByType('map').id
-        else: mapId = None
-        if not id:
-            if not mapId:
-                GMessage(message = _("Please, create map frame first."))
-                return
-            
-##        dlg = MainVectorDialog(self, id = id, settings = self.instruction)
-##        dlg.ShowModal()
-        if 'mapNotebook' in self.openDialogs:
-            self.openDialogs['mapNotebook'].notebook.ChangeSelection(2)
-        else:
-            if 'vector' not in self.openDialogs:
-                dlg =  MainVectorDialog(self, id = id, settings = self.instruction)
-                self.openDialogs['vector'] = dlg
-            self.openDialogs['vector'].Show()
-        
-    def OnDecoration(self, event):
-        """!Decorations overlay menu
-        """
-        decmenu = wx.Menu()
-        # legend
-        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addLegend"].GetLabel())
-        AddLegend.SetBitmap(Icons['psMap']["addLegend"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddLegend)
-        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
-        # mapinfo
-        AddMapinfo = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addMapinfo"].GetLabel())
-        AddMapinfo.SetBitmap(Icons['psMap']["addMapinfo"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddMapinfo)
-        self.Bind(wx.EVT_MENU, self.OnAddMapinfo, AddMapinfo) 
-        # scalebar
-        AddScalebar = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addScalebar"].GetLabel())
-        AddScalebar.SetBitmap(Icons['psMap']["addScalebar"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddScalebar)
-        self.Bind(wx.EVT_MENU, self.OnAddScalebar, AddScalebar) 
-        # text
-        AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addText"].GetLabel())
-        AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddText)
-        self.Bind(wx.EVT_MENU, self.OnAddText, AddText) 
-        # eps image
-        AddImage = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addImage"].GetLabel())
-        AddImage.SetBitmap(Icons['psMap']["addImage"].GetBitmap(self.iconsize))
-        decmenu.AppendItem(AddImage)
-        self.Bind(wx.EVT_MENU, self.OnAddImage, AddImage) 
-        # north arrow image
-        AddNorthArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("North arrow"))
-        AddNorthArrow.SetBitmap(wx.ArtProvider.GetBitmap(id = wx.ART_MISSING_IMAGE,
-                                client = wx.ART_MENU, size = self.iconsize))
-        decmenu.AppendItem(AddNorthArrow)
-        self.Bind(wx.EVT_MENU, self.OnAddNorthArrow, AddNorthArrow) 
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(decmenu)
-        decmenu.Destroy()
-        
-    def OnAddScalebar(self, event):
-        """!Add scalebar"""
-        if projInfo()['proj'] == 'll':
-            GMessage(message = _("Scalebar is not appropriate for this projection"))
-            return
-        if self.instruction.FindInstructionByType('scalebar'):
-            id = self.instruction.FindInstructionByType('scalebar').id
-        else: id = None
-        
-        if 'scalebar' not in self.openDialogs:
-            dlg = ScalebarDialog(self, id = id, settings = self.instruction)
-            self.openDialogs['scalebar'] = dlg
-        self.openDialogs['scalebar'].Show()
-        
-    def OnAddLegend(self, event, page = 0):
-        """!Add raster or vector legend"""
-        if self.instruction.FindInstructionByType('rasterLegend'):
-            idR = self.instruction.FindInstructionByType('rasterLegend').id
-        else: idR = None
-        if self.instruction.FindInstructionByType('vectorLegend'):
-            idV = self.instruction.FindInstructionByType('vectorLegend').id
-        else: idV = None
-
-        if 'rasterLegend' not in self.openDialogs:    
-            dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
-            self.openDialogs['rasterLegend'] = dlg
-            self.openDialogs['vectorLegend'] = dlg
-        self.openDialogs['rasterLegend'].notebook.ChangeSelection(page)
-        self.openDialogs['rasterLegend'].Show()
-
-    def OnAddMapinfo(self, event):
-        if self.instruction.FindInstructionByType('mapinfo'):
-            id = self.instruction.FindInstructionByType('mapinfo').id
-        else: id = None
-        
-        if 'mapinfo' not in self.openDialogs:
-            dlg = MapinfoDialog(self, id = id, settings = self.instruction)
-            self.openDialogs['mapinfo'] = dlg
-        self.openDialogs['mapinfo'].Show()
-        
-    def OnAddImage(self, event, id = None):
-        """!Show dialog for image adding and editing"""
-        position = None
-        if 'image' in self.openDialogs:
-            position = self.openDialogs['image'].GetPosition()
-            self.openDialogs['image'].OnApply(event = None)
-            self.openDialogs['image'].Destroy()
-        dlg = ImageDialog(self, id = id, settings = self.instruction)
-        self.openDialogs['image'] = dlg 
-        if position: 
-            dlg.SetPosition(position)
-        dlg.Show()
-        
-    def OnAddNorthArrow(self, event, id = None):
-        """!Show dialog for north arrow adding and editing"""
-        if self.instruction.FindInstructionByType('northArrow'):
-            id = self.instruction.FindInstructionByType('northArrow').id
-        else: id = None
-        
-        if 'northArrow' not in self.openDialogs:
-            dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
-            self.openDialogs['northArrow'] = dlg
-        self.openDialogs['northArrow'].Show()
-        
-    def OnAddText(self, event, id = None):
-        """!Show dialog for text adding and editing"""
-        position = None
-        if 'text' in self.openDialogs:
-            position = self.openDialogs['text'].GetPosition()
-            self.openDialogs['text'].OnApply(event = None)
-            self.openDialogs['text'].Destroy()
-        dlg = TextDialog(self, id = id, settings = self.instruction)
-        self.openDialogs['text'] = dlg 
-        if position: 
-            dlg.SetPosition(position)
-        dlg.Show()
-        
-        
-    def getModifiedTextBounds(self, x, y, textExtent, rotation):
-        """!computes bounding box of rotated text, not very precisely"""
-        w, h = textExtent
-        rotation = float(rotation)/180*pi
-        H = float(w) * sin(rotation)
-        W = float(w) * cos(rotation)
-        X, Y = x, y
-        if pi/2 < rotation <= 3*pi/2:
-            X = x + W 
-        if 0 < rotation < pi:
-            Y = y - H
-        if rotation == 0:
-            return wx.Rect(x,y, *textExtent)
-        else:
-            return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h) 
-
-    def makePSFont(self, textDict):
-        """!creates a wx.Font object from selected postscript font. To be
-        used for estimating bounding rectangle of text"""
-        
-        fontsize = textDict['fontsize'] * self.canvas.currScale
-        fontface = textDict['font'].split('-')[0]
-        try:
-            fontstyle = textDict['font'].split('-')[1]
-        except IndexError:
-            fontstyle = ''
-        
-        if fontface == "Times":
-            family = wx.FONTFAMILY_ROMAN
-            face = "times"
-        elif fontface == "Helvetica":
-            family = wx.FONTFAMILY_SWISS
-            face = 'helvetica'
-        elif fontface == "Courier":
-            family = wx.FONTFAMILY_TELETYPE
-            face = 'courier'
-        else:
-            family = wx.FONTFAMILY_DEFAULT
-            face = ''
-            
-        style = wx.FONTSTYLE_NORMAL
-        weight = wx.FONTWEIGHT_NORMAL
-            
-        if 'Oblique' in fontstyle:
-            style =  wx.FONTSTYLE_SLANT
-            
-        if 'Italic' in fontstyle:
-            style =  wx.FONTSTYLE_ITALIC
-            
-        if 'Bold' in fontstyle:
-            weight = wx.FONTWEIGHT_BOLD
-        
-        try:
-            fn = wx.Font(pointSize = fontsize, family = family, style = style,
-                         weight = weight, face = face)
-        except:
-            fn = wx.Font(pointSize = fontsize, family = wx.FONTFAMILY_DEFAULT, 
-                         style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL)
-
-        return fn
-       
-       
-    def getTextExtent(self, textDict):
-        """!Estimates bounding rectangle of text"""
-        #fontsize = str(fontsize if fontsize >= 4 else 4)
-        dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
-       
-        fn = self.makePSFont(textDict)
-
-        try:
-            dc.SetFont(fn)
-            w,h,lh = dc.GetMultiLineTextExtent(textDict['text'])
-            return (w,h)
-        except:
-            return (0,0)
-    
-    def getInitMap(self):
-        """!Create default map frame when no map is selected, needed for coordinates in map units"""
-        instrFile = grass.tempfile()
-        instrFileFd = open(instrFile, mode = 'w')
-        instrFileFd.write(self.InstructionFile())
-        instrFileFd.flush()
-        instrFileFd.close()
-        
-        page = self.instruction.FindInstructionByType('page')
-        mapInitRect = GetMapBounds(instrFile, portrait = (page['Orientation'] == 'Portrait'))
-        grass.try_remove(instrFile)
-        
-        region = grass.region()
-        units = UnitConversion(self)
-        realWidth = units.convert(value = abs(region['w'] - region['e']), fromUnit = 'meter', toUnit = 'inch')
-        scale = mapInitRect.Get()[2]/realWidth  
-        
-        initMap = self.instruction.FindInstructionByType('initMap')
-        if initMap:
-            id = initMap.id 
-        else:
-            id = None
-
-        
-        if not id:
-            id = wx.NewId()
-            initMap = InitMap(id)
-            self.instruction.AddInstruction(initMap)
-        self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
-
-    def OnDelete(self, event):
-        if self.canvas.dragId != -1 and self.currentPage == 0:
-            if self.instruction[self.canvas.dragId].type == 'map':
-                self.deleteObject(self.canvas.dragId)
-                self.getInitMap()
-                self.canvas.RecalculateEN()
-            else:
-                self.deleteObject(self.canvas.dragId)   
-    
-    def deleteObject(self, id):
-        """!Deletes object, his id and redraws"""
-        #delete from canvas
-        self.canvas.pdcObj.RemoveId(id)
-        if id == self.canvas.dragId:
-            self.canvas.pdcTmp.RemoveAll()
-            self.canvas.dragId = -1
-        self.canvas.Refresh()
-        
-        # delete from instructions
-        del self.instruction[id]
-
-    def DialogDataChanged(self, id):
-        ids = id
-        if type(id) == int:
-            ids = [id]
-        for id in ids:
-            itype = self.instruction[id].type
-            
-            if itype in ('scalebar', 'mapinfo', 'image'):
-                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
-                self.canvas.UpdateLabel(itype = itype, id = id)
-                self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
-                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
-                self.canvas.RedrawSelectBox(id)
-            if itype == 'northArrow':
-                self.canvas.UpdateLabel(itype = itype, id = id)
-                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
-                self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
-                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'bitmap', bb = drawRectangle)
-                self.canvas.RedrawSelectBox(id)
-            if itype == 'text':
-                
-                if self.instruction[id]['rotate']:
-                    rot = float(self.instruction[id]['rotate']) 
-                else:
-                    rot = 0
-
-                extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
-                rect = wx.Rect2D(self.instruction[id]['where'][0], self.instruction[id]['where'][1], 0, 0)
-                self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
-                
-                #computes text coordinates according to reference point, not precisely
-                if self.instruction[id]['ref'].split()[0] == 'lower':
-                    self.instruction[id]['coords'][1] -= extent[1]
-                elif self.instruction[id]['ref'].split()[0] == 'center':
-                    self.instruction[id]['coords'][1] -= extent[1]/2
-                if self.instruction[id]['ref'].split()[1] == 'right':
-                    self.instruction[id]['coords'][0] -= extent[0] * cos(rot/180*pi)
-                    self.instruction[id]['coords'][1] += extent[0] * sin(rot/180*pi)
-                elif self.instruction[id]['ref'].split()[1] == 'center':
-                    self.instruction[id]['coords'][0] -= extent[0]/2 * cos(rot/180*pi)
-                    self.instruction[id]['coords'][1] += extent[0]/2 * sin(rot/180*pi)
-                    
-                self.instruction[id]['coords'][0] += self.instruction[id]['xoffset']
-                self.instruction[id]['coords'][1] -= self.instruction[id]['yoffset']
-                coords = self.instruction[id]['coords']
-                self.instruction[id]['rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
-                self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
-                                        textDict = self.instruction[id].GetInstruction(),
-                                        coords = coords, bounds = bounds)
-                self.canvas.RedrawSelectBox(id)
-                
-            if itype in ('map', 'vector', 'raster'):
-                
-                if itype == 'raster':#set resolution
-                    info = grass.raster_info(self.instruction[id]['raster'])
-                    RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
-                    # change current raster in raster legend
-                    
-                if 'rasterLegend' in self.openDialogs:
-                    self.openDialogs['rasterLegend'].updateDialog()
-                id = self.instruction.FindInstructionByType('map').id
-                
-                #check resolution
-                if itype == 'raster':
-                    SetResolution(dpi = self.instruction[id]['resolution'], 
-                                  width = self.instruction[id]['rect'].width,
-                                  height = self.instruction[id]['rect'].height)   
-                rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'],
-                                                                canvasToPaper = False)
-                self.canvas.RecalculateEN()
-                self.canvas.UpdateMapLabel()
-                
-                self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
-                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
-                # redraw select box  
-                self.canvas.RedrawSelectBox(id)
-                self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
-                # redraw to get map to the bottom layer
-                #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
-                
-            if itype == 'rasterLegend':
-                if self.instruction[id]['rLegend']:
-                    self.canvas.UpdateLabel(itype = itype, id = id)
-                    drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
-                    self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
-                                     pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
-                    self.canvas.RedrawSelectBox(id)
-                else:
-                    self.deleteObject(id)
-                    
-            if itype == 'vectorLegend':
-                if not self.instruction.FindInstructionByType('vector'):
-                    self.deleteObject(id)
-                elif self.instruction[id]['vLegend']:
-                    self.canvas.UpdateLabel(itype = itype, id = id)
-                    drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
-                    self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
-                                     pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
-                    self.canvas.RedrawSelectBox(id)
-
-                else:
-                    self.deleteObject(id)
-                
-    def OnPageChanged(self, event):
-        """!Flatnotebook page has changed"""
-        self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
-        
-        
-    def OnPageChanging(self, event):
-        """!Flatnotebook page is changing"""
-        if self.currentPage == 0 and self.mouse['use'] == 'addMap':
-            event.Veto()
-
-    def OnHelp(self, event):
-        """!Show help"""
-        if self.parent and self.parent.GetName() == 'LayerManager':
-            log = self.parent.GetLogWindow()
-            log.RunCmd(['g.manual',
-                        'entry=wxGUI.PsMap'])
-        else:
-            RunCommand('g.manual',
-                       quiet = True,
-                       entry = 'wxGUI.PsMap')
-        
-    def OnAbout(self, event):
-        """!Display About window"""
-        info = wx.AboutDialogInfo()
-        
-        info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-        info.SetName(_('wxGUI Cartographic Composer'))
-        info.SetWebSite('http://grass.osgeo.org')
-        info.SetDescription(_('(C) 2011 by the GRASS Development Team\n\n') + 
-                            '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
-                                                      '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
-        
-        wx.AboutBox(info)
-
-    def OnCloseWindow(self, event):
-        """!Close window"""
-        try:
-            os.remove(self.imgName)
-        except OSError:
-            pass
-        grass.set_raise_on_error(False)
-        self.Destroy()
-
-
-
-class PsMapBufferedWindow(wx.Window):
-    """!A buffered window class.
-    
-    @param parent parent window
-    @param kwargs other wx.Window parameters
-    """
-    def __init__(self, parent, id =  wx.ID_ANY,
-                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
-                 **kwargs):
-        wx.Window.__init__(self, parent, id = id, style = style)
-        self.parent = parent
-    
-        self.FitInside()
-        
-        # store an off screen empty bitmap for saving to file
-        self._buffer = None
-        # indicates whether or not a resize event has taken place
-        self.resize = False 
-        
-        self.mouse = kwargs['mouse']
-        self.cursors = kwargs['cursors']
-        self.preview = kwargs['preview']
-        self.pen = kwargs['pen']
-        self.brush = kwargs['brush']
-        
-        if kwargs.has_key('instruction'):
-            self.instruction = kwargs['instruction']
-        if kwargs.has_key('openDialogs'):
-            self.openDialogs = kwargs['openDialogs']
-        if kwargs.has_key('pageId'):
-            self.pageId = kwargs['pageId']
-        if kwargs.has_key('objectId'):
-            self.objectId = kwargs['objectId']
-        
-        
-        #labels
-        self.itemLabelsDict = { 'map': 'MAP FRAME',
-                                'rasterLegend': 'RASTER LEGEND',
-                                'vectorLegend': 'VECTOR LEGEND',
-                                'mapinfo': 'MAP INFO',
-                                'scalebar': 'SCALE BAR',
-                                'image': 'IMAGE',
-                                'northArrow': 'NORTH ARROW'}
-        self.itemLabels = {}
-        
-        # define PseudoDC
-        self.pdc = wx.PseudoDC()
-        self.pdcObj = wx.PseudoDC()
-        self.pdcPaper = wx.PseudoDC()
-        self.pdcTmp = wx.PseudoDC()
-        self.pdcImage = wx.PseudoDC()
-        dc = wx.PaintDC(self)
-        self.font = dc.GetFont()
-        
-        self.SetClientSize((700,510))#?
-        self._buffer = wx.EmptyBitmap(*self.GetClientSize())
-        
-        self.idBoxTmp = wx.NewId()
-        self.idZoomBoxTmp = wx.NewId()
-        self.idResizeBoxTmp = wx.NewId()
-        
-        
-
-        self.dragId = -1
-        
-        if self.preview:
-            self.image = None
-            self.imageId = 2000
-            self.imgName = self.parent.imgName
-            
-            
-            
-        self.currScale = None
-        
-        self.Clear()
-        
-        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
-        
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        self.Bind(wx.EVT_SIZE,  self.OnSize)
-        self.Bind(wx.EVT_IDLE,  self.OnIdle)
-        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
-
-
-    def Clear(self):
-        """!Clear canvas and set paper
-        """
-        bg = wx.LIGHT_GREY_BRUSH
-        self.pdcPaper.BeginDrawing()
-        self.pdcPaper.SetBackground(bg)
-        self.pdcPaper.Clear()
-        self.pdcPaper.EndDrawing()
-        
-        self.pdcObj.RemoveAll()
-        self.pdcTmp.RemoveAll()
-        
-
-
-        if not self.preview:
-            self.SetPage()
-
-    
-    def CanvasPaperCoordinates(self, rect, canvasToPaper = True):
-        """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
-        
-        units = UnitConversion(self)
-        
-        fromU = 'pixel'
-        toU = 'inch'
-        pRect = self.pdcPaper.GetIdBounds(self.pageId)
-        pRectx, pRecty = pRect.x, pRect.y 
-        scale = 1/self.currScale
-        if not canvasToPaper: # paper -> canvas
-            fromU = 'inch'
-            toU = 'pixel'
-            scale = self.currScale
-            pRectx = units.convert(value =  - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
-            pRecty = units.convert(value =  - pRect.y, fromUnit = 'pixel', toUnit = 'inch' ) /scale 
-        Width = units.convert(value = rect.width, fromUnit = fromU, toUnit = toU) * scale
-        Height = units.convert(value = rect.height, fromUnit = fromU, toUnit = toU) * scale
-        X = units.convert(value = (rect.x - pRectx), fromUnit = fromU, toUnit = toU) * scale
-        Y = units.convert(value = (rect.y - pRecty), fromUnit = fromU, toUnit = toU) * scale
-
-        return wx.Rect2D(X, Y, Width, Height)
-
-    
-    
-    def SetPage(self):
-        """!Sets and changes page, redraws paper"""
-        
-        page = self.instruction[self.pageId]
-        if not page:
-            page = PageSetup(id = self.pageId)
-            self.instruction.AddInstruction(page)
-        
-        ppi = wx.PaintDC(self).GetPPI()
-        cW, cH = self.GetClientSize()
-        pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
-
-        if self.currScale is None:
-            self.currScale = min(cW/pW, cH/pH)
-        pW = pW * self.currScale
-        pH = pH * self.currScale
-        
-        x = cW/2 - pW/2
-        y = cH/2 - pH/2
-        self.DrawPaper(wx.Rect(x, y, pW, pH))
-
-
-    def modifyRectangle(self, r):
-        """! Recalculates rectangle not to have negative size"""
-        if r.GetWidth() < 0:
-            r.SetX(r.GetX() + r.GetWidth())
-        if r.GetHeight() < 0:
-            r.SetY(r.GetY() + r.GetHeight())
-        r.SetWidth(abs(r.GetWidth()))
-        r.SetHeight(abs(r.GetHeight()))
-        return r 
-    
-    def RecalculateEN(self):
-        """!Recalculate east and north for texts (eps, points) after their or map's movement"""
-        try:
-            mapId = self.instruction.FindInstructionByType('map').id
-        except AttributeError:
-            mapId = self.instruction.FindInstructionByType('initMap').id
-        
-        for itemType in ('text', 'image', 'northArrow'):
-            items = self.instruction.FindInstructionByType(itemType, list = True)
-            for item in items:
-                e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[item.id]['where'][0],
-                                           y = self.instruction[item.id]['where'][1], paperToMap = True)
-                self.instruction[item.id]['east'], self.instruction[item.id]['north'] = e, n
-                
-    def OnPaint(self, event):
-        """!Draw pseudo DC to buffer
-        """
-        if not self._buffer:
-            return
-        dc = wx.BufferedPaintDC(self, self._buffer)
-        # use PrepareDC to set position correctly
-        self.PrepareDC(dc)
-        
-        dc.SetBackground(wx.LIGHT_GREY_BRUSH)
-        dc.Clear()
-        
-        # draw paper
-        if not self.preview:
-            self.pdcPaper.DrawToDC(dc)
-        # draw to the DC using the calculated clipping rect
-
-        rgn = self.GetUpdateRegion()
-        
-        if not self.preview:
-            self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
-        else: 
-            self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
-        self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
-        
-    def OnMouse(self, event):
-
-        if event.GetWheelRotation():
-            zoom = event.GetWheelRotation()
-            use = self.mouse['use']
-            self.mouse['begin'] = event.GetPosition()
-            if zoom > 0:
-                self.mouse['use'] = 'zoomin'
-            else:
-                self.mouse['use'] = 'zoomout'
-                
-            zoomFactor, view = self.ComputeZoom(wx.Rect(0,0,0,0))
-            self.Zoom(zoomFactor, view)
-            self.mouse['use'] = use
-            
-        if event.Moving():
-            if self.mouse['use'] in ('pointer', 'resize'):
-                pos = event.GetPosition()
-                foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
-                if foundResize and foundResize[0] == self.idResizeBoxTmp:
-                    self.SetCursor(self.cursors["sizenwse"])
-                    self.parent.SetStatusText(_('Click and drag to resize object'), 0)
-                else:
-                    self.parent.SetStatusText('', 0)
-                    self.SetCursor(self.cursors["default"])
-                    
-        elif event.LeftDown():
-            self.mouse['begin'] = event.GetPosition()
-            self.begin = self.mouse['begin']
-            if self.mouse['use'] in ('pan', 'zoomin', 'zoomout', 'addMap'):
-                pass
-            
-            #select
-            if self.mouse['use'] == 'pointer':
-                found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
-                foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
-
-                if foundResize and foundResize[0] == self.idResizeBoxTmp:
-                    self.mouse['use'] = 'resize'
-                    
-                    # when resizing, proportions match region
-                    if self.instruction[self.dragId].type == 'map':
-                        self.constraint = False
-                        self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
-                        if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
-                            self.constraint = True
-                            self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
-                    
-                elif found:
-                    self.dragId = found[0]  
-                    self.RedrawSelectBox(self.dragId)
-                    if self.instruction[self.dragId].type != 'map':
-                        self.pdcTmp.RemoveId(self.idResizeBoxTmp)
-                        self.Refresh()
-                        
-                else:
-                    self.dragId = -1
-                    self.pdcTmp.RemoveId(self.idBoxTmp)
-                    self.pdcTmp.RemoveId(self.idResizeBoxTmp)
-                    self.Refresh()           
-                    
-                    
-        elif event.Dragging() and event.LeftIsDown():
-            #draw box when zooming, creating map 
-            if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap'):
-                self.mouse['end'] = event.GetPosition()
-                r = wx.Rect(self.mouse['begin'][0], self.mouse['begin'][1],
-                            self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
-                r = self.modifyRectangle(r)
-                self.Draw(pen = self.pen['box'], brush = self.brush['box'], pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
-                          pdctype = 'rect', bb = r)
-                
-            # panning                
-            if self.mouse["use"] == 'pan':
-                self.mouse['end'] = event.GetPosition()
-                view = self.mouse['begin'][0] - self.mouse['end'][0], self.mouse['begin'][1] - self.mouse['end'][1]
-                zoomFactor = 1
-                self.Zoom(zoomFactor, view)
-                self.mouse['begin'] = event.GetPosition()
-                
-            #move object
-            if self.mouse['use'] == 'pointer' and self.dragId != -1:
-                
-                self.mouse['end'] = event.GetPosition()
-                dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
-                self.pdcObj.TranslateId(self.dragId, dx, dy)
-                self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
-                self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
-                if self.instruction[self.dragId].type == 'text': 
-                    self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
-                        self.instruction[self.dragId]['coords'][1] + dy
-                self.begin = event.GetPosition()
-                self.Refresh()
-                
-            # resize object
-            if self.mouse['use'] == 'resize':
-                type = self.instruction[self.dragId].type
-                pos = event.GetPosition()
-                x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
-                width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
-                diffX = pos[0] - self.mouse['begin'][0]
-                diffY = pos[1] - self.mouse['begin'][1]
-                # match given region
-                if self.constraint:
-                    if width > height:
-                        newWidth = width + diffX
-                        newHeight = height + diffX * (float(height) / width)
-                    else:
-                        newWidth = width + diffY * (float(width) / height)
-                        newHeight = height + diffY
-                else:
-                    newWidth = width + diffX
-                    newHeight = height + diffY
-                    
-                if newWidth < 10 or newHeight < 10:
-                    return
-                
-                bounds = wx.Rect(x, y, newWidth, newHeight)    
-                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj, drawid = self.dragId,
-                          pdctype = 'rectText', bb = bounds)
-                self.RedrawSelectBox(self.dragId)
-                
-        elif event.LeftUp():
-            # zoom in, zoom out
-            if self.mouse['use'] in ('zoomin','zoomout'):
-                zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
-                self.pdcTmp.RemoveId(self.idZoomBoxTmp)
-                self.Refresh()
-                zoomFactor, view = self.ComputeZoom(zoomR)
-                self.Zoom(zoomFactor, view)
-
-                
-            # draw map frame    
-            if self.mouse['use'] == 'addMap':
-                rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
-                # too small rectangle, it's usually some mistake
-                if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
-                    self.pdcTmp.RemoveId(self.idZoomBoxTmp)
-                    self.Refresh()
-                    return
-                rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)                
-                
-                dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction, 
-                                rect = rectPaper)
-                self.openDialogs['map'] = dlg
-                self.openDialogs['map'].Show()
-                
-                
-                self.mouse['use'] = self.parent.mouseOld
-
-                self.SetCursor(self.parent.cursorOld)
-                self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
-                self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
-                self.parent.toolbar.action['id'] = self.parent.actionOld
-                
-
-
-            # resize resizable objects (only map sofar)
-            if self.mouse['use'] == 'resize':
-                mapId = self.instruction.FindInstructionByType('map').id
-                
-                if self.dragId == mapId:
-                    # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
-                    newRectCanvas = self.pdcObj.GetIdBounds(mapId)
-                    newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
-                    self.instruction[mapId]['rect'] = newRectPaper
-                    
-                    if self.instruction[mapId]['scaleType'] in (0, 1, 2):
-                        if self.instruction[mapId]['scaleType'] == 0:
-                            
-                            scale, foo, rect = AutoAdjust(self, scaleType = 0,
-                                                          map = self.instruction[mapId]['map'],
-                                                          mapType = self.instruction[mapId]['mapType'], 
-                                                          rect = self.instruction[mapId]['rect'])
-                            
-                        elif self.instruction[mapId]['scaleType'] == 1:
-                            scale, foo, rect = AutoAdjust(self, scaleType = 1,
-                                                          region = self.instruction[mapId]['region'],
-                                                          rect = self.instruction[mapId]['rect'])
-                        else:
-                            scale, foo, rect = AutoAdjust(self, scaleType = 2,
-                                                          rect = self.instruction[mapId]['rect'])
-                        self.instruction[mapId]['rect'] = rect
-                        self.instruction[mapId]['scale'] = scale
-                        
-                        rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
-                        self.Draw(pen = self.pen['map'], brush = self.brush['map'],
-                                  pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
-                        
-                    elif self.instruction[mapId]['scaleType'] == 3:
-                        ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
-                    #check resolution
-                    SetResolution(dpi = self.instruction[mapId]['resolution'],
-                                  width = self.instruction[mapId]['rect'].width,
-                                  height = self.instruction[mapId]['rect'].height)
-                    
-                    self.RedrawSelectBox(mapId)
-                    self.Zoom(zoomFactor = 1, view = (0, 0))
-                self.mouse['use'] = 'pointer'
-                
-            # recalculate the position of objects after dragging    
-            if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
-                if self.mouse['begin'] != event.GetPosition(): #for double click
-                    
-                    self.RecalculatePosition(ids = [self.dragId])
-                    if self.instruction[self.dragId].type in self.openDialogs:
-                        self.openDialogs[self.instruction[self.dragId].type].updateDialog()
-
-        # double click launches dialogs
-        elif event.LeftDClick():
-            if self.mouse['use'] == 'pointer' and self.dragId != -1:
-                itemCall = {    'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
-                                'scalebar': self.parent.OnAddScalebar, 'image': self.parent.OnAddImage,
-                                'northArrow' : self.parent.OnAddNorthArrow,
-                                'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,  
-                                'map': self.parent.OnAddMap}
-                itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
-                            'scalebar': dict(event = None), 'image': dict(event = None, id = self.dragId),
-                            'northArrow': dict(event = None, id = self.dragId),
-                            'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
-                            'map': dict(event = None, notebook = True)}
-                type = self.instruction[self.dragId].type
-                itemCall[type](**itemArg[type])
-
-                
-                
-                
-    def RecalculatePosition(self, ids):
-        for id in ids:
-            itype = self.instruction[id].type
-            if itype == 'map':
-                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                           canvasToPaper = True)
-                self.RecalculateEN()
-                
-            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
-                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                           canvasToPaper = True)
-                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                            canvasToPaper = True)[:2] 
-                if itype in ('image', 'northArrow'):
-                    self.RecalculateEN()
-            elif  itype == 'scalebar':
-                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                           canvasToPaper = True)
-
-                
-                self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
-                
-            elif  itype == 'text':
-                x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
-                    self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
-                extent = self.parent.getTextExtent(textDict = self.instruction[id])
-                if self.instruction[id]['rotate'] is not None:
-                    rot = float(self.instruction[id]['rotate'])/180*pi 
-                else:
-                    rot = 0
-
-                if self.instruction[id]['ref'].split()[0] == 'lower':
-                    y += extent[1]
-                elif self.instruction[id]['ref'].split()[0] == 'center':
-                    y += extent[1]/2
-                if self.instruction[id]['ref'].split()[1] == 'right':
-                    x += extent[0] * cos(rot)
-                    y -= extent[0] * sin(rot)
-                elif self.instruction[id]['ref'].split()[1] == 'center':
-                    x += extent[0]/2 * cos(rot)
-                    y -= extent[0]/2 * sin(rot)
-                
-                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = wx.Rect2D(x, y, 0, 0),
-                                                                            canvasToPaper = True)[:2]
-                self.RecalculateEN()
-        
-    def ComputeZoom(self, rect):
-        """!Computes zoom factor and scroll view"""
-        zoomFactor = 1
-        cW, cH = self.GetClientSize()
-        cW = float(cW)
-        if rect.IsEmpty(): # clicked on canvas
-            zoomFactor = 1.5
-            if self.mouse['use'] == 'zoomout':
-                zoomFactor = 1./zoomFactor
-            x,y = self.mouse['begin']
-            xView = x - x/zoomFactor#x - cW/(zoomFactor * 2)
-            yView = y - y/zoomFactor#y - cH/(zoomFactor * 2)
-
-        else:   #dragging    
-            rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
-            zoomFactor = 1/max(rW/cW, rH/cH)
-            # when zooming to full extent, in some cases, there was zoom 1.01..., which causes problem
-            if abs(zoomFactor - 1) > 0.01:
-                zoomFactor = zoomFactor 
-            else:
-                zoomFactor = 1.
-
-
-            if self.mouse['use'] == 'zoomout':
-                zoomFactor = min(rW/cW, rH/cH) 
-            if rW/rH > cW/cH:
-                yView = rect.GetY() - (rW*(cH/cW) - rH)/2
-                xView = rect.GetX()
-                
-                if self.mouse['use'] == 'zoomout':
-                    x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
-                    xView, yView = -x, -y
-            else:
-                xView = rect.GetX() - (rH*(cW/cH) - rW)/2
-                yView = rect.GetY()
-                if self.mouse['use'] == 'zoomout':
-                    x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
-                    xView, yView = -x, -y
-        return zoomFactor, (int(xView), int(yView))
-    
-    
-    def Zoom(self, zoomFactor, view):
-        """! Zoom to specified region, scroll view, redraw"""
-        if not self.currScale:
-            return
-        self.currScale = self.currScale*zoomFactor
-        
-        if self.currScale > 10 or self.currScale < 0.1:
-            self.currScale = self.currScale/zoomFactor
-            return 
-        if not self.preview:
-            # redraw paper
-            pRect = self.pdcPaper.GetIdBounds(self.pageId)
-            pRect.OffsetXY(-view[0], -view[1])
-            pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
-            self.DrawPaper(pRect)
-            
-            #redraw objects
-            for id in self.objectId:
-                oRect = self.CanvasPaperCoordinates(
-                    rect = self.instruction[id]['rect'], canvasToPaper = False)
-                
-                type = self.instruction[id].type
-                if type == 'text':
-                    coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
-                    self.instruction[id]['coords'] = coords = [(int(coord) - view[i]) * zoomFactor
-                                                               for i, coord in enumerate(coords)]
-                    self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
-                                     coords = coords, bounds = oRect )
-                    extent = self.parent.getTextExtent(textDict = self.instruction[id])
-                    if self.instruction[id]['rotate']:
-                        rot = float(self.instruction[id]['rotate']) 
-                    else:
-                        rot = 0
-
-                    self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
-                    self.pdcObj.SetIdBounds(id, bounds)
-                elif type == 'northArrow':
-                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
-                              drawid = id, pdctype = 'bitmap', bb = oRect)
-                else:
-                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
-                              drawid = id, pdctype = 'rectText', bb = oRect)
-            #redraw tmp objects
-            if self.dragId != -1:
-                self.RedrawSelectBox(self.dragId)
-                
-        #redraw preview
-        else: # preview mode    
-            imageRect = self.pdcImage.GetIdBounds(self.imageId)
-            imageRect.OffsetXY(-view[0], -view[1])
-            imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
-            self.DrawImage(imageRect)
-        
-    def ZoomAll(self):
-        """! Zoom to full extent"""  
-        if not self.preview:
-            bounds = self.pdcPaper.GetIdBounds(self.pageId)
-        else:
-            bounds = self.pdcImage.GetIdBounds(self.imageId)
-        zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
-        zoomFactor, view = self.ComputeZoom(zoomP)
-        self.Zoom(zoomFactor, view)
-        
-    def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0)): 
-        """! Draw object"""    
-        if drawid is None:
-            drawid = wx.NewId()
-        bb = bb.Get()
-        pdc.BeginDrawing()
-        pdc.RemoveId(drawid)
-        pdc.SetId(drawid)
-        pdc.SetPen(pen)
-        pdc.SetBrush(brush)
-        
-        if pdctype == 'bitmap':
-            if havePILImage:
-                file = self.instruction[drawid]['epsfile']
-                rotation = self.instruction[drawid]['rotate']
-                self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
-            else: # draw only rectangle with label
-                pdctype = 'rectText'
-                
-        if pdctype in ('rect', 'rectText'):
-            pdc.DrawRectangle(*bb)
-            
-        if pdctype == 'rectText':
-            dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
-            font = self.font
-            size = 10
-            font.SetPointSize(size)
-            font.SetStyle(wx.ITALIC)
-            dc.SetFont(font)
-            pdc.SetFont(font)
-            text = '\n'.join(self.itemLabels[drawid])
-            w,h,lh = dc.GetMultiLineTextExtent(text)
-            textExtent = (w,h)
-            textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
-            r = map(int, bb)
-            while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
-                size -= 2
-                font.SetPointSize(size)
-                dc.SetFont(font)
-                pdc.SetFont(font)
-                textExtent = dc.GetTextExtent(text)
-                textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
-            pdc.SetTextForeground(wx.Color(100,100,100,200)) 
-            pdc.SetBackgroundMode(wx.TRANSPARENT)
-            pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
-                
-        pdc.SetIdBounds(drawid, bb)
-        pdc.EndDrawing()
-        self.Refresh()
-
-        return drawid
-    
-    def DrawBitmap(self, pdc, filePath, rotation, bbox):
-        """!Draw bitmap using PIL"""
-        pImg = PILImage.open(filePath)
-        if rotation:
-            # get rid of black background
-            pImg = pImg.convert("RGBA")
-            rot = pImg.rotate(rotation, expand = 1)
-            new = PILImage.new('RGBA', rot.size, (255,) * 4)
-            pImg = PILImage.composite(rot, new, rot)
-        pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
-        img = PilImageToWxImage(pImg)
-        bitmap = img.ConvertToBitmap()
-        mask = wx.Mask(bitmap, wx.WHITE)
-        bitmap.SetMask(mask)
-        pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask = True)
-        
-    def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
-        if textDict['rotate']:
-            rot = float(textDict['rotate']) 
-        else:
-            rot = 0
-
-        fontsize = textDict['fontsize'] * self.currScale
-        if textDict['background'] != 'none':
-            background = textDict['background'] 
-        else:
-            background = None
-
-        pdc.RemoveId(drawId)
-        pdc.SetId(drawId)
-        pdc.BeginDrawing()
-        
-        # border is not redrawn when zoom changes, why?
-##        if textDict['border'] != 'none' and not rot:
-##            units = UnitConversion(self)
-##            borderWidth = units.convert(value = textDict['width'],
-##                                        fromUnit = 'point', toUnit = 'pixel' ) * self.currScale
-##            pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth))
-##            pdc.DrawRectangle(*bounds)
-            
-        if background:
-            pdc.SetTextBackground(convertRGB(background))
-            pdc.SetBackgroundMode(wx.SOLID)
-        else:
-            pdc.SetBackgroundMode(wx.TRANSPARENT)
-        
-        fn = self.parent.makePSFont(textDict)
-
-        pdc.SetFont(fn)
-        pdc.SetTextForeground(convertRGB(textDict['color']))        
-        pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
-        
-        pdc.SetIdBounds(drawId, wx.Rect(*bounds))
-        self.Refresh()
-        pdc.EndDrawing()
-        
-    def DrawImage(self, rect):
-        """!Draw preview image to pseudoDC"""
-        self.pdcImage.ClearId(self.imageId)
-        self.pdcImage.SetId(self.imageId)
-        img = self.image
-        
-
-        if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
-            img = img.Scale(rect.width, rect.height)
-        bitmap = img.ConvertToBitmap()
-        
-        self.pdcImage.BeginDrawing()
-        self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
-        self.pdcImage.SetIdBounds(self.imageId, rect)
-        self.pdcImage.EndDrawing()
-        self.Refresh()
-        
-    def DrawPaper(self, rect):
-        """!Draw paper and margins"""
-        page = self.instruction[self.pageId]
-        scale = page['Width'] / rect.GetWidth()
-        w = (page['Width'] - page['Right'] - page['Left']) / scale
-        h = (page['Height'] - page['Top'] - page['Bottom']) / scale
-        x = page['Left'] / scale + rect.GetX()
-        y = page['Top'] / scale + rect.GetY()
-        
-        self.pdcPaper.BeginDrawing()
-        self.pdcPaper.RemoveId(self.pageId)
-        self.pdcPaper.SetId(self.pageId)
-        self.pdcPaper.SetPen(self.pen['paper'])
-        self.pdcPaper.SetBrush(self.brush['paper'])
-        self.pdcPaper.DrawRectangleRect(rect)
-        
-        self.pdcPaper.SetPen(self.pen['margins'])
-        self.pdcPaper.SetBrush(self.brush['margins'])
-        self.pdcPaper.DrawRectangle(x, y, w, h)
-        
-        self.pdcPaper.SetIdBounds(self.pageId, rect)
-        self.pdcPaper.EndDrawing()
-        self.Refresh()
-
-        
-    def ImageRect(self):
-        """!Returns image centered in canvas, computes scale"""
-        img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
-        cW, cH = self.GetClientSize()
-        iW, iH = img.GetWidth(), img.GetHeight()
-
-        self.currScale = min(float(cW)/iW, float(cH)/iH)
-        iW = iW * self.currScale
-        iH = iH * self.currScale
-        x = cW/2 - iW/2
-        y = cH/2 - iH/2
-        imageRect = wx.Rect(x, y, iW, iH)
-
-        return imageRect 
-    
-    def RedrawSelectBox(self, id):
-        """!Redraws select box when selected object changes its size"""
-        if self.dragId == id:
-            rect = [self.pdcObj.GetIdBounds(id).Inflate(3,3)]
-            type = ['select']
-            ids = [self.idBoxTmp]
-            if self.instruction[id].type == 'map':
-                controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
-                rect.append(wx.Rect(controlP.x, controlP.y, 10,10))
-                type.append('resize')
-                ids.append(self.idResizeBoxTmp)
-            for id, type, rect in zip(ids, type, rect):
-                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcTmp,
-                          drawid = id, pdctype = 'rect', bb = rect)
-        
-    def UpdateMapLabel(self):
-        """!Updates map frame label"""
-
-        vector = self.instruction.FindInstructionByType('vector')
-        if vector:
-            vectorId = vector.id 
-        else:
-            vectorId = None
-
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            rasterId = raster.id 
-        else:
-            rasterId = None
-
-        rasterName = 'None'
-        if rasterId:
-            rasterName = self.instruction[rasterId]['raster'].split('@')[0]
-            
-        mapId = self.instruction.FindInstructionByType('map').id
-        self.itemLabels[mapId] = []
-        self.itemLabels[mapId].append(self.itemLabelsDict['map'])
-        self.itemLabels[mapId].append("raster: " + rasterName)
-        if vectorId: 
-            for map in self.instruction[vectorId]['list']:
-                self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
-            
-    def UpdateLabel(self, itype, id):
-        self.itemLabels[id] = []
-        self.itemLabels[id].append(self.itemLabelsDict[itype])
-        if itype == 'image':
-            file = os.path.basename(self.instruction[id]['epsfile'])
-            self.itemLabels[id].append(file)
-        
-    def OnSize(self, event):
-        """!Init image size to match window size
-        """
-        # not zoom all when notebook page is changed
-        if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
-            self.ZoomAll()
-        self.OnIdle(None)
-        event.Skip()
-        
-    def OnIdle(self, event):
-        """!Only re-render a image during idle time instead of
-        multiple times during resizing.
-        """ 
-        
-        width, height = self.GetClientSize()
-        # Make new off screen bitmap: this bitmap will always have the
-        # current drawing in it, so it can be used to save the image
-        # to a file, or whatever.
-        self._buffer = wx.EmptyBitmap(width, height)
-        # re-render image on idle
-        self.resize = True
-        
-    def ScaleRect(self, rect, scale):
-        """! Scale rectangle"""
-        return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
-                       rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)   
-    
-def main():
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    app = wx.PySimpleApp()
-    wx.InitAllImageHandlers()
-    frame = PsMapFrame()
-    frame.Show()
-    
-    app.MainLoop()
-
-if __name__ == "__main__":
-    main()

Deleted: grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,6408 +0,0 @@
-"""!
- at package psmap_dialogs.py
-
- at brief Map feature objects and dialogs for ps.map
-
-Classes:
- - UnitConversion
- - TCValidator
- - PenStyleComboBox
- - CheckListCtrl
- - Instruction
- - InstructionObject
- - InitMap
- - MapFrame
- - PageSetup
- - Mapinfo
- - Text
- - Image
- - NorthArrow
- - Scalebar
- - RasterLegend
- - VectorLegend
- - Raster
- - Vector
- - VProperties
- - PsmapDialog
- - PageSetupDialog
- - MapDialog
- - MapFramePanel
- - RasterPanel
- - VectorPanel
- - RasterDialog
- - MainVectorDialog
- - VPropertiesDialog
- - LegendDialog
- - MapinfoDialog
- - ScalebarDialog
- - TextDialog
- - ImageDialog
- - NorthArrowDialog
-
-(C) 2011 by Anna Kratochvilova, and 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 Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
- at author Martin Landa <landa.martin gmail.com> (mentor)
-"""
-
-
-import os
-import sys
-import string
-from math import ceil, floor, sin, cos, pi
-from copy import deepcopy
-from time import strftime, localtime
-try:
-    import Image as PILImage
-    havePILImage = True
-except ImportError:
-    havePILImage = False
-
-import grass.script as grass
-if int(grass.version()['version'].split('.')[0]) > 6:
-    sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython',
-                                 'gui_modules'))
-else:
-    sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython',
-                                 'gui_modules'))
-import globalvar
-import dbm_base
-from   utils      import CmdToTuple, GetCmdString
-from   gselect    import Select
-from   gcmd       import RunCommand, GError, GMessage, GWarning
-
-import wx
-import wx.lib.scrolledpanel as scrolled
-import  wx.lib.filebrowsebutton as filebrowse
-from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin
-from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
-try:
-    import wx.lib.agw.floatspin as fs
-except ImportError:
-    fs = None
-
-grass.set_raise_on_error(True)
-
-PSMAP_COLORS = ['aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'grey', 'green', 'indigo',
-                'magenta','orange', 'purple', 'red', 'violet', 'white', 'yellow']
-class UnitConversion:
-    """! Class for converting units"""
-    def __init__(self, parent = None):
-        self.parent = parent
-        if self.parent:
-            ppi = wx.PaintDC(self.parent).GetPPI()
-        else: 
-            ppi = (72, 72)
-        self._unitsPage = { 'inch'          : {'val': 1.0, 'tr' : _("inch")},
-                            'point'         : {'val': 72.0, 'tr' : _("point")},
-                            'centimeter'    : {'val': 2.54, 'tr' : _("centimeter")},
-                            'millimeter'    : {'val': 25.4, 'tr' : _("millimeter")}}
-        self._unitsMap = {  'meters'        : {'val': 0.0254, 'tr' : _("meters")},
-                            'kilometers'    : {'val': 2.54e-5, 'tr' : _("kilometers")},
-                            'feet'          : {'val': 1./12, 'tr' : _("feet")},
-                            'miles'         : {'val': 1./63360, 'tr' : _("miles")},
-                            'nautical miles': {'val': 1/72913.386, 'tr' : _("nautical miles")}}
-
-        self._units = { 'pixel'     : {'val': ppi[0], 'tr' : _("pixel")},
-                        'meter'     : {'val': 0.0254, 'tr' : _("meter")},
-                        'nautmiles' : {'val': 1/72913.386, 'tr' :_("nautical miles")},
-                        'degrees'   : {'val': 0.0254 , 'tr' : _("degree")} #like 1 meter, incorrect
-                        }
-        self._units.update(self._unitsPage)
-        self._units.update(self._unitsMap)
-
-    def getPageUnitsNames(self):
-        return sorted(self._unitsPage[unit]['tr'] for unit in self._unitsPage.keys())
-    
-    def getMapUnitsNames(self):
-        return sorted(self._unitsMap[unit]['tr'] for unit in self._unitsMap.keys())
-    
-    def getAllUnits(self):
-        return sorted(self._units.keys())
-    
-    def findUnit(self, name):
-        """!Returns unit by its tr. string"""
-        for unit in self._units.keys():
-            if self._units[unit]['tr'] == name:
-                return unit
-        return None
-    
-    def findName(self, unit):
-        """!Returns tr. string of a unit"""
-        try:
-            return self._units[unit]['tr']
-        except KeyError:
-            return None
-    
-    def convert(self, value, fromUnit = None, toUnit = None):
-        return float(value)/self._units[fromUnit]['val']*self._units[toUnit]['val']
-    
-    
-class TCValidator(wx.PyValidator):
-    """!validates input in textctrls, combobox, taken from wxpython demo"""
-    def __init__(self, flag = None):
-        wx.PyValidator.__init__(self)
-        self.flag = flag
-        self.Bind(wx.EVT_CHAR, self.OnChar)
-
-    def Clone(self):
-        return TCValidator(self.flag)
-
-    def Validate(self, win):
-        
-        tc = self.GetWindow()
-        val = tc.GetValue()
-
-        if self.flag == 'DIGIT_ONLY':
-            for x in val:
-                if x not in string.digits:
-                    return False
-        return True
-
-    def OnChar(self, event):
-        key = event.GetKeyCode()
-        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
-            event.Skip()
-            return
-        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.':
-            event.Skip()
-            return
-##        if self.flag == 'SCALE' and chr(key) in string.digits + ':':
-##            event.Skip()
-##            return
-        if self.flag == 'ZERO_AND_ONE_ONLY' and chr(key) in '01':
-            event.Skip()
-            return
-        if not wx.Validator_IsSilent():
-            wx.Bell()
-        # Returning without calling even.Skip eats the event before it
-        # gets to the text control
-        return  
-
-
-class PenStyleComboBox(wx.combo.OwnerDrawnComboBox):
-    """!Combo for selecting line style, taken from wxpython demo"""
-
-    # Overridden from OwnerDrawnComboBox, called to draw each
-    # item in the list
-    def OnDrawItem(self, dc, rect, item, flags):
-        if item == wx.NOT_FOUND:
-            # painting the control, but there is no valid item selected yet
-            return
-
-        r = wx.Rect(*rect)  # make a copy
-        r.Deflate(3, 5)
-
-        penStyle = wx.SOLID
-        if item == 1:
-            penStyle = wx.LONG_DASH
-        elif item == 2:
-            penStyle = wx.DOT
-        elif item == 3:
-            penStyle = wx.DOT_DASH
-
-        pen = wx.Pen(dc.GetTextForeground(), 3, penStyle)
-        dc.SetPen(pen)
-
-        # for painting the items in the popup
-        dc.DrawText(self.GetString(item ),
-                    r.x + 3,
-                    (r.y + 0) + ((r.height/2) - dc.GetCharHeight() )/2
-                    )
-        dc.DrawLine(r.x+5, r.y+((r.height/4)*3)+1, r.x+r.width - 5, r.y+((r.height/4)*3)+1 )
-
-        
-    def OnDrawBackground(self, dc, rect, item, flags):
-        """!Overridden from OwnerDrawnComboBox, called for drawing the
-        background area of each item."""
-        # If the item is selected, or its item # iseven, or we are painting the
-        # combo control itself, then use the default rendering.
-        if (item & 1 == 0 or flags & (wx.combo.ODCB_PAINTING_CONTROL |
-                                      wx.combo.ODCB_PAINTING_SELECTED)):
-            wx.combo.OwnerDrawnComboBox.OnDrawBackground(self, dc, rect, item, flags)
-            return
-
-        # Otherwise, draw every other background with different colour.
-        bgCol = wx.Colour(240,240,250)
-        dc.SetBrush(wx.Brush(bgCol))
-        dc.SetPen(wx.Pen(bgCol))
-        dc.DrawRectangleRect(rect);
-
-    def OnMeasureItem(self, item):
-        """!Overridden from OwnerDrawnComboBox, should return the height
-        needed to display an item in the popup, or -1 for default"""
-        return 30
-
-    def OnMeasureItemWidth(self, item):
-        """!Overridden from OwnerDrawnComboBox.  Callback for item width, or
-        -1 for default/undetermined"""
-        return -1; # default - will be measured from text width  
-    
-    
-class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
-    """!List control for managing order and labels of vector maps in legend"""
-    def __init__(self, parent):
-        wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY, 
-                             style = wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.BORDER_SUNKEN|wx.LC_VRULES|wx.LC_HRULES)
-        CheckListCtrlMixin.__init__(self) 
-        ListCtrlAutoWidthMixin.__init__(self)
-        
-class Instruction:
-    """!Class which represents instruction file"""
-    def __init__(self, parent, objectsToDraw):
-        
-        self.parent = parent
-        self.objectsToDraw = objectsToDraw
-        #here are kept objects like mapinfo, rasterlegend, etc.
-        self.instruction = list()
-        
-    def __str__(self):
-        """!Returns text for instruction file"""
-        comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
-        env = grass.gisenv()
-        comment += "# location: %s\n" % env['LOCATION_NAME']
-        comment += "# mapset: %s\n" % env['MAPSET']
-        comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
-        border = ''
-        if not self.FindInstructionByType('map'):
-            border = 'border n\n'
-        text = [str(each) for each in self.instruction]
-        return comment + border + '\n'.join(text) + '\nend'
-    
-    def __getitem__(self, id):
-        for each in self.instruction:
-            if each.id == id:
-                return each
-        return None
-
-    def __contains__(self, id):
-        """!Test if instruction is included"""
-        for each in self.instruction:
-            if each.id == id:
-                return True
-        return False
-    
-    def __delitem__(self, id):
-        """!Delete instruction"""
-        for each in self.instruction:
-            if each.id == id:
-                if each.type == 'map':
-                    #must remove raster, vector layers too
-                    vektor = self.FindInstructionByType('vector', list = True)
-                    vProperties = self.FindInstructionByType('vProperties', list = True)
-                    raster = self.FindInstructionByType('raster', list = True)
-                    for item in vektor + vProperties + raster:
-                        if item in self.instruction:
-                            self.instruction.remove(item)
-                            
-                self.instruction.remove(each)
-                if id in self.objectsToDraw:
-                    self.objectsToDraw.remove(id)
-                return
-            
-    def AddInstruction(self, instruction):
-        """!Add instruction"""
-        # add to instructions
-        if instruction.type == 'map':
-            self.instruction.insert(0, instruction)
-        else:
-            self.instruction.append(instruction)
-        # add to drawable objects
-        if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
-            if instruction.type == 'map':
-                self.objectsToDraw.insert(0, instruction.id) 
-            else:
-                self.objectsToDraw.append(instruction.id) 
-                
-            
-    def FindInstructionByType(self, type, list = False):
-        """!Find instruction(s) with the given type"""
-        inst = []
-        for each in self.instruction:
-            if each.type == type:
-                inst.append(each)
-        if len(inst) == 1 and not list:
-            return inst[0]
-        return inst
-    
-    def Read(self, filename):
-        """!Reads instruction file and creates instruction objects"""
-        self.filename = filename
-        # open file
-        try:
-            file = open(filename, 'r')
-        except IOError:
-            GError(message = _("Unable to open file\n%s") % filename)
-            return
-        # first read file to get information about region and scaletype
-        isRegionComment = False
-        orientation = 'Portrait'
-        for line in file:
-            if '# g.region' in line:
-                self.SetRegion(regionInstruction = line)
-                isRegionComment = True
-                break
-            if '# page orientation' in line:
-                orientation = line.split(':')[-1].strip()
-                
-        if not isRegionComment:
-            self.SetRegion(regionInstruction = None)
-        # then run ps.map -b to get information for maploc
-        # compute scale and center 
-        map = self.FindInstructionByType('map')
-        region = grass.region()
-        map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
-        mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
-        map['rect'] = mapRect
-        proj = projInfo()
-        toM = 1.0
-        if proj['units']:
-            toM = float(proj['meters'])
-        units = UnitConversion(self.parent)
-        w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
-        map['scale'] = w / abs((region['w'] - region['e']))
-        
-        SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
-        
-        # read file again, now with information about map bounds
-        isBuffer = False
-        buffer = []
-        instruction = None
-        vectorMapNumber = 1
-        file.seek(0)
-        for line in file:
-            if not line.strip(): 
-                continue
-            line = line.strip()
-            if isBuffer:
-                buffer.append(line)
-                if 'end' in line:
-                    isBuffer = False
-                    kwargs = {}
-                    if instruction == 'scalebar':
-                        kwargs['scale'] = map['scale']
-                    elif instruction in ('text', 'eps'):
-                        kwargs['mapInstruction'] = map
-                    elif instruction in ('vpoints', 'vlines', 'vareas'):
-                        kwargs['id'] = wx.NewId()
-                        kwargs['vectorMapNumber'] = vectorMapNumber
-                        vectorMapNumber += 1
-                    elif instruction == 'paper':
-                        kwargs['Orientation'] = orientation
-                        
-                    ok = self.SendToRead(instruction, buffer, **kwargs)
-                    if not ok: return False
-                    buffer = []
-                continue 
-            
-            elif line.startswith('paper'):
-                instruction = 'paper'
-                isBuffer = True
-                buffer.append(line)
-            
-            elif line.startswith('border'):
-                if line.split()[1].lower() in ('n', 'no', 'none'):
-                    ok = self.SendToRead('border', [line])
-                    if not ok: return False
-                elif line.split()[1].lower() in ('y', 'yes'):
-                    instruction = 'border'
-                    isBuffer = True
-                    buffer.append(line)
-            
-            elif line.startswith('scale '):
-                if isBuffer:
-                    continue
-                ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
-                if not ok: return False
-            
-            elif line.startswith('maploc'):
-                ok = self.SendToRead(instruction = 'maploc', text = line)
-                if not ok: return False
-                
-            elif line.startswith('raster'):
-                ok = self.SendToRead(instruction = 'raster', text = line)
-                if not ok: return False
-            
-            elif line.startswith('mapinfo'):
-                instruction = 'mapinfo'
-                isBuffer = True
-                buffer.append(line)
-
-
-            elif line.startswith('scalebar'):
-                instruction = 'scalebar'
-                isBuffer = True
-                buffer.append(line) 
-            
-            elif line.startswith('text'):
-                instruction = 'text'
-                isBuffer = True
-                buffer.append(line)
-                
-            elif line.startswith('eps'):
-                instruction = 'eps'
-                isBuffer = True
-                buffer.append(line) 
-            
-            elif line.startswith('colortable'):
-                if len(line.split()) == 2 and line.split()[1].lower() in ('n', 'no', 'none'):
-                    break
-                instruction = 'colortable'
-                isBuffer = True
-                buffer.append(line) 
-        
-            elif line.startswith('vlegend'):
-                instruction = 'vlegend'
-                isBuffer = True
-                buffer.append(line) 
-                
-            elif line.startswith('vpoints'):
-                instruction = 'vpoints'
-                isBuffer = True
-                buffer.append(line) 
-                
-            elif line.startswith('vlines'):
-                instruction = 'vlines'
-                isBuffer = True
-                buffer.append(line)
-                
-            elif line.startswith('vareas'):
-                instruction = 'vareas'
-                isBuffer = True
-                buffer.append(line)
-
-
-        
-        rasterLegend = self.FindInstructionByType('rasterLegend')
-        raster = self.FindInstructionByType('raster')
-        page = self.FindInstructionByType('page')
-        vector = self.FindInstructionByType('vector')
-        vectorLegend = self.FindInstructionByType('vectorLegend')
-        vectorMaps = self.FindInstructionByType('vProperties', list = True)
-
-        # check (in case of scaletype 0) if map is drawn also
-        map['drawMap'] = False
-        if map['scaleType'] == 0:
-            mapForRegion = map['map']
-            if map['mapType'] == 'raster' and raster:
-                if mapForRegion == raster['raster']:
-                    map['drawMap'] = True
-            elif map['mapType'] == 'vector' and vector:
-                for vmap in vector['list']:
-                    if mapForRegion == vmap[0]:
-                        map['drawMap'] = True
-
-        # rasterLegend
-        if rasterLegend:
-            if rasterLegend['rasterDefault'] and raster:
-                rasterLegend['raster'] = raster['raster']
-                if not rasterLegend['discrete']:
-                    rasterType = getRasterType(map = rasterLegend['raster'])
-                    if rasterType == 'CELL':
-                        rasterLegend['discrete'] = 'y'
-                    else:
-                        rasterLegend['discrete'] = 'n'
-            
-            #estimate size
-            height = rasterLegend.EstimateHeight(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
-                                                 fontsize = rasterLegend['fontsize'],
-                                                 cols = rasterLegend['cols'], 
-                                                 height = rasterLegend['height'])
-            width = rasterLegend.EstimateWidth(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
-                                               fontsize = rasterLegend['fontsize'],
-                                               cols = rasterLegend['cols'] , 
-                                               width = rasterLegend['width'],
-                                               paperInstr = page)
-            rasterLegend['rect'] = wx.Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
-                                             w = width, h = height)
-            
-        # vectors, vlegend        
-        
-        if vector:
-            for vmap in vectorMaps:
-                for i, each in enumerate(vector['list']):
-                    if each[2] == vmap.id:
-                        
-                        vector['list'][i][4] = vmap['label']
-                        vector['list'][i][3] = vmap['lpos']
-            if vectorLegend:
-                size = vectorLegend.EstimateSize(vectorInstr = vector, fontsize = vectorLegend['fontsize'],
-                                                 width = vectorLegend['width'], cols = vectorLegend['cols'])                            
-                vectorLegend['rect'] = wx.Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
-                                                 w = size[0], h = size[1])
-        
-        
-        page = self.FindInstructionByType('page')
-        if not page:
-            page = PageSetup(wx.NewId())
-            self.AddInstruction(page)
-        else:
-            page['Orientation'] = orientation
-
-
-        #
-        return True
-    
-    def SendToRead(self, instruction, text, **kwargs):
-        psmapInstrDict = dict(paper = ['page'],
-                              maploc = ['map'],
-                              scale = ['map'],
-                              border = ['map'],
-                              raster = ['raster'],
-                              mapinfo = ['mapinfo'],
-                              scalebar = ['scalebar'],
-                              text = ['text'],
-                              eps = ['image', 'northArrow'],
-                              vpoints = ['vector', 'vProperties'],
-                              vlines = ['vector', 'vProperties'],
-                              vareas = ['vector', 'vProperties'],
-                              colortable = ['rasterLegend'],
-                              vlegend = ['vectorLegend']
-                              )
-        
-        myInstrDict = dict(page = PageSetup,
-                           map = MapFrame,
-                           raster = Raster,
-                           mapinfo = Mapinfo,
-                           scalebar = Scalebar,
-                           text = Text,
-                           image = Image,
-                           northArrow = NorthArrow,
-                           rasterLegend = RasterLegend,
-                           vectorLegend = VectorLegend,
-                           vector = Vector,
-                           vProperties = VProperties
-                           )
-        
-        myInstruction = psmapInstrDict[instruction]
-        
-        for i in myInstruction:
-            instr = self.FindInstructionByType(i)
-            if i in ('text', 'vProperties', 'image', 'northArrow') or not instr:
-                
-                id = wx.NewId() #!vProperties expect subtype
-                if i == 'vProperties':
-                    id = kwargs['id']
-                    newInstr = myInstrDict[i](id, subType = instruction[1:])
-                elif i in ('image', 'northArrow'):
-                    commentFound = False
-                    for line in text:
-                        if line.find("# north arrow") >= 0:
-                            commentFound = True
-                    if i == 'image' and commentFound or \
-                       i == 'northArrow' and not commentFound:
-                        continue
-                    newInstr = myInstrDict[i](id, settings = self)
-                else:
-                    newInstr = myInstrDict[i](id)
-                ok = newInstr.Read(instruction, text, **kwargs)
-                if ok:
-                    self.AddInstruction(newInstr)
-                else:
-                    return False
-
-            else:
-                ok = instr.Read(instruction, text, **kwargs)
-
-                if not ok:
-                    return False
-        return True
-    
-    def SetRegion(self, regionInstruction):
-        """!Sets region from file comment or sets current region in case of no comment"""
-        map = MapFrame(wx.NewId())
-        self.AddInstruction(map)
-        if regionInstruction:
-            cmd = CmdToTuple(regionInstruction.strip('# ').split())
-            
-            # define scaleType
-            if len(cmd[1]) <= 3:
-                if 'rast' in cmd[1]:
-                    map['scaleType'] = 0
-                    map['mapType'] = 'raster'   
-                    map['map'] = cmd[1]['rast']  
-                elif 'vect' in cmd[1]:
-                    map['scaleType'] = 0
-                    map['mapType'] = 'vector' 
-                    map['map'] = cmd[1]['vect']  
-                elif 'region' in cmd[1]:
-                    map['scaleType'] = 1  
-                    map['region'] = cmd[1]['region']
-                    
-            else:
-                map['scaleType'] = 2  
-        else:
-            map['scaleType'] = 2
-            grass.del_temp_region()
-            region = grass.region()
-            grass.use_temp_region()    
-            cmd = ['g.region', region]
-        cmdString = GetCmdString(cmd).replace('g.region', '')
-        GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
-        try:
-            RunCommand(cmd[0], **cmd[1])
-            
-        except grass.ScriptError, e:
-            GError(_("Region cannot be set\n%s") % e)
-            return False
-        
-
-class InstructionObject:
-    """!Abtract class representing single instruction"""
-    def __init__(self, id): 
-        self.id = id
-        
-        # default values
-        self.defaultInstruction = dict()
-        # current values
-        self.instruction = self.defaultInstruction   
-        # converting units
-        self.unitConv = UnitConversion() 
-    
-    def __str__(self):
-        """!Returns particular part of text instruction"""
-        return ''
-    
-    def __getitem__(self, key):
-        for each in self.instruction.keys():
-            if each == key:
-                return self.instruction[key]
-        return None
-    
-    def __setitem__(self, key, value):
-        self.instruction[key] = value
-    
-    def GetInstruction(self):
-        """!Get current values"""
-        return self.instruction
-    
-    def SetInstruction(self, instruction):
-        """!Set default values"""
-        self.instruction = instruction
-        
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save them"""
-        pass
-    
-class InitMap(InstructionObject):
-    """!Class representing virtual map"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'initMap'
-        
-        # default values
-        self.defaultInstruction = dict(rect = None, scale =  None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    
-class MapFrame(InstructionObject):
-    """!Class representing map (instructions maploc, scale, border)"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'map'
-        # default values
-        self.defaultInstruction = dict(map = None, mapType = None, drawMap = True, region = None,
-                                       rect = wx.Rect2D(), scaleType = 0, scale = None, center = None,
-                                       resolution = 300, border = 'y', width = 1, color = '0:0:0') 
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = ''
-        comment = ''
-        
-        #region settings
-        region = grass.region()
-        if self.instruction['scaleType'] == 0: #match map
-            map = self.instruction['map']
-            if self.instruction['mapType'] == 'raster':
-                comment = "# g.region rast=%s nsres=%s ewres=%s\n" % (map, region['nsres'], region['ewres'])
-            else:
-                comment = "# g.region vect=%s\n" % (map)
-        elif self.instruction['scaleType'] == 1:# saved region
-            region = self.instruction['region']
-            comment = "# g.region region=%s\n" % region
-        elif self.instruction['scaleType'] in (2, 3): #current region, fixed scale
-            comment = string.Template("# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region)
-        
-        instr += comment
-        instr += '\n'
-        # maploc
-        maplocInstruction = "maploc %.3f %.3f" % (self.instruction['rect'].x, self.instruction['rect'].y)
-        if self.instruction['scaleType'] != 3:
-            maplocInstruction += "  %.3f %.3f"% (self.instruction['rect'].width, self.instruction['rect'].height)
-        instr += maplocInstruction
-        instr += '\n'
-        
-        # scale
-        if self.instruction['scaleType'] == 3: #fixed scale
-            scaleInstruction = "scale 1:%.0f" % (1/self.instruction['scale'])
-            instr += scaleInstruction
-            instr += '\n'
-        # border
-        borderInstruction = ''
-        if self.instruction['border'] == 'n':
-            borderInstruction = "border n"
-        else:
-            borderInstruction = "border y\n"
-            borderInstruction += string.Template("    width $width\n    color $color\n").substitute(self.instruction)
-            borderInstruction += "    end"
-        instr += borderInstruction
-        instr += '\n'
-
-        return instr  
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        if 'isRegionComment' in kwargs:
-            isRegionComment = kwargs['isRegionComment']
-        instr = {}
-        
-        if instruction == 'border':
-            for line in text:
-                if line.startswith('end'):
-                    break
-                try:
-                    if line.split()[1].lower() in ('n', 'no', 'none'):
-                        instr['border'] = 'n'
-                        break
-                    elif line.split()[1].lower() in ('y', 'yes'):
-                        instr['border'] = 'y'
-                    elif line.startswith('width'):
-                        instr['width'] = line.split()[1]
-                    elif line.startswith('color'):
-                        instr['color'] = line.split()[1]
-                except IndexError:
-                    GError(_("Failed to read instruction %s") % instruction)
-                    return False
-                
-        elif instruction == 'scale':
-            try:
-                scaleText = text.strip('scale ').split(':')[1]
-                # when scale instruction given and region comment also, then scaletype is fixed scale
-                if not isRegionComment:
-                    instr['scaleType'] = 2 
-                else:
-                    instr['scaleType'] = 3
-
-                scale = 1/float(scaleText)
-                if abs(scale - self.instruction['scale']) > (0.01 * scale):
-                    GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % \
-                                 { 'old' : scale, 'new' : self.instruction['scale'] })
-            except (ValueError, IndexError):
-                GError(_("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction)
-                return False
-        
-        elif instruction == 'maploc':
-            maploc = text.strip('maploc ').split()
-            if len(maploc) >= 2:
-                if  abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \
-                        abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5:
-                    GWarning(_("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
-                                 { 'old1' : maploc[0], 'old2' : maploc[1],
-                                   'new1' : self.instruction['rect'].Get()[0], 'new2' : self.instruction['rect'].Get()[1] })
-                    
-                #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3])
-            if len(maploc) == 4:
-                if  abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \
-                        abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5:
-                    GWarning(_("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
-                                 { 'old1' : maploc[2], 'old2' : maploc[3],
-                                   'new1' : self.instruction['rect'].Get()[2], 'new2' : self.instruction['rect'].Get()[3] })
-                #instr['rect'] = wx.Rect2D(*map(float, maploc))
-        self.instruction.update(instr)   
-        return True 
-    
-class PageSetup(InstructionObject):
-    """!Class representing page instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'page'
-        # default values
-        self.defaultInstruction = dict(Units = 'inch', Format = 'a4', Orientation = 'Portrait',
-                                       Width = 8.268, Height = 11.693, Left = 0.5, Right = 0.5, Top = 1, Bottom = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        if self.instruction['Format'] == 'custom':
-            instr = string.Template("paper\n    width $Width\n    height $Height\n").substitute(self.instruction)
-        else:
-            instr = string.Template("paper $Format\n").substitute(self.instruction)
-        instr += string.Template("    left $Left\n    right $Right\n    bottom $Bottom\n    top $Top\n    end").substitute(self.instruction)
-
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
-        self.subInstr = dict(zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats))
-        
-        if instruction == 'paper': # just for sure
-            for line in text:
-                if line.startswith('paper'): 
-                    if len(line.split()) > 1:
-                        pformat = line.split()[1]
-                        availableFormats = self._toDict(grass.read_command('ps.map', flags = 'p',
-                                                                           quiet = True))
-                        # e.g. paper a3 
-                        try:
-                            instr['Format'] = pformat
-                            for key, value in availableFormats[pformat].iteritems():
-                                instr[key] = float(value)
-                            break
-                        except KeyError:
-                            GError(_("Failed to read instruction %(file)s.\nUnknown format %(for)s") % \
-                                       { 'file' : instruction, 'for' : format })
-                            return False
-                    else:
-                        # paper
-                        # width ...
-                        instr['Format'] = 'custom'
-                # read subinstructions
-                elif instr['Format'] == 'custom' and not line.startswith('end'):
-                    text = line.split()
-                    try:
-                        instr[self.subInstr[text[0]]] = float(text[1])
-                    except  (IndexError, KeyError):
-                        GError(_("Failed to read instruction %s.") % instruction)
-                        return False
-                    
-            if 'Orientation' in kwargs and kwargs['Orientation'] == 'Landscape':
-                instr['Width'], instr['Height'] = instr['Height'], instr['Width']
-                
-            self.instruction.update(instr)
-        return True  
-    
-    def _toDict(self, paperStr):    
-        sizeDict = dict()
-#     cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
-        for line in paperStr.strip().split('\n'):
-            d = dict(zip(self.cats, line.split()[1:]))
-            sizeDict[line.split()[0]] = d
-            
-        return sizeDict    
-    
-class Mapinfo(InstructionObject):
-    """!Class representing mapinfo instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'mapinfo'
-        # default values
-        self.defaultInstruction = dict(unit = 'inch', where = (0, 0),
-                                       font = 'Helvetica', fontsize = 10, color = '0:0:0', background = 'none', 
-                                       border = 'none', rect = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "mapinfo\n"
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").substitute(self.instruction)            
-        instr += string.Template("    background $background\n    border $border\n").substitute(self.instruction)  
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text):
-        """!Read instruction and save information"""
-        instr = {}
-        try:
-            for line in text:
-                sub = line.split(None,1)
-                if sub[0] == 'font':
-                    instr['font'] = sub[1]
-                elif sub[0] == 'fontsize':
-                    instr['fontsize'] = int(sub[1])
-                elif sub[0] == 'color':
-                    instr['color'] = sub[1]
-                elif sub[0] == 'background':
-                    instr['background'] = sub[1]
-                elif sub[0] == 'border':
-                    instr['border'] = sub[1]
-                elif sub[0] == 'where':
-                    instr['where'] = float(sub[1].split()[0]), float(sub[1].split()[1])
-        except (ValueError, IndexError):
-            GError(_("Failed to read instruction %s") % instruction)
-            return False
-        self.instruction.update(instr)
-        self.instruction['rect'] = self.EstimateRect(mapinfoDict = self.instruction)
-        return True
-    
-    def EstimateRect(self, mapinfoDict):
-        """!Estimate size to draw mapinfo"""
-        w = mapinfoDict['fontsize'] * 20 # any better estimation? 
-        h = mapinfoDict['fontsize'] * 7
-        width = self.unitConv.convert(value = w, fromUnit = 'point', toUnit = 'inch')
-        height = self.unitConv.convert(value = h, fromUnit = 'point', toUnit = 'inch')
-        return wx.Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]), w = width, h = height)
-    
-class Text(InstructionObject):
-    """!Class representing text instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'text'
-        # default values
-        self.defaultInstruction = dict(text = "", font = "Helvetica", fontsize = 10, color = 'black', background = 'none',
-                                       hcolor = 'none', hwidth = 1, border = 'none', width = '1', XY = True,
-                                       where = (0,0), unit = 'inch', rotate = None, 
-                                       ref = "center center", xoffset = 0, yoffset = 0, east = None, north = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        text = self.instruction['text'].replace('\n','\\n')
-        instr = "text %s %s" % (self.instruction['east'], self.instruction['north'])
-        try:
-            instr += " %s\n" % text.encode('latin_1')
-        except UnicodeEncodeError, err:
-            try:
-                pos = str(err).split('position')[1].split(':')[0].strip()
-            except IndexError:
-                pos = ''
-            if pos:
-                message = _("Characters on position %s are not supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.") % pos
-            else:
-                message = _("Not all characters are supported "
-                            "by ISO-8859-1 (Latin 1) encoding "
-                            "which is required by module ps.map.")
-            GMessage(message = message)
-            return ''
-        instr += (string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").
-                                                                   substitute(self.instruction).
-                                                                   encode('latin_1'))
-        instr += string.Template("    hcolor $hcolor\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction['hcolor'] != 'none':
-            instr += string.Template("    hwidth $hwidth\n").substitute(self.instruction).encode('latin_1')
-        instr += string.Template("    border $border\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction['border'] != 'none':
-            instr += string.Template("    width $width\n").substitute(self.instruction).encode('latin_1')
-        instr += string.Template("    background $background\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction["ref"] != '0':
-            instr += string.Template("    ref $ref\n").substitute(self.instruction).encode('latin_1')
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction).encode('latin_1')
-        if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
-            instr += (string.Template("    xoffset $xoffset\n    yoffset $yoffset\n").
-                                                            substitute(self.instruction).encode('latin_1'))
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        map = kwargs['mapInstruction']
-        instr = {}
-        for line in text:
-            try:
-                sub = line.split(None, 1)[0]
-                if sub == 'text':
-                    e, n = line.split(None, 3)[1:3]
-                    if '%' in e and '%' in n:
-                        instr['XY'] = True
-                        instr['east'], instr['north'] = self.PercentToReal(e, n)
-                    else:
-                        instr['XY'] = False
-                        instr['east'], instr['north'] = float(e), float(n)
-                        
-                    instr['text'] = line.split(None, 3)[3]
-                
-                elif sub == 'font':
-                    instr['font'] = line.split(None, 1)[1]
-                elif sub == 'fontsize':
-                    instr['fontsize'] = float(line.split(None, 1)[1])
-                elif sub == 'color':
-                    instr['color'] = line.split(None, 1)[1]
-                elif sub == 'width':
-                    instr['width'] = line.split(None, 1)[1]
-                elif sub == 'hcolor':
-                    instr['hcolor'] = line.split(None, 1)[1]
-                elif sub == 'hwidth':
-                    instr['hwidth'] = line.split(None, 1)[1]
-                elif sub == 'background':
-                    instr['background'] = line.split(None, 1)[1]
-                elif sub == 'border':
-                    instr['border'] = line.split(None, 1)[1]
-                elif sub == 'ref':
-                    instr['ref'] = line.split(None, 1)[1]
-                elif sub == 'rotate':
-                    instr['rotate'] = float(line.split(None, 1)[1])
-                elif sub == 'xoffset':
-                    instr['xoffset'] = int(line.split(None, 1)[1])
-                elif sub == 'yoffset':
-                    instr['yoffset'] = int(line.split(None, 1)[1])
-                elif sub == 'opaque':
-                    if line.split(None, 1)[1].lower() in ('n', 'none'):
-                        instr['background'] = 'none'
-                        
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-        instr['where'] = PaperMapCoordinates(map = map, x = instr['east'], y = instr['north'], paperToMap = False)       
-        self.instruction.update(instr)
-
-        return True 
-    
-    def PercentToReal(self, e, n):
-        """!Converts text coordinates from percent of region to map coordinates"""
-        e, n = float(e.strip('%')), float(n.strip('%'))
-        region = grass.region()
-        N = region['s'] + (region['n'] - region['s']) / 100 * n
-        E = region['w'] + (region['e'] - region['w']) / 100 * e
-        return E, N
-        
-class Image(InstructionObject):
-    """!Class representing eps instruction - image"""
-    def __init__(self, id, settings):
-        InstructionObject.__init__(self, id = id)
-        self.settings = settings
-        self.type = 'image'
-        # default values
-        self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
-                                       east = None, north = None,
-                                       rotate = None, scale = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        self.ChangeRefPoint(toCenter = True)
-        
-        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
-        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
-        if self.instruction["scale"]:
-            instr += string.Template("    scale $scale\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        mapInstr = kwargs['mapInstruction']
-        instr = {}
-        for line in text:
-            try:
-                sub = line.split(None, 1)[0]
-                if sub == 'eps':
-                    e, n = line.split(None, 3)[1:3]
-                    if '%' in e and '%' in n:
-                        instr['XY'] = True
-                        instr['east'], instr['north'] = self.PercentToReal(e, n)
-                    else:
-                        instr['XY'] = False
-                        instr['east'], instr['north'] = float(e), float(n)
-                
-                elif sub == 'epsfile':
-                    instr['epsfile'] = line.split(None, 1)[1]
-                elif sub == 'rotate':
-                    instr['rotate'] = float(line.split(None, 1)[1])
-                elif sub == 'scale':
-                    instr['scale'] = float(line.split(None, 1)[1])
-                        
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-        if not os.path.exists(instr['epsfile']):
-            GError(_("Failed to read instruction %s: file %s not found.") % instruction, instr['epsfile'])
-            return False
-        
-        instr['epsfile'] = os.path.abspath(instr['epsfile'])
-        instr['size'] = self.GetImageOrigSize(instr['epsfile'])
-        if 'rotate' in instr:
-            instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
-        self.instruction.update(instr)
-        self.ChangeRefPoint(toCenter = False)
-        instr['where'] = PaperMapCoordinates(map = mapInstr, x = self.instruction['east'],
-                                             y = self.instruction['north'], paperToMap = False)       
-        w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
-        h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
-        instr['rect'] = wx.Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
-                                  w = w * self.instruction['scale'], h = h * self.instruction['scale'])
-        self.instruction.update(instr)
-
-        return True 
-    
-    def PercentToReal(self, e, n):
-        """!Converts eps coordinates from percent of region to map coordinates"""
-        e, n = float(e.strip('%')), float(n.strip('%'))
-        region = grass.region()
-        N = region['s'] + (region['n'] - region['s']) / 100 * n
-        E = region['w'] + (region['e'] - region['w']) / 100 * e
-        return E, N
-        
-    def ChangeRefPoint(self, toCenter):
-        """!Change reference point (left top x center)"""
-        mapInstr = self.settings.FindInstructionByType('map')
-        if not mapInstr:
-            mapInstr = self.settings.FindInstructionByType('initMap')
-        mapId = mapInstr.id
-        if toCenter:
-            center = self.instruction['rect'].GetCentre()
-            ENCenter = PaperMapCoordinates(map = self.settings[mapId],
-                                           x = center[0], y = center[1], paperToMap = True)
-                                           
-            self.instruction['east'], self.instruction['north'] = ENCenter
-        else:
-            x, y = PaperMapCoordinates(map = self.settings[mapId], x = self.instruction['east'],
-                                       y = self.instruction['north'], paperToMap = False)
-            w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
-            h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
-            x -= w * self.instruction['scale'] / 2
-            y -= h * self.instruction['scale'] / 2
-            e, n = PaperMapCoordinates(map = self.settings[mapId], x = x, y = y, paperToMap = True)
-            self.instruction['east'], self.instruction['north'] = e, n
-
-    def GetImageOrigSize(self, imagePath):
-        """!Get image size.
-        
-        If eps, size is read from image header.
-        """
-        fileName = os.path.split(imagePath)[1]
-        # if eps, read info from header
-        if os.path.splitext(fileName)[1].lower() == '.eps':
-            bbInfo = "%%BoundingBox"
-            file = open(imagePath,"r")
-            w = h = 0
-            while file:
-                line = file.readline()
-                if line.find(bbInfo) == 0:
-                    w, h = line.split()[3:5]
-                    break
-            file.close()
-            return float(w), float(h)
-        else: # we can use wx.Image
-            img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
-            return img.GetWidth(), img.GetHeight()
-            
-class NorthArrow(Image):
-    """!Class representing eps instruction -- North Arrow"""
-    def __init__(self, id, settings):
-        Image.__init__(self, id = id, settings = settings)
-        self.type = 'northArrow'
-        
-    def __str__(self):
-        self.ChangeRefPoint(toCenter = True)
-        
-        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
-        instr += "# north arrow\n"
-        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
-        if self.instruction["rotate"]:
-            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
-        if self.instruction["scale"]:
-            instr += string.Template("    scale $scale\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-        
-class Scalebar(InstructionObject):
-    """!Class representing scalebar instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'scalebar'
-        # default values
-        self.defaultInstruction = dict(unit = 'inch', where = (1,1),
-                                       unitsLength = 'auto', unitsHeight = 'inch',
-                                       length = None, height = 0.1, rect = None,
-                                       fontsize = 10, background = 'y',
-                                       scalebar = 'f', segment = 4, numbers = 1)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = string.Template("scalebar $scalebar\n").substitute(self.instruction)
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    length $length\n    units $unitsLength\n").substitute(self.instruction)
-        instr += string.Template("    height $height\n").substitute(self.instruction)
-        instr += string.Template("    segment $segment\n    numbers $numbers\n").substitute(self.instruction)
-        instr += string.Template("    fontsize $fontsize\n    background $background\n").substitute(self.instruction)
-        instr += "    end"
-        return instr
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        scale = kwargs['scale']
-        instr = {}
-        for line in text:
-            try:
-                if line.startswith('scalebar'):
-                    if 'scalebar s' in line:
-                        instr['scalebar'] = 's'
-                    else:
-                        instr['scalebar'] = 'f'
-                elif line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('length'):
-                    instr['length'] = float(line.split()[1])
-                elif line.startswith('units'):
-                    if line.split()[1] in ['auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']:
-                        instr['unitsLength'] = line.split()[1]
-                elif line.startswith('height'):
-                    instr['height'] = float(line.split()[1])
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('numbers'):
-                    instr['numbers'] = int(line.split()[1])
-                elif line.startswith('segment'):
-                    instr['segment'] = int(line.split()[1])
-                elif line.startswith('background'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['background'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['background'] = 'n'
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        self.instruction.update(instr)
-        w, h = self.EstimateSize(scalebarDict = self.instruction, scale = scale)
-        x = self.instruction['where'][0] - w / 2 
-        y = self.instruction['where'][1] - h / 2
-        self.instruction['rect'] = wx.Rect2D(x, y, w, h)
-        return True 
-    
-    def EstimateSize(self, scalebarDict, scale):
-        """!Estimate size to draw scalebar"""
-        units = projInfo()['units']
-        if not units or units not in self.unitConv.getAllUnits():
-            units = 'meters'
-        if scalebarDict['unitsLength'] != 'auto':
-            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = scalebarDict['unitsLength'], toUnit = 'inch')
-        else:
-            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = units, toUnit = 'inch')
-            
-        length *= scale
-        length *= 1.1 #for numbers on the edge
-        height = scalebarDict['height'] + 2 * self.unitConv.convert(value = scalebarDict['fontsize'], fromUnit = 'point', toUnit = 'inch')     
-        return (length, height)
-    
-class RasterLegend(InstructionObject):
-    """!Class representing colortable instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'rasterLegend'
-        # default values
-        self.defaultInstruction = dict(rLegend = False, unit = 'inch', rasterDefault = True, raster = None,
-                                       discrete = None, type = None,
-                                       where = (0, 0),
-                                       width = None, height = None, cols = 1, font = "Helvetica", fontsize = 10,
-                                       #color = '0:0:0', tickbar = False, range = False, min = 0, max = 0,
-                                       color = 'black', tickbar = 'n', range = False, min = 0, max = 0,
-                                       nodata = 'n')
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "colortable y\n"
-        instr += string.Template("    raster $raster\n").substitute(self.instruction)
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        if self.instruction['width']:
-            instr += string.Template("    width $width\n").substitute(self.instruction)
-        instr += string.Template("    discrete $discrete\n").substitute(self.instruction)
-        if self.instruction['discrete'] == 'n':
-            if self.instruction['height']:
-                instr += string.Template("    height $height\n").substitute(self.instruction)
-            instr += string.Template("    tickbar $tickbar\n").substitute(self.instruction)
-            if self.instruction['range']:
-                instr += string.Template("    range $min $max\n").substitute(self.instruction)
-        else:
-            instr += string.Template("    cols $cols\n").substitute(self.instruction)
-            instr += string.Template("    nodata $nodata\n").substitute(self.instruction)
-        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n")\
-            .substitute(self.instruction)
-        instr += "    end"
-        return instr    
-    
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['rLegend'] = True
-        for line in text:
-            try:
-                if line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('font '):
-                    instr['font'] = line.split()[1]
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('color '):
-                    instr['color'] = line.split()[1]
-                elif line.startswith('raster'):
-                    instr['raster'] = line.split()[1]
-                elif line.startswith('width'):
-                    instr['width'] = float(line.split()[1])
-                elif line.startswith('height'):
-                    instr['height'] = float(line.split()[1])
-                elif line.startswith('cols'):
-                    instr['cols'] = int(line.split()[1])                    
-                elif line.startswith('range'):
-                    instr['range'] = True
-                    instr['min'] = float(line.split()[1])
-                    instr['max'] = float(line.split()[2])
-                elif line.startswith('nodata'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['nodata'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['nodata'] = 'n'
-                elif line.startswith('tickbar'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['tickbar'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['tickbar'] = 'n'
-                elif line.startswith('discrete'):
-                    if line.split()[1].strip().lower() in ('y','yes'):
-                        instr['discrete'] = 'y'
-                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
-                        instr['discrete'] = 'n'            
-
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        if 'raster' in instr:
-            instr['rasterDefault'] = False
-            if 'discrete' not in instr:
-                rasterType = getRasterType(map = instr['raster'])
-                instr['type'] = rasterType
-                if rasterType == 'CELL':
-                    instr['discrete'] = 'y'
-                else:
-                    instr['discrete'] = 'n'
-            
-        else:
-            instr['rasterDefault'] = True
-        self.instruction.update(instr)
-        # add 'rect' in the end
-            
-        return True 
-    
-    def EstimateHeight(self, raster, discrete, fontsize, cols = None,  height = None):
-        """!Estimate height to draw raster legend"""
-        if discrete == 'n':
-            if height:
-                height = height
-            else:
-                height = self.unitConv.convert(value = fontsize * 10,
-                                                    fromUnit = 'point', toUnit = 'inch')
-                                                    
-        if discrete == 'y':
-            if cols:
-                cols = cols 
-            else:
-                cols = 1 
-
-            rinfo = grass.raster_info(raster)
-            if rinfo['datatype'] in ('DCELL', 'FCELL'):
-                minim, maxim = rinfo['min'], rinfo['max']
-                rows = ceil(maxim / cols )
-            else:
-                cat = grass.read_command('r.category', map = raster,
-                                    fs = ':').strip().split('\n')
-                rows = ceil(float(len(cat)) / cols )
-                            
-                
-            height = self.unitConv.convert(value =  1.5 * rows * fontsize, fromUnit = 'point', toUnit = 'inch')
-            
-        return height
-        
-    def EstimateWidth(self, raster, discrete, fontsize, cols = None, width = None, paperInstr = None):
-        """!Estimate size to draw raster legend"""
-        
-        if discrete == 'n':
-            rinfo = grass.raster_info(raster)
-            minim, maxim = rinfo['min'], rinfo['max']
-            if width:
-                width = width
-            else:
-                width = self.unitConv.convert(value = fontsize * 2,
-                                                    fromUnit = 'point', toUnit = 'inch')
-            text = len(max(str(minim), str(maxim), key = len))
-            textPart = self.unitConv.convert(value = text * fontsize / 2,
-                                                    fromUnit = 'point', toUnit = 'inch')
-            width += textPart
-                                                    
-        elif discrete == 'y':
-            if cols:
-                cols = cols 
-            else:
-                cols = 1    
-
-            if width:
-                width = width
-            else:
-                paperWidth = paperInstr['Width'] - paperInstr['Right'] - paperInstr['Left']
-                width = (paperWidth / cols) * (cols - 1) + 1
-                
-        return width    
-             
-class VectorLegend(InstructionObject):
-    """!Class representing colortable instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vectorLegend'
-        # default values
-        self.defaultInstruction = dict(vLegend = False, unit = 'inch', where = (0, 0),
-                                                defaultSize = True, width = 0.4, cols = 1, span = None,
-                                                font = "Helvetica", fontsize = 10,
-                                                border = 'none')
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = "vlegend\n"
-        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
-        instr += string.Template("    font $font\n    fontsize $fontsize\n").substitute(self.instruction)
-        instr += string.Template("    width $width\n    cols $cols\n").substitute(self.instruction)
-        if self.instruction['span']:
-            instr += string.Template("    span $span\n").substitute(self.instruction)
-        instr += string.Template("    border $border\n").substitute(self.instruction)  
-        instr += "    end"  
-        return instr
-
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['vLegend'] = True
-        for line in text:
-            try:
-                if line.startswith('where'):
-                    instr['where'] = map(float, line.split()[1:3])
-                elif line.startswith('font '):
-                    instr['font'] = line.split()[1]
-                elif line.startswith('fontsize'):
-                    instr['fontsize'] = float(line.split()[1])
-                elif line.startswith('width'):
-                    instr['width'] = float(line.split()[1])
-                elif line.startswith('cols'):
-                    instr['cols'] = int(line.split()[1]) 
-                elif line.startswith('span'):
-                    instr['span'] = float(line.split()[1])
-                elif line.startswith('border'):
-                    instr['border'] = line.split()[1]
-                    
-            except(IndexError, ValueError):
-                GError(_("Failed to read instruction %s") % instruction)
-                return False
-            
-        self.instruction.update(instr)
-            
-        return True 
-    
-    def EstimateSize(self, vectorInstr, fontsize, width = None, cols = None):
-        """!Estimate size to draw vector legend"""
-        if width:
-            width = width 
-        else:
-            width = fontsize/24.0
-
-        if cols:
-            cols = cols 
-        else:
-            cols = 1
-
-        vectors = vectorInstr['list']
-        labels = [vector[4] for vector in vectors if vector[3] != 0]
-        extent = (len(max(labels, key = len)) * fontsize / 2, fontsize)
-        wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'point', toUnit = 'inch')
-        hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'point', toUnit = 'inch')
-        w = (width + wExtent) * cols
-        h = len(labels) * hExtent / cols
-        h *= 1.1
-        return (w, h)
-            
-   
-class Raster(InstructionObject):
-    """!Class representing raster instruction"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'raster'
-        # default values
-        self.defaultInstruction = dict(isRaster = False, raster = None)
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        instr = string.Template("raster $raster").substitute(self.instruction)
-        return instr
-    
-    def Read(self, instruction, text):
-        """!Read instruction and save information"""
-        instr = {}
-        instr['isRaster'] = True
-        try:
-            map = text.split()[1]
-        except IndexError:
-            GError(_("Failed to read instruction %s") % instruction)
-            return False
-        try:
-            info = grass.find_file(map, element = 'cell')
-        except grass.ScriptError, e:
-            GError(message = e.value)
-            return False
-        instr['raster'] = info['fullname']
-
-        
-        self.instruction.update(instr)
-        return True
-    
-class Vector(InstructionObject):
-    """!Class keeps vector layers"""
-    def __init__(self, id):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vector'
-        # default values
-        self.defaultInstruction = dict(list = None)# [vmap, type, id, lpos, label] 
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-    def __str__(self):
-        return ''
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        
-        for line in text:
-            if line.startswith('vpoints') or line.startswith('vlines') or line.startswith('vareas'):
-                # subtype
-                if line.startswith('vpoints'):
-                    subType = 'points'
-                elif line.startswith('vlines'):
-                    subType = 'lines'
-                elif line.startswith('vareas'):
-                    subType = 'areas'
-                # name of vector map
-                vmap = line.split()[1]
-                try:
-                    info = grass.find_file(vmap, element = 'vector')
-                except grass.ScriptError, e:
-                    GError(message = e.value)
-                    return False
-                vmap = info['fullname']
-                # id
-                id = kwargs['id']
-                # lpos
-                lpos = kwargs['vectorMapNumber']
-                #label
-                label = '('.join(vmap.split('@')) + ')'
-                break
-        instr = [vmap, subType, id, lpos, label] 
-        if not self.instruction['list']:
-            self.instruction['list'] = []
-        self.instruction['list'].append(instr)
-        
-        return True    
-    
-class VProperties(InstructionObject):
-    """!Class represents instructions vareas, vlines, vpoints"""
-    def __init__(self, id, subType):
-        InstructionObject.__init__(self, id = id)
-        self.type = 'vProperties'
-        self.subType = subType
-        # default values
-        if self.subType == 'points':
-            dd = dict(subType  = 'points', name = None, type = 'point or centroid', connection = False, layer = '1',
-                        masked = 'n', color = '0:0:0', width = 1,
-                        fcolor = '255:0:0', rgbcolumn = None, symbol = os.path.join('basic', 'x'), eps = None,
-                        size = 5, sizecolumn = None, scale = None,
-                        rotation = False, rotate = 0, rotatecolumn = None, label = None, lpos = None)
-        elif self.subType == 'lines':
-            dd = dict(subType = 'lines', name = None, type = 'line or boundary', connection = False, layer = '1',
-                        masked = 'n', color = '0:0:0', hwidth = 1,
-                        hcolor = 'none', rgbcolumn = None,
-                        width = 1, cwidth = None,
-                        style = 'solid', linecap = 'butt', label = None, lpos = None)
-        else: # areas
-            dd = dict(subType = 'areas', name = None, connection = False, layer = '1',    
-                        masked = 'n', color = '0:0:0', width = 1,
-                        fcolor = 'none', rgbcolumn = None,
-                        pat = None, pwidth = 1, scale = 1, label = None, lpos = None)
-        self.defaultInstruction = dd
-        # current values
-        self.instruction = dict(self.defaultInstruction)
-        
-    def __str__(self):
-        dic = self.instruction
-        vInstruction = string.Template("v$subType $name\n").substitute(dic)
-        #data selection
-        if self.subType in ('points', 'lines'):
-           vInstruction += string.Template("    type $type\n").substitute(dic) 
-        if dic['connection']:
-            vInstruction += string.Template("    layer $layer\n").substitute(dic)
-            if dic.has_key('cats'):
-                vInstruction += string.Template("    cats $cats\n").substitute(dic)
-            elif dic.has_key('where'):
-                    vInstruction += string.Template("    where $where\n").substitute(dic)
-        vInstruction += string.Template("    masked $masked\n").substitute(dic)
-        #colors
-        vInstruction += string.Template("    color $color\n").substitute(dic)
-        if self.subType in ('points', 'areas'):
-            if dic['color'] != 'none':
-                vInstruction += string.Template("    width $width\n").substitute(dic)
-            if dic['rgbcolumn']:
-                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
-            vInstruction += string.Template("    fcolor $fcolor\n").substitute(dic)
-        else:
-            if dic['rgbcolumn']:
-                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
-            elif dic['hcolor'] != 'none':
-                vInstruction += string.Template("    hwidth $hwidth\n").substitute(dic)
-                vInstruction += string.Template("    hcolor $hcolor\n").substitute(dic)
-        
-        # size and style
-        if self.subType == 'points':
-            if dic['symbol']:
-                vInstruction += string.Template("    symbol $symbol\n").substitute(dic)
-            else: #eps
-                vInstruction += string.Template("    eps $eps\n").substitute(dic)
-            if dic['size']:
-                vInstruction += string.Template("    size $size\n").substitute(dic)            
-            else: # sizecolumn
-                vInstruction += string.Template("    sizecolumn $sizecolumn\n").substitute(dic)
-                vInstruction += string.Template("    scale $scale\n").substitute(dic)
-            if dic['rotation']:
-                if dic['rotate'] is not None:
-                    vInstruction += string.Template("    rotate $rotate\n").substitute(dic)
-                else:
-                    vInstruction += string.Template("    rotatecolumn $rotatecolumn\n").substitute(dic)
-                    
-        if self.subType == 'areas':
-            if dic['pat'] is not None:
-                vInstruction += string.Template("    pat $pat\n").substitute(dic)
-                vInstruction += string.Template("    pwidth $pwidth\n").substitute(dic)
-                vInstruction += string.Template("    scale $scale\n").substitute(dic)
-                
-        if self.subType == 'lines':
-            if dic['width'] is not None:
-                vInstruction += string.Template("    width $width\n").substitute(dic)
-            else:
-                vInstruction += string.Template("    cwidth $cwidth\n").substitute(dic)
-            vInstruction += string.Template("    style $style\n").substitute(dic)
-            vInstruction += string.Template("    linecap $linecap\n").substitute(dic)
-        #position and label in vlegend
-        vInstruction += string.Template("    label $label\n    lpos $lpos\n").substitute(dic)
-        
-        vInstruction += "    end"
-        return vInstruction
-    
-    def Read(self, instruction, text, **kwargs):
-        """!Read instruction and save information"""
-        instr = {}
-        try:
-            info = grass.find_file(name = text[0].split()[1], element = 'vector')
-        except grass.ScriptError, e:
-            GError(message = e.value)
-            return False
-        instr['name'] = info['fullname']
-        #connection
-        instr['connection'] = True
-        self.mapDBInfo = dbm_base.VectorDBInfo(instr['name'])
-        self.layers = self.mapDBInfo.layers.keys()
-        if not self.layers:
-            instr['connection'] = False
-            
-        # points
-        if text[0].startswith('vpoints'):
-            for line in text[1:]:
-                if line.startswith('type'):
-                    tp = []
-                    if line.find('point') != -1:
-                        tp.append('point')
-                    if line.find('centroid') != -1:
-                        tp.append('centroid')
-                    instr['type'] = ' or '.join(tp)
-                elif line.startswith('fcolor'):
-                    instr['fcolor'] = line.split()[1]
-                elif line.startswith('rgbcolumn'):
-                    instr['rgbcolumn'] = line.split()[1]
-                elif line.startswith('symbol'):
-                    instr['symbol'] = line.split()[1]
-                elif line.startswith('eps'):
-                    instr['eps'] = line.split()[1]
-                elif line.startswith('size '):
-                    instr['size'] = line.split()[1]
-                elif line.startswith('sizecolumn'):
-                    instr['size'] = None
-                    instr['sizecolumn'] = line.split()[1]
-                elif line.startswith('scale '):
-                    instr['scale'] = float(line.split()[1])
-                elif line.startswith('rotate '):
-                    instr['rotation'] = True
-                    instr['rotate'] = line.split()[1]
-                elif line.startswith('rotatecolumn'):
-                    instr['rotatecolumn'] = line.split()[1]
-                    instr['rotation'] = True
-                    instr['rotate'] = None
-                    
-        # lines            
-        elif text[0].startswith('vlines'):
-            for line in text[1:]:
-                if line.startswith('type'):
-                    tp = []
-                    if line.find('line') != -1:
-                        tp.append('line')
-                    if line.find('boundary') != -1:
-                        tp.append('boundary')
-                    instr['type'] = ' or '.join(tp)
-                elif line.startswith('hwidth'):
-                    instr['hwidth'] = float(line.split()[1])
-                elif line.startswith('hcolor'):
-                    instr['hcolor'] = line.split()[1]
-                elif line.startswith('rgbcolumn'):
-                    instr['rgbcolumn'] = line.split()[1]                    
-                elif line.startswith('cwidth'):
-                    instr['cwidth'] = float(line.split()[1])
-                    instr['width'] = None
-                elif line.startswith('style'):
-                    instr['style'] = line.split()[1]       
-                elif line.startswith('linecap'):
-                    instr['linecap'] = line.split()[1]
-         
-        elif text[0].startswith('vareas'):
-            for line in text[1:]:
-                if line.startswith('fcolor'):
-                    instr['fcolor'] = line.split()[1]    
-                elif line.startswith('pat'):
-                    instr['pat'] = line.split()[1]
-                elif line.startswith('pwidth'):
-                    instr['pwidth'] = float(line.split()[1])
-                elif line.startswith('scale'):
-                    instr['scale'] = float(line.split()[1])
-            
-            
-        # same properties for all    
-        for line in text[1:]:
-            if line.startswith('lpos'):
-                instr['lpos'] = int(line.split()[1])
-            elif line.startswith('label'):
-                instr['label'] = line.split(None, 1)[1]
-            elif line.startswith('layer'):
-                instr['layer'] = line.split()[1]
-            elif line.startswith('masked'):
-                if line.split()[1].lower() in ('y', 'yes'):
-                    instr['masked'] = 'y'
-                else:
-                    instr['masked'] = 'n'
-            elif line.startswith('color'):
-                instr['color'] = line.split()[1]
-            elif line.startswith('rgbcolumn'):
-                instr['rgbcolumn'] = line.split()[1] 
-            elif line.startswith('width'):
-                instr['width'] = float(line.split()[1])
-                
-        if 'label' not in instr:
-            instr['label'] = '('.join(instr['name'].split('@')) + ')'
-        if 'lpos' not in instr:
-            instr['lpos'] = kwargs['vectorMapNumber']
-        self.instruction.update(instr)
-        
-        return True
-        
-class PsmapDialog(wx.Dialog):
-    def __init__(self, parent, id,  title, settings, apply = True):
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, 
-                            title = title, size = wx.DefaultSize,
-                            style = wx.CAPTION|wx.MINIMIZE_BOX|wx.CLOSE_BOX)
-        self.apply = apply
-        self.id = id
-        self.parent = parent
-        self.instruction = settings
-        self.objectType = None
-        self.unitConv = UnitConversion(self)
-        self.spinCtrlSize = (65, -1)
-        
-        self.Bind(wx.EVT_CLOSE, self.OnClose)
-        
-    
-        
-    def AddUnits(self, parent, dialogDict):
-        parent.units = dict()
-        parent.units['unitsLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Units:"))
-        choices = self.unitConv.getPageUnitsNames()
-        parent.units['unitsCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = choices)  
-        parent.units['unitsCtrl'].SetStringSelection(self.unitConv.findName(dialogDict['unit']))
-          
-    def AddPosition(self, parent, dialogDict):
-        if not hasattr(parent, "position"):
-            parent.position = dict()
-        parent.position['comment'] = wx.StaticText(parent, id = wx.ID_ANY,\
-                    label = _("Position of the top left corner\nfrom the top left edge of the paper"))
-        parent.position['xLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("X:"))
-        parent.position['yLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Y:"))
-        parent.position['xCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][0]), validator = TCValidator(flag = 'DIGIT_ONLY'))
-        parent.position['yCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][1]), validator = TCValidator(flag = 'DIGIT_ONLY'))
-        if dialogDict.has_key('unit'):
-            x = self.unitConv.convert(value = dialogDict['where'][0], fromUnit = 'inch', toUnit = dialogDict['unit'])
-            y = self.unitConv.convert(value = dialogDict['where'][1], fromUnit = 'inch', toUnit = dialogDict['unit'])
-            parent.position['xCtrl'].SetValue("%5.3f" % x)
-            parent.position['yCtrl'].SetValue("%5.3f" % y)
-        
-    def AddExtendedPosition(self, panel, gridBagSizer, dialogDict):
-        """!Add widgets for setting position relative to paper and to map"""
-        panel.position = dict()
-        positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
-        panel.position['toPaper'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
-        panel.position['toMap'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
-        panel.position['toPaper'].SetValue(dialogDict['XY'])
-        panel.position['toMap'].SetValue(not dialogDict['XY'])
-        
-        gridBagSizer.Add(positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(panel.position['toPaper'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(panel.position['toMap'], pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        
-        # first box - paper coordinates
-        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
-        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerP.AddGrowableCol(1)
-        self.gridBagSizerP.AddGrowableRow(3)
-        
-        self.AddPosition(parent = panel, dialogDict = dialogDict)
-        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
-        self.AddUnits(parent = panel, dialogDict = dialogDict)
-        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
-        
-        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
-        
-        # second box - map coordinates
-        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
-        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerM.AddGrowableCol(0)
-        self.gridBagSizerM.AddGrowableCol(1)
-        
-        eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
-        northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
-        panel.position['eCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        panel.position['nCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
-        panel.position['eCtrl'].SetValue(str(east))
-        panel.position['nCtrl'].SetValue(str(north))
-        
-        self.gridBagSizerM.Add(eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(panel.position['eCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(panel.position['nCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
-        
-    def AddFont(self, parent, dialogDict, color = True):
-        parent.font = dict()
-##        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:"))
-##        parent.font['fontCtrl'] = wx.FontPickerCtrl(parent, id = wx.ID_ANY)
-##        
-##        parent.font['fontCtrl'].SetSelectedFont(
-##                        wx.FontFromNativeInfoString(dialogDict['font'] + " " + str(dialogDict['fontsize'])))
-##        parent.font['fontCtrl'].SetMaxPointSize(50)
-##        
-##        if color:
-##            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
-##            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY, style=wx.FNTP_FONTDESC_AS_LABEL)
-##            parent.font['colorCtrl'].SetColour(dialogDict['color'])
-           
-##        parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color'])) 
-           
-        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font:"))
-        parent.font['fontSizeLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font size:"))
-        fontChoices = [ 'Times-Roman', 'Times-Italic', 'Times-Bold', 'Times-BoldItalic', 'Helvetica',\
-                        'Helvetica-Oblique', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Courier',\
-                        'Courier-Oblique', 'Courier-Bold', 'Courier-BoldOblique'] 
-        parent.font['fontCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = fontChoices)
-        if dialogDict['font'] in fontChoices:
-            parent.font['fontCtrl'].SetStringSelection(dialogDict['font'])
-        else:
-            parent.font['fontCtrl'].SetStringSelection('Helvetica')
-        parent.font['fontSizeCtrl'] = wx.SpinCtrl(parent, id = wx.ID_ANY, min = 4, max = 50, initial = 10)
-        parent.font['fontSizeCtrl'].SetValue(dialogDict['fontsize'])
-         
-        if color:
-            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
-            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
-            parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color']))
-##            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Color:"))
-##            colorChoices = [  'aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'green', 'indigo', 'magenta',\
-##                                'orange', 'purple', 'red', 'violet', 'white', 'yellow']
-##            parent.colorCtrl = wx.Choice(parent, id = wx.ID_ANY, choices = colorChoices)
-##            parent.colorCtrl.SetStringSelection(parent.rLegendDict['color'])
-##            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
-##            parent.font['colorCtrl'].SetColour(dialogDict['color'])   
-    def OnApply(self, event):
-        ok = self.update()
-        if ok:
-            self.parent.DialogDataChanged(id = self.id)
-            return True 
-        else:
-            return False
-        
-    def OnOK(self, event):
-        """!Apply changes, close dialog"""
-        ok = self.OnApply(event)
-        if ok:
-            self.Close()
-    
-    def OnCancel(self, event):
-        """!Close dialog"""
-        self.Close()
-
-    def OnClose(self, event):
-        """!Destroy dialog and delete it from open dialogs"""
-        if self.objectType:
-            for each in  self.objectType:
-                if each in self.parent.openDialogs:
-                    del self.parent.openDialogs[each]
-        event.Skip()
-        self.Destroy()
-        
-    def _layout(self, panel):
-        #buttons
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnOK = wx.Button(self, wx.ID_OK)
-        btnOK.SetDefault()
-        if self.apply:
-            btnApply = wx.Button(self, wx.ID_APPLY)
-        
-
-        # bindigs
-        btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
-        btnOK.SetToolTipString(_("Close dialog and apply changes"))
-        #btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        if self.apply:
-            btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-            btnApply.SetToolTipString(_("Apply changes"))
-        
-        # sizers
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        if self.apply:
-            btnSizer.AddButton(btnApply)
-        btnSizer.AddButton(btnOK)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = panel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Layout()
-        mainSizer.Fit(self) 
-            
-class PageSetupDialog(PsmapDialog):
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Page setup",  settings = settings)
-        
-        self.cat = ['Units', 'Format', 'Orientation', 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
-        labels = [_('Units'), _('Format'), _('Orientation'), _('Width'), _('Height'),
-                  _('Left'), _('Right'), _('Top'), _('Bottom')]
-        self.catsLabels = dict(zip(self.cat, labels))
-        paperString = RunCommand('ps.map', flags = 'p', read = True, quiet = True)
-        self.paperTable = self._toList(paperString) 
-        self.unitsList = self.unitConv.getPageUnitsNames()
-        self.pageSetupDict = settings[id].GetInstruction()
-
-        self._layout()
-        
-        if self.pageSetupDict:
-            self.getCtrl('Units').SetStringSelection(self.unitConv.findName(self.pageSetupDict['Units']))
-            if self.pageSetupDict['Format'] == 'custom':
-                self.getCtrl('Format').SetSelection(self.getCtrl('Format').GetCount() - 1)
-            else:
-                self.getCtrl('Format').SetStringSelection(self.pageSetupDict['Format'])
-            if self.pageSetupDict['Orientation'] == 'Portrait':
-                self.getCtrl('Orientation').SetSelection(0)
-            else:
-                self.getCtrl('Orientation').SetSelection(1)
-                
-            for item in self.cat[3:]:
-                val = self.unitConv.convert(value = self.pageSetupDict[item],
-                                            fromUnit = 'inch', toUnit = self.pageSetupDict['Units'])
-                self.getCtrl(item).SetValue("%4.3f" % val)
-
-       
-        if self.getCtrl('Format').GetSelection() != self.getCtrl('Format').GetCount() - 1: # custom
-            self.getCtrl('Width').Disable()
-            self.getCtrl('Height').Disable()
-        else:
-            self.getCtrl('Orientation').Disable()
-        # events
-        self.getCtrl('Units').Bind(wx.EVT_CHOICE, self.OnChoice)
-        self.getCtrl('Format').Bind(wx.EVT_CHOICE, self.OnChoice)
-        self.getCtrl('Orientation').Bind(wx.EVT_CHOICE, self.OnChoice)
-        self.btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
-
-    
-    def update(self):
-        self.pageSetupDict['Units'] = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
-        self.pageSetupDict['Format'] = self.paperTable[self.getCtrl('Format').GetSelection()]['Format']
-        if self.getCtrl('Orientation').GetSelection() == 0:
-            self.pageSetupDict['Orientation'] = 'Portrait'
-        else:
-            self.pageSetupDict['Orientation'] = 'Landscape'
-        for item in self.cat[3:]:
-            self.pageSetupDict[item] = self.unitConv.convert(value = float(self.getCtrl(item).GetValue()),
-                                        fromUnit = self.pageSetupDict['Units'], toUnit = 'inch')
-            
-
-            
-    def OnOK(self, event):
-        try:
-            self.update()
-        except ValueError:
-                wx.MessageBox(message = _("Literal is not allowed!"), caption = _('Invalid input'),
-                                    style = wx.OK|wx.ICON_ERROR)
-        else:
-            event.Skip()
-        
-    def _layout(self):
-        size = (110,-1)
-        #sizers
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        pageBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Page size"))
-        pageSizer = wx.StaticBoxSizer(pageBox, wx.VERTICAL)
-        marginBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Margins"))
-        marginSizer = wx.StaticBoxSizer(marginBox, wx.VERTICAL)
-        horSizer = wx.BoxSizer(wx.HORIZONTAL) 
-        #staticText + choice
-        choices = [self.unitsList, [item['Format'] for item in self.paperTable], [_('Portrait'), _('Landscape')]]
-        propor = [0,1,1]
-        border = [5,3,3]
-        self.hBoxDict={}
-        for i, item in enumerate(self.cat[:3]):
-            hBox = wx.BoxSizer(wx.HORIZONTAL)
-            stText = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
-            choice = wx.Choice(self, id = wx.ID_ANY, choices = choices[i], size = size)
-            hBox.Add(stText, proportion = propor[i], flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = border[i])
-            hBox.Add(choice, proportion = 0, flag = wx.ALL, border = border[i])
-            if item == 'Units':
-                hBox.Add(size,1) 
-            self.hBoxDict[item] = hBox    
-
-        #staticText + TextCtrl
-        for item in self.cat[3:]:
-            hBox = wx.BoxSizer(wx.HORIZONTAL)
-            label = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
-            textctrl = wx.TextCtrl(self, id = wx.ID_ANY, size = size, value = '')
-            hBox.Add(label, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
-            hBox.Add(textctrl, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 3)
-            self.hBoxDict[item] = hBox
-         
-        sizer = list([mainSizer] + [pageSizer]*4 + [marginSizer]*4)
-        for i, item in enumerate(self.cat):
-                sizer[i].Add(self.hBoxDict[item], 0, wx.GROW|wx.RIGHT|wx.LEFT,5)
-        # OK button
-        btnSizer = wx.StdDialogButtonSizer()
-        self.btnOk = wx.Button(self, wx.ID_OK)
-        self.btnOk.SetDefault()
-        btnSizer.AddButton(self.btnOk)
-        btn = wx.Button(self, wx.ID_CANCEL)
-        btnSizer.AddButton(btn)
-        btnSizer.Realize()
-    
-    
-        horSizer.Add(pageSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM, border = 10)
-        horSizer.Add(marginSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND, border = 10)
-        mainSizer.Add(horSizer, proportion = 0, border = 10)  
-        mainSizer.Add(btnSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL,  border = 10)      
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-    
-    def OnChoice(self, event):
-        currPaper = self.paperTable[self.getCtrl('Format').GetSelection()]
-        currUnit = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
-        currOrientIdx = self.getCtrl('Orientation').GetSelection()
-        newSize = dict()
-        for item in self.cat[3:]:
-            newSize[item] = self.unitConv.convert(float(currPaper[item]), fromUnit = 'inch', toUnit = currUnit)
-
-        enable = True
-        if currPaper['Format'] != _('custom'):
-            if currOrientIdx == 1: # portrait
-                newSize['Width'], newSize['Height'] = newSize['Height'], newSize['Width']
-            for item in self.cat[3:]:
-                self.getCtrl(item).ChangeValue("%4.3f" % newSize[item])
-            enable = False
-        self.getCtrl('Width').Enable(enable)
-        self.getCtrl('Height').Enable(enable)
-        self.getCtrl('Orientation').Enable(not enable)
-
-
-    def getCtrl(self, item):
-         return self.hBoxDict[item].GetItem(1).GetWindow()
-        
-    def _toList(self, paperStr):
-        
-        sizeList = list()
-        for line in paperStr.strip().split('\n'):
-            d = dict(zip([self.cat[1]]+ self.cat[3:],line.split()))
-            sizeList.append(d)
-        d = {}.fromkeys([self.cat[1]]+ self.cat[3:], 100)
-        d.update(Format = _('custom'))
-        sizeList.append(d)
-        return sizeList
-    
-class MapDialog(PsmapDialog):
-    """!Dialog for map frame settings and optionally  raster and vector map selection"""
-    def __init__(self, parent, id, settings,  rect = None, notebook = False):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "", settings = settings)
- 
-        self.isNotebook = notebook
-        if self.isNotebook:
-            self.objectType = ('mapNotebook',) 
-        else:
-            self.objectType = ('map',)
-
-        
-        #notebook
-        if self.isNotebook:
-            self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-            self.mPanel = MapFramePanel(parent = self.notebook, id = self.id[0], settings = self.instruction, 
-                                        rect = rect, notebook = True)
-            self.id[0] = self.mPanel.getId()
-            self.rPanel = RasterPanel(parent = self.notebook, id = self.id[1], settings = self.instruction, 
-                                        notebook = True)
-            self.id[1] = self.rPanel.getId()
-            self.vPanel = VectorPanel(parent = self.notebook, id = self.id[2], settings = self.instruction,
-                                        notebook = True)
-            self.id[2] = self.vPanel.getId()
-            self._layout(self.notebook)
-            self.SetTitle(_("Map settings"))
-        else:
-            self.mPanel = MapFramePanel(parent = self, id = self.id[0], settings = self.instruction, 
-                                        rect = rect, notebook = False)
-            self.id[0] = self.mPanel.getId()
-            self._layout(self.mPanel)
-            self.SetTitle(_("Map frame settings"))
-        
-        
-    def OnApply(self, event):
-        """!Apply changes"""
-        if self.isNotebook:
-            okV = self.vPanel.update()
-            okR = self.rPanel.update()
-            if okV and self.id[2] in self.instruction:
-                self.parent.DialogDataChanged(id = self.id[2])
-            if okR and self.id[1] in self.instruction:
-                self.parent.DialogDataChanged(id = self.id[1])
-            if not okR or not okV:
-                return False
-
-        ok = self.mPanel.update()
-        if ok:
-            self.parent.DialogDataChanged(id = self.id[0])
-            return True 
-        
-        return False
-    
-    def OnCancel(self, event):
-        """!Close dialog and remove tmp red box"""
-        self.parent.canvas.pdcTmp.RemoveId(self.parent.canvas.idZoomBoxTmp)
-        self.parent.canvas.Refresh() 
-        self.Close()
-        
-    def updateDialog(self):
-        """!Update raster and vector information"""
-        if self.mPanel.scaleChoice.GetSelection() == 0:
-            if self.mPanel.rasterTypeRadio.GetValue():
-                if 'raster' in self.parent.openDialogs:
-                    if self.parent.openDialogs['raster'].rPanel.rasterYesRadio.GetValue() and \
-                            self.parent.openDialogs['raster'].rPanel.rasterSelect.GetValue() == self.mPanel.select.GetValue():
-                            self.mPanel.drawMap.SetValue(True)
-                    else:
-                        self.mPanel.drawMap.SetValue(False)
-            else:
-                if 'vector' in self.parent.openDialogs:
-                    found = False
-                    for each in self.parent.openDialogs['vector'].vPanel.vectorList:
-                        if each[0] == self.mPanel.select.GetValue():
-                            found = True
-                    self.mPanel.drawMap.SetValue(found)    
-                        
-class MapFramePanel(wx.Panel):
-    """!wx.Panel with map (scale, region, border) settings"""
-    def __init__(self, parent, id, settings, rect, notebook = True):
-        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-
-        self.id = id
-        self.instruction = settings
-        
-        if notebook:
-            self.book = parent
-            self.book.AddPage(page = self, text = _("Map frame"))
-            self.mapDialog = self.book.GetParent()
-        else:
-            self.mapDialog = parent
-            
-        if self.id is not None:
-            self.mapFrameDict = self.instruction[self.id].GetInstruction() 
-        else:
-            self.id = wx.NewId()
-            mapFrame = MapFrame(self.id)
-            self.mapFrameDict = mapFrame.GetInstruction()
-            self.mapFrameDict['rect'] = rect
-
-            
-        self._layout()
-
-        self.scale = [None]*4
-        self.center = [None]*4
-        
-        
-        
-        self.selectedMap = self.mapFrameDict['map']
-        self.selectedRegion = self.mapFrameDict['region']
-        self.scaleType = self.mapFrameDict['scaleType']
-        self.mapType = self.mapFrameDict['mapType']
-        self.scaleChoice.SetSelection(self.mapFrameDict['scaleType'])
-        if self.instruction[self.id]:
-            self.drawMap.SetValue(self.mapFrameDict['drawMap'])
-        else:
-            self.drawMap.SetValue(True)
-        if self.mapFrameDict['scaleType'] == 0 and self.mapFrameDict['map']:
-            self.select.SetValue(self.mapFrameDict['map'])
-            if self.mapFrameDict['mapType'] == 'raster':
-                self.rasterTypeRadio.SetValue(True)
-                self.vectorTypeRadio.SetValue(False)
-            else:
-                self.rasterTypeRadio.SetValue(False)
-                self.vectorTypeRadio.SetValue(True)
-        elif self.mapFrameDict['scaleType'] == 1 and self.mapFrameDict['region']:
-            self.select.SetValue(self.mapFrameDict['region'])
-        
-        
-        self.OnMap(None)
-        self.scale[self.mapFrameDict['scaleType']] = self.mapFrameDict['scale']
-        self.center[self.mapFrameDict['scaleType']] = self.mapFrameDict['center']
-        self.OnScaleChoice(None)
-        self.OnElementType(None)
-        self.OnBorder(None)
-        
-        
-        
-    def _layout(self):
-        """!Do layout"""
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map frame"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-
-
-        #scale options
-        frameText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map frame options:"))
-        scaleChoices = [_("fit frame to match selected map"),
-                        _("fit frame to match saved region"),
-                        _("fit frame to match current computational region"),
-                        _("fixed scale and map center")]
-        self.scaleChoice = wx.Choice(self, id = wx.ID_ANY, choices = scaleChoices)
-        
-        
-        gridBagSizer.Add(frameText, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.scaleChoice, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        #map and region selection
-        self.staticBox = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map selection"))
-        sizerM = wx.StaticBoxSizer(self.staticBox, wx.HORIZONTAL)
-        self.mapSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-
-        self.rasterTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("raster"), style = wx.RB_GROUP)
-        self.vectorTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("vector"))
-        self.drawMap = wx.CheckBox(self, id = wx.ID_ANY, label = "add selected map")
-        
-        self.mapOrRegionText = [_("Map:"), _("Region:")] 
-        dc = wx.PaintDC(self)# determine size of labels
-        width = max(dc.GetTextExtent(self.mapOrRegionText[0])[0], dc.GetTextExtent(self.mapOrRegionText[1])[0])
-        self.mapText = wx.StaticText(self, id = wx.ID_ANY, label = self.mapOrRegionText[0], size = (width, -1))
-        self.select = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                             type = 'raster', multiple = False,
-                             updateOnPopup = True, onPopup = None)
-                            
-        self.mapSizer.Add(self.rasterTypeRadio, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.mapSizer.Add(self.vectorTypeRadio, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.mapSizer.Add(self.drawMap, pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        self.mapSizer.Add(self.mapText, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.mapSizer.Add(self.select, pos = (1, 1), span = (1, 3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-                 
-        sizerM.Add(self.mapSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerM, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-
-        #map scale and center
-        boxC   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map scale and center"))
-        sizerC = wx.StaticBoxSizer(boxC, wx.HORIZONTAL)
-        self.centerSizer = wx.FlexGridSizer(rows = 2, cols = 5, hgap = 5, vgap = 5)        
-                
-                           
-        centerText = wx.StaticText(self, id = wx.ID_ANY, label = _("Center:"))
-        self.eastingText = wx.StaticText(self, id = wx.ID_ANY, label = _("E:"))
-        self.northingText = wx.StaticText(self, id = wx.ID_ANY, label = _("N:"))
-        self.eastingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
-        self.northingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
-        scaleText = wx.StaticText(self, id = wx.ID_ANY, label = _("Scale:"))
-        scalePrefixText = wx.StaticText(self, id = wx.ID_ANY, label = _("1 :"))
-        self.scaleTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, value = "", style = wx.TE_RIGHT, validator = TCValidator('DIGIT_ONLY'))
-        
-        self.centerSizer.Add(centerText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
-        self.centerSizer.Add(self.eastingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        self.centerSizer.Add(self.eastingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.centerSizer.Add(self.northingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        self.centerSizer.Add(self.northingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        self.centerSizer.Add(scaleText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
-        self.centerSizer.Add(scalePrefixText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        self.centerSizer.Add(self.scaleTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizerC.Add(self.centerSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerC, pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        
-        #resolution
-        flexSizer = wx.FlexGridSizer(rows = 1, cols = 2, hgap = 5, vgap = 5)
-        
-        resolutionText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map max resolution (dpi):"))
-        self.resolutionSpin = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 1000, initial = 300)
-        
-        flexSizer.Add(resolutionText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.resolutionSpin, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.resolutionSpin.SetValue(self.mapFrameDict['resolution'])
-        
-        gridBagSizer.Add(flexSizer, pos = (4, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # border
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Border"))        
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        self.borderCheck = wx.CheckBox(self, id = wx.ID_ANY, label = (_("draw border around map frame")))
-        if self.mapFrameDict['border'] == 'y':
-            self.borderCheck.SetValue(True)
-        else: 
-            self.borderCheck.SetValue(False)
-        
-        self.borderColorText = wx.StaticText(self, id = wx.ID_ANY, label = _("border color:"))
-        self.borderWidthText = wx.StaticText(self, id = wx.ID_ANY, label = _("border width (pts):"))
-        self.borderColourPicker = wx.ColourPickerCtrl(self, id = wx.ID_ANY)
-        self.borderWidthCtrl = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 100, initial = 1)
-        
-        if self.mapFrameDict['border'] == 'y':
-            self.borderWidthCtrl.SetValue(int(self.mapFrameDict['width']))
-            self.borderColourPicker.SetColour(convertRGB(self.mapFrameDict['color']))
-        
-        
-        gridBagSizer.Add(self.borderCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.borderColorText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.borderWidthText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.borderColourPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.borderWidthCtrl, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.SetSizer(border)
-        self.Fit()
-        
-        
-        if projInfo()['proj'] == 'll':
-            self.scaleChoice.SetItems(self.scaleChoice.GetItems()[0:3])
-            boxC.Hide()
-            for each in self.centerSizer.GetChildren():
-                each.GetWindow().Hide()
-
-            
-        # bindings
-        self.scaleChoice.Bind(wx.EVT_CHOICE, self.OnScaleChoice)
-        self.select.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnMap)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.vectorTypeRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.rasterTypeRadio)
-        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.borderCheck)
-        
-        
-     
-    def OnMap(self, event):
-        """!Selected map or region changing"""
-        
-        if self.select.GetValue():
-            self.selected = self.select.GetValue() 
-        else:
-            self.selected = None
-
-        if self.scaleChoice.GetSelection() == 0:
-            self.selectedMap = self.selected
-            if self.rasterTypeRadio.GetValue():
-                mapType = 'raster' 
-            else:
-                mapType = 'vector'
-
-            self.scale[0], self.center[0], foo = AutoAdjust(self, scaleType = 0, map = self.selected,
-                                                mapType = mapType, rect = self.mapFrameDict['rect'])
-            #self.center[0] = self.RegionCenter(self.RegionDict(scaleType = 0))
-
-        elif self.scaleChoice.GetSelection() == 1:
-            self.selectedRegion = self.selected
-            self.scale[1], self.center[1],  foo = AutoAdjust(self, scaleType = 1, region = self.selected, rect = self.mapFrameDict['rect'])
-            #self.center[1] = self.RegionCenter(self.RegionDict(scaleType = 1))
-        elif self.scaleChoice.GetSelection() == 2:
-            self.scale[2], self.center[2], foo = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
-            #self.center[2] = self.RegionCenter(self.RegionDict(scaleType = 2))
-            
-        else:
-            self.scale[3] = None        
-            self.center[3] = None
-            
-        self.OnScaleChoice(None)
-        
-            
-    def OnScaleChoice(self, event):
-        """!Selected scale type changing"""
-        
-        scaleType = self.scaleChoice.GetSelection()
-        if self.scaleType != scaleType:
-            self.scaleType = scaleType
-            self.select.SetValue("")
-        
-        if scaleType in (0, 1): # automatic - region from raster map, saved region
-            if scaleType == 0:
-                # set map selection
-                self.rasterTypeRadio.Show()
-                self.vectorTypeRadio.Show()
-                self.drawMap.Show()
-                self.staticBox.SetLabel(" %s " % _("Map selection"))
-                if self.rasterTypeRadio.GetValue():
-                    stype = 'raster' 
-                else:
-                    stype = 'vector'
-
-                self.select.SetElementList(type = stype)
-                self.mapText.SetLabel(self.mapOrRegionText[0])
-                self.select.SetToolTipString(_("Region is set to match this map,\nraster or vector map must be added later"))
-                    
-            if scaleType == 1:
-                # set region selection
-                self.rasterTypeRadio.Hide()
-                self.vectorTypeRadio.Hide()
-                self.drawMap.Hide()
-                self.staticBox.SetLabel(" %s " % _("Region selection"))
-                stype = 'region'
-                self.select.SetElementList(type = stype)
-                self.mapText.SetLabel(self.mapOrRegionText[1])
-                self.select.SetToolTipString("")
-
-            for each in self.mapSizer.GetChildren():
-                each.GetWindow().Enable()
-            for each in self.centerSizer.GetChildren():
-                each.GetWindow().Disable()
-                    
-            if self.scale[scaleType]:
-                
-                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
-            if self.center[scaleType]:
-                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
-                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
-        elif scaleType == 2:
-            for each in self.mapSizer.GetChildren():
-                each.GetWindow().Disable()
-            for each in self.centerSizer.GetChildren():
-                each.GetWindow().Disable()
-                
-            if self.scale[scaleType]:
-                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
-            if self.center[scaleType]:
-                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
-                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
-        else: # fixed
-            for each in self.mapSizer.GetChildren():
-                each.GetWindow().Disable()
-            for each in self.centerSizer.GetChildren():
-                each.GetWindow().Enable()
-                    
-            if self.scale[scaleType]:
-                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
-            if self.center[scaleType]:
-                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
-                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
-                
-    def OnElementType(self, event):
-        """!Changes data in map selection tree ctrl popup"""
-        if self.rasterTypeRadio.GetValue():
-            mapType = 'raster'
-        else:
-            mapType = 'vector'
-        self.select.SetElementList(type  = mapType)
-        if self.mapType != mapType and event is not None:
-            self.mapType = mapType
-            self.select.SetValue('')
-        self.mapType = mapType    
-        
-    def OnBorder(self, event):
-        """!Enables/disable the part relating to border of map frame"""
-        for each in (self.borderColorText, self.borderWidthText, self.borderColourPicker, self.borderWidthCtrl):
-            each.Enable(self.borderCheck.GetValue())
-            
-    def getId(self):
-        """!Returns id of raster map"""
-        return self.id
-            
-    def update(self):
-        """!Save changes"""
-        mapFrameDict = dict(self.mapFrameDict)
-        # resolution
-        mapFrameDict['resolution'] = self.resolutionSpin.GetValue()
-        #scale
-        scaleType = self.scaleType
-        mapFrameDict['scaleType'] = scaleType
-        
-        if mapFrameDict['scaleType'] == 0:
-            if self.select.GetValue():
-                mapFrameDict['drawMap'] = self.drawMap.GetValue()
-                mapFrameDict['map'] = self.select.GetValue()
-                mapFrameDict['mapType'] = self.mapType
-                mapFrameDict['region'] = None
-                
-                if mapFrameDict['drawMap']:
-
-                    if mapFrameDict['mapType'] == 'raster':
-                        mapFile = grass.find_file(mapFrameDict['map'], element = 'cell')
-                        if mapFile['file'] == '':
-                            GMessage("Raster %s not found" % mapFrameDict['map'])
-                            return False
-                        raster = self.instruction.FindInstructionByType('raster')
-                        if raster:
-                            raster['raster'] = mapFrameDict['map']
-                        else:
-                            raster = Raster(wx.NewId())
-                            raster['raster'] = mapFrameDict['map']
-                            raster['isRaster'] = True
-                            self.instruction.AddInstruction(raster)
-
-                    elif mapFrameDict['mapType'] == 'vector':
-                        
-                        mapFile = grass.find_file(mapFrameDict['map'], element = 'vector')
-                        if mapFile['file'] == '':
-                            GMessage("Vector %s not found" % mapFrameDict['map'])
-                            return False
-                        
-                        vector = self.instruction.FindInstructionByType('vector')
-                        isAdded = False
-                        if vector:
-                            for each in vector['list']:
-                                if each[0] == mapFrameDict['map']:
-                                    isAdded = True
-                        if not isAdded:
-                            topoInfo = grass.vector_info_topo(map = mapFrameDict['map'])
-                            if topoInfo:
-                                if bool(topoInfo['areas']):
-                                    topoType = 'areas'
-                                elif bool(topoInfo['lines']):
-                                    topoType = 'lines'
-                                else:
-                                    topoType = 'points'
-                                label = '('.join(mapFrameDict['map'].split('@')) + ')'
-                           
-                                if not vector:
-                                    vector = Vector(wx.NewId())
-                                    vector['list'] = []
-                                    self.instruction.AddInstruction(vector)
-                                id = wx.NewId()
-                                vector['list'].insert(0, [mapFrameDict['map'], topoType, id, 1, label])
-                                vProp = VProperties(id, topoType)
-                                vProp['name'], vProp['label'], vProp['lpos'] = mapFrameDict['map'], label, 1
-                                self.instruction.AddInstruction(vProp)
-                            else:
-                                return False
-                            
-                self.scale[0], self.center[0], self.rectAdjusted = AutoAdjust(self, scaleType = 0, map = mapFrameDict['map'],
-                                                                   mapType = self.mapType, rect = self.mapFrameDict['rect'])
-                                               
-                if self.rectAdjusted:
-                    mapFrameDict['rect'] = self.rectAdjusted 
-                else:
-                    mapFrameDict['rect'] = self.mapFrameDict['rect']
-
-                mapFrameDict['scale'] = self.scale[0]
-                
-                mapFrameDict['center'] = self.center[0]
-                # set region
-                if self.mapType == 'raster':
-                    RunCommand('g.region', rast = mapFrameDict['map'])
-                if self.mapType == 'vector':
-                    raster = self.instruction.FindInstructionByType('raster')
-                    if raster:
-                        rasterId = raster.id 
-                    else:
-                        rasterId = None
-
-                    if rasterId:
-                        
-                        RunCommand('g.region', vect = mapFrameDict['map'], rast = self.instruction[rasterId]['raster'])
-                    else:
-                        RunCommand('g.region', vect = mapFrameDict['map'])
-                
-                    
-                
-            else:
-                wx.MessageBox(message = _("No map selected!"),
-                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
-                return False    
-            
-        elif mapFrameDict['scaleType'] == 1:
-            if self.select.GetValue():
-                mapFrameDict['drawMap'] = False
-                mapFrameDict['map'] = None
-                mapFrameDict['mapType'] = None
-                mapFrameDict['region'] = self.select.GetValue()
-                self.scale[1], self.center[1], self.rectAdjusted = AutoAdjust(self, scaleType = 1, region = mapFrameDict['region'],
-                                                                                rect = self.mapFrameDict['rect'])
-                if self.rectAdjusted:
-                    mapFrameDict['rect'] = self.rectAdjusted 
-                else:
-                    mapFrameDict['rect'] = self.mapFrameDict['rect']
-
-                mapFrameDict['scale'] = self.scale[1]
-                mapFrameDict['center'] = self.center[1]
-                # set region
-                RunCommand('g.region', region = mapFrameDict['region'])
-            else:
-                wx.MessageBox(message = _("No region selected!"),
-                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
-                return False 
-                               
-        elif scaleType == 2:
-            mapFrameDict['drawMap'] = False
-            mapFrameDict['map'] = None
-            mapFrameDict['mapType'] = None
-            mapFrameDict['region'] = None
-            self.scale[2], self.center[2], self.rectAdjusted = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
-            if self.rectAdjusted:
-                mapFrameDict['rect'] = self.rectAdjusted 
-            else:
-                mapFrameDict['rect'] = self.mapFrameDict['rect']
-
-            mapFrameDict['scale'] = self.scale[2]
-            mapFrameDict['center'] = self.center[2]
-            
-            env = grass.gisenv()
-            windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
-            try:
-                windFile = open(windFilePath, 'r').read()
-                region = grass.parse_key_val(windFile, sep = ':', val_type = float)
-            except IOError:
-                region = grass.region()
-            
-            raster = self.instruction.FindInstructionByType('raster')
-            if raster:
-                rasterId = raster.id 
-            else:
-                rasterId = None
-
-            if rasterId: # because of resolution
-                RunCommand('g.region', n = region['north'], s = region['south'],
-                            e = region['east'], w = region['west'], rast = self.instruction[rasterId]['raster'])
-            else:
-                RunCommand('g.region', n = region['north'], s = region['south'],
-                           e = region['east'], w = region['west'])
-            
-        elif scaleType == 3:
-            mapFrameDict['drawMap'] = False
-            mapFrameDict['map'] = None
-            mapFrameDict['mapType'] = None
-            mapFrameDict['region'] = None
-            mapFrameDict['rect'] = self.mapFrameDict['rect']
-            try:
-                scaleNumber = float(self.scaleTextCtrl.GetValue())
-                centerE = float(self.eastingTextCtrl.GetValue()) 
-                centerN = float(self.northingTextCtrl.GetValue())
-            except (ValueError, SyntaxError):
-                wx.MessageBox(message = _("Invalid scale or map center!"),
-                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
-                return False  
-            mapFrameDict['scale'] = 1/scaleNumber
-            mapFrameDict['center'] = centerE, centerN
-        
-            ComputeSetRegion(self, mapDict = mapFrameDict)
-        
-        # check resolution
-        SetResolution(dpi = mapFrameDict['resolution'], width = mapFrameDict['rect'].width,
-                                                        height = mapFrameDict['rect'].height)
-        # border
-        if self.borderCheck.GetValue():
-            mapFrameDict['border'] = 'y' 
-        else:
-            mapFrameDict['border'] = 'n'
-
-        if mapFrameDict['border'] == 'y':
-            mapFrameDict['width'] = self.borderWidthCtrl.GetValue()
-            mapFrameDict['color'] = convertRGB(self.borderColourPicker.GetColour())
-            
-        if self.id not in self.instruction:
-            mapFrame = MapFrame(self.id)
-            self.instruction.AddInstruction(mapFrame)
-        self.instruction[self.id].SetInstruction(mapFrameDict)
-
-        if self.id not in self.mapDialog.parent.objectId:
-            self.mapDialog.parent.objectId.insert(0, self.id)# map frame is drawn first
-        return True
-        
-class RasterPanel(wx.Panel):
-    """!Panel for raster map settings"""
-    def __init__(self, parent, id, settings,  notebook = True):
-        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-        self.instruction = settings
-        
-        if notebook:
-            self.book = parent
-            self.book.AddPage(page = self, text = _("Raster map"))
-            self.mainDialog = self.book.GetParent()
-        else:
-            self.mainDialog = parent
-        if id:
-            self.id = id
-            self.rasterDict = self.instruction[self.id].GetInstruction()
-        else:
-            self.id = wx.NewId()
-            raster = Raster(self.id)
-            self.rasterDict = raster.GetInstruction()
-            
-            
-        self._layout()
-        self.OnRaster(None)
-            
-    def _layout(self):
-        """!Do layout"""
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        # choose raster map
-        
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Choose raster map"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        
-        self.rasterNoRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("no raster map"), style = wx.RB_GROUP)
-        self.rasterYesRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("raster:"))
-        
-        self.rasterSelect = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                             type = 'raster', multiple = False,
-                             updateOnPopup = True, onPopup = None)
-        if self.rasterDict['isRaster']:
-            self.rasterYesRadio.SetValue(True)
-            self.rasterNoRadio.SetValue(False)
-            self.rasterSelect.SetValue(self.rasterDict['raster'])
-        else:
-            self.rasterYesRadio.SetValue(False)
-            self.rasterNoRadio.SetValue(True)
-            mapId = self.instruction.FindInstructionByType('map').id
-
-            if self.instruction[mapId]['map'] and self.instruction[mapId]['mapType'] == 'raster':
-                self.rasterSelect.SetValue(self.instruction[mapId]['map'])# raster map from map frame dialog if possible
-            else:
-                self.rasterSelect.SetValue('')                
-        gridBagSizer.Add(self.rasterNoRadio, pos = (0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)            
-        gridBagSizer.Add(self.rasterYesRadio, pos = (1, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.rasterSelect, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterNoRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterYesRadio)
-        
-        self.SetSizer(border)
-        self.Fit()
-        
-    def OnRaster(self, event):
-        """!Enable/disable raster selection"""
-        self.rasterSelect.Enable(self.rasterYesRadio.GetValue())
-        
-    def update(self):
-        #draw raster
-        mapInstr = self.instruction.FindInstructionByType('map')
-        if not mapInstr: # no map frame
-            GMessage(message = _("Please, create map frame first."))
-            return
-            
-        if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
-            self.rasterDict['isRaster'] = False
-            self.rasterDict['raster'] = None
-            mapInstr['drawMap'] = False
-            if self.id in self.instruction:
-                del self.instruction[self.id]
-
-        else:
-            self.rasterDict['isRaster'] = True
-            self.rasterDict['raster'] = self.rasterSelect.GetValue()
-            if self.rasterDict['raster'] != mapInstr['drawMap']:
-                mapInstr['drawMap'] = False
-
-            raster = self.instruction.FindInstructionByType('raster')
-            if not raster:
-                raster = Raster(self.id)
-                self.instruction.AddInstruction(raster)
-                self.instruction[self.id].SetInstruction(self.rasterDict)
-            else:
-                self.instruction[raster.id].SetInstruction(self.rasterDict)
-            
-        if 'map' in self.mainDialog.parent.openDialogs:
-            self.mainDialog.parent.openDialogs['map'].updateDialog()
-        return True
-        
-    def getId(self):
-        return self.id
-  
-class VectorPanel(wx.Panel):
-    """!Panel for vector maps settings"""
-    def __init__(self, parent, id, settings, notebook = True):
-        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-        
-        self.parent = parent
-        self.instruction = settings
-        self.tmpDialogDict = {}
-        vectors = self.instruction.FindInstructionByType('vProperties', list = True)
-        for vector in vectors:
-            self.tmpDialogDict[vector.id] = dict(self.instruction[vector.id].GetInstruction())
-        
-        if id:
-            self.id = id
-            self.vectorList = deepcopy(self.instruction[id]['list'])
-        else:
-            self.id = wx.NewId()
-            self.vectorList = []
-
-        vLegend = self.instruction.FindInstructionByType('vectorLegend')
-        if vLegend:
-            self.vLegendId = vLegend.id 
-        else:
-            self.vLegendId = None
-
-         
-        self._layout()
-        
-        if notebook:
-            self.parent.AddPage(page = self, text = _("Vector maps"))
-            self.parent = self.parent.GetParent()
-            
-    def _layout(self):
-        """!Do layout"""
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        # choose vector map
-        
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Add map"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        
-        text = wx.StaticText(self, id = wx.ID_ANY, label = _("Map:"))
-        self.select = Select(self, id = wx.ID_ANY,# size = globalvar.DIALOG_GSELECT_SIZE,
-                             type = 'vector', multiple = False,
-                             updateOnPopup = True, onPopup = None)
-        topologyType = [_("points"), _("lines"), _("areas")]
-        self.vectorType = wx.RadioBox(self, id = wx.ID_ANY, label = " %s " % _("Data Type"), choices = topologyType,
-                                        majorDimension = 3, style = wx.RA_SPECIFY_COLS)
-        self.AddVector = wx.Button(self, id = wx.ID_ANY, label = _("Add"))
-        
-        gridBagSizer.Add(text, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.select, pos = (0,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.vectorType, pos = (1,1), flag = wx.ALIGN_CENTER, border = 0)
-        gridBagSizer.Add(self.AddVector, pos = (1,2), flag = wx.ALIGN_BOTTOM|wx.ALIGN_RIGHT, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # manage vector layers
-        
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Manage vector maps"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(0,2)
-        gridBagSizer.AddGrowableCol(1,1)
-
-        
-        
-        text = wx.StaticText(self, id = wx.ID_ANY, label = _("The topmost vector map overlaps the others"))
-        self.listbox = wx.ListBox(self, id = wx.ID_ANY, choices = [], style = wx.LB_SINGLE|wx.LB_NEEDED_SB)
-        self.btnUp = wx.Button(self, id = wx.ID_ANY, label = _("Up"))
-        self.btnDown = wx.Button(self, id = wx.ID_ANY, label = _("Down"))
-        self.btnDel = wx.Button(self, id = wx.ID_ANY, label = _("Delete"))
-        self.btnProp = wx.Button(self, id = wx.ID_ANY, label = _("Properties..."))
-        
-        self.updateListBox(selected=0)
-        
-        
-        gridBagSizer.Add(text, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.listbox, pos = (1,0), span = (4, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.btnUp, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.btnDown, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.btnDel, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.btnProp, pos = (4,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_BUTTON, self.OnAddVector, self.AddVector)
-        self.Bind(wx.EVT_BUTTON, self.OnDelete, self.btnDel)
-        self.Bind(wx.EVT_BUTTON, self.OnUp, self.btnUp)
-        self.Bind(wx.EVT_BUTTON, self.OnDown, self.btnDown)
-        self.Bind(wx.EVT_BUTTON, self.OnProperties, self.btnProp)
-        self.select.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnVector)
-        
-        self.SetSizer(border)
-        self.Fit()
-        
-        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnProperties, self.listbox)
-
-    def OnVector(self, event):
-        """!Gets info about toplogy and enables/disables choices point/line/area"""
-        vmap = self.select.GetValue()   
-        try:     
-            topoInfo = grass.vector_info_topo(map = vmap)
-        except grass.ScriptError:
-            return
-        
-        if topoInfo:
-            self.vectorType.EnableItem(2, bool(topoInfo['areas']))
-            self.vectorType.EnableItem(1, bool(topoInfo['boundaries']) or bool(topoInfo['lines']))
-            self.vectorType.EnableItem(0, bool(topoInfo['centroids'] or bool(topoInfo['points']) ))
-            for item in range(2,-1,-1):
-                if self.vectorType.IsItemEnabled(item):
-                    self.vectorType.SetSelection(item)
-                    break
-            
-            self.AddVector.SetFocus()        
-            
-    def OnAddVector(self, event):
-        """!Adds vector map to list"""
-        vmap = self.select.GetValue()
-        if vmap:
-            mapname = vmap.split('@')[0]
-            try:
-                mapset = '(' + vmap.split('@')[1] + ')'
-            except IndexError:
-                mapset = ''
-            type = self.vectorType.GetStringSelection()
-            record = "%s - %s" % (vmap,type)
-            id = wx.NewId()
-            lpos = 1
-            label = mapname + mapset 
-            self.vectorList.insert(0, [vmap, type, id, lpos, label])
-            self.reposition()
-            self.listbox.InsertItems([record], 0)
-            
-            vector = VProperties(id, type)
-            self.tmpDialogDict[id] = vector.GetInstruction()
-            self.tmpDialogDict[id]['name'] = vmap
-
-            
-            self.listbox.SetSelection(0)  
-            self.listbox.EnsureVisible(0)
-            self.btnProp.SetFocus()
-            self.enableButtons()
-            
-    def OnDelete(self, event):
-        """!Deletes vector map from the list"""
-        if self.listbox.GetSelections():
-            pos = self.listbox.GetSelection()
-            id = self.vectorList[pos][2]
-            del self.vectorList[pos]
-            del self.tmpDialogDict[id]
-            
-            for i in range(pos, len(self.vectorList)):
-                if self.vectorList[i][3]:# can be 0
-                    self.vectorList[i][3] -= 1
-            
-            if pos < len(self.vectorList) -1:
-                selected = pos
-            else:
-                selected = len(self.vectorList) -1
-            self.updateListBox(selected = selected)
-            if self.listbox.IsEmpty():
-                self.enableButtons(False)
-            
-            
-    def OnUp(self, event):
-        """!Moves selected map to top"""
-        if self.listbox.GetSelections():
-            pos = self.listbox.GetSelection()
-            if pos:
-                self.vectorList.insert(pos - 1, self.vectorList.pop(pos))
-            if not self.vLegendId:
-                self.reposition()
-                
-            if pos > 0:
-                self.updateListBox(selected = (pos - 1)) 
-            else:
-                self.updateListBox(selected = 0)
-
-            
-    def OnDown(self, event):
-        """!Moves selected map to bottom"""
-        if self.listbox.GetSelections():
-            pos = self.listbox.GetSelection()
-            if pos != len(self.vectorList) - 1:
-                self.vectorList.insert(pos + 1, self.vectorList.pop(pos))
-                if not self.vLegendId:
-                    self.reposition()
-            if pos < len(self.vectorList) -1:
-                self.updateListBox(selected = (pos + 1)) 
-            else:
-                self.updateListBox(selected = len(self.vectorList) -1)
-
-    
-    def OnProperties(self, event):
-        """!Opens vector map properties dialog"""
-        if self.listbox.GetSelections():
-            pos = self.listbox.GetSelection()
-            id = self.vectorList[pos][2]
-
-            dlg = VPropertiesDialog(self, id = id, settings = self.instruction, 
-                                    vectors = self.vectorList, tmpSettings = self.tmpDialogDict[id])
-            dlg.ShowModal()
-            
-            self.parent.FindWindowById(wx.ID_OK).SetFocus()
-           
-    def enableButtons(self, enable = True):
-        """!Enable/disable up, down, properties, delete buttons"""
-        self.btnUp.Enable(enable)
-        self.btnDown.Enable(enable)
-        self.btnProp.Enable(enable)
-        self.btnDel.Enable(enable)
-    
-    def updateListBox(self, selected = None):
-        mapList = ["%s - %s" % (item[0], item[1]) for item in self.vectorList]
-        self.listbox.Set(mapList)
-        if self.listbox.IsEmpty():
-            self.enableButtons(False)
-        else:
-            self.enableButtons(True)
-            if selected is not None:
-                self.listbox.SetSelection(selected)  
-                self.listbox.EnsureVisible(selected)  
-              
-    def reposition(self):
-        """!Update position in legend, used only if there is no vlegend yet"""
-        for i in range(len(self.vectorList)):
-            if self.vectorList[i][3]:
-                self.vectorList[i][3] = i + 1
-                
-    def getId(self):
-        return self.id
-        
-    def update(self):
-        vectors = self.instruction.FindInstructionByType('vProperties', list = True)
-        
-        for vector in vectors:
-            del self.instruction[vector.id]
-        if self.id in self.instruction:
-            del self.instruction[self.id] 
-
-        if len(self.vectorList) > 0:
-            vector = Vector(self.id)
-            self.instruction.AddInstruction(vector)
-
-            vector.SetInstruction({'list': deepcopy(self.vectorList)})
-            
-            # save new vectors
-            for item in self.vectorList:
-                id = item[2]
-
-                vLayer = VProperties(id, item[1])
-                self.instruction.AddInstruction(vLayer)
-                vLayer.SetInstruction(self.tmpDialogDict[id])
-                vLayer['name'] = item[0]
-                vLayer['label'] = item[4]
-                vLayer['lpos'] = item[3]
-            
-        else:
-            if self.id in self.instruction:
-                del self.instruction[self.id]
-                
-        if 'map' in self.parent.parent.openDialogs:
-            self.parent.parent.openDialogs['map'].updateDialog()
-
-        return True
-    
-class RasterDialog(PsmapDialog):
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = _("Raster map settings"), settings = settings)
-        self.objectType = ('raster',)
-        
-        self.rPanel = RasterPanel(parent = self, id = self.id, settings = self.instruction, notebook = False)
-
-        self.id = self.rPanel.getId()
-        self._layout(self.rPanel)
-    
-    def update(self):
-        ok = self.rPanel.update()
-        if ok:
-            return True
-        return False
-    
-    def OnApply(self, event):
-        ok = self.update()
-        if not ok:
-            return False
-
-        if self.id in self.instruction:
-            self.parent.DialogDataChanged(id = self.id)
-        else:
-            mapId = self.instruction.FindInstructionByType('map').id
-            self.parent.DialogDataChanged(id = mapId)
-        return True
-    
-    def updateDialog(self):
-        """!Update information (not used)"""
-        pass
-##        if 'map' in self.parent.openDialogs:
-##            if self.parent.openDialogs['map'].mPanel.rasterTypeRadio.GetValue()\
-##                    and self.parent.openDialogs['map'].mPanel.select.GetValue():
-##                if self.parent.openDialogs['map'].mPanel.drawMap.IsChecked():
-##                    self.rPanel.rasterSelect.SetValue(self.parent.openDialogs['map'].mPanel.select.GetValue())   
-                
-class MainVectorDialog(PsmapDialog):
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = _("Vector maps settings"), settings = settings)
-        self.objectType = ('vector',)
-        self.vPanel = VectorPanel(parent = self, id = self.id, settings = self.instruction, notebook = False)
-
-        self.id = self.vPanel.getId()
-        self._layout(self.vPanel)
-    
-    def update(self):
-        self.vPanel.update()
-        
-    def OnApply(self, event):
-        self.update()
-        if self.id in self.instruction:
-            self.parent.DialogDataChanged(id = self.id)
-        else:
-            mapId = self.instruction.FindInstructionByType('map').id
-            self.parent.DialogDataChanged(id = mapId)
-        return True
-        
-    def updateDialog(self):
-        """!Update information (not used)"""
-        pass
-        
-class VPropertiesDialog(PsmapDialog):
-    def __init__(self, parent, id, settings, vectors, tmpSettings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "", settings = settings, apply = False)
-        
-        vectorList = vectors
-        self.vPropertiesDict = tmpSettings
-        
-        # determine map and its type
-        for item in vectorList:
-            if id == item[2]:
-                self.vectorName = item[0]
-                self.type = item[1]
-        self.SetTitle(self.vectorName + " "+ _("properties"))
-        
-        #vector map info
-        self.connection = True
-        try:
-            self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
-            self.layers = self.mapDBInfo.layers.keys()
-        except grass.ScriptError:
-            self.connection = False
-            self.layers = []
-        if not self.layers:
-            self.connection = False
-            self.layers = []
-            
-        self.currLayer = self.vPropertiesDict['layer']
-        
-        #path to symbols, patterns
-        gisbase = os.getenv("GISBASE")
-        self.symbolPath = os.path.join(gisbase, 'etc', 'symbol')
-        self.symbols = []
-        for dir in os.listdir(self.symbolPath):
-            for symbol in os.listdir(os.path.join(self.symbolPath, dir)):
-                self.symbols.append(os.path.join(dir, symbol))
-        self.patternPath = os.path.join(gisbase, 'etc', 'paint', 'patterns')
-
-        #notebook
-        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-        self.DSpanel = self._DataSelectionPanel(notebook)
-        self.EnableLayerSelection(enable = self.connection)
-        selectPanel = { 'points': [self._ColorsPointAreaPanel, self._StylePointPanel], 
-                        'lines': [self._ColorsLinePanel, self._StyleLinePanel], 
-                        'areas': [self._ColorsPointAreaPanel, self._StyleAreaPanel]}
-        self.ColorsPanel = selectPanel[self.type][0](notebook)
-        
-        self.OnOutline(None)
-        if self.type in ('points', 'areas'):
-            self.OnFill(None)
-        self.OnColor(None)
-        
-        self.StylePanel = selectPanel[self.type][1](notebook)
-        if self.type == 'points':
-            self.OnSize(None)
-            self.OnRotation(None)
-        if self.type == 'areas':
-            self.OnPattern(None)
-        
-        self._layout(notebook)
-        
-    def _DataSelectionPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Data selection"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        # data type
-        self.checkType1 = self.checkType2 = None
-        if self.type in ('lines', 'points'):
-            box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Feature type"))
-            sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-            gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-            if self.type == 'points':
-                label = (_("points"), _("centroids"))
-            else: 
-                label = (_("lines"), _("boundaries"))
-            if self.type == 'points':
-                name = ("point", "centroid")
-            else:
-                name = ("line", "boundary")
-            self.checkType1 = wx.CheckBox(panel, id = wx.ID_ANY, label = label[0], name = name[0])
-            self.checkType2 = wx.CheckBox(panel, id = wx.ID_ANY, label = label[1], name = name[1])
-            self.checkType1.SetValue(self.vPropertiesDict['type'].find(name[0]) >= 0)
-            self.checkType2.SetValue(self.vPropertiesDict['type'].find(name[1]) >= 0)
-            
-            gridBagSizer.Add(self.checkType1, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            gridBagSizer.Add(self.checkType2, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-            border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # layer selection
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Layer selection"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        self.gridBagSizerL = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        self.warning =  wx.StaticText(panel, id = wx.ID_ANY, label = "")
-        if not self.connection:
-            self.warning = wx.StaticText(panel, id = wx.ID_ANY, label = _("Database connection is not defined in DB file."))
-        text = wx.StaticText(panel, id = wx.ID_ANY, label = _("Select layer:"))
-        self.layerChoice = wx.Choice(panel, id = wx.ID_ANY, choices = map(str, self.layers), size = self.spinCtrlSize)
-        
-        self.layerChoice.SetStringSelection(self.currLayer)
-                
-        if self.connection:
-            table = self.mapDBInfo.layers[int(self.currLayer)]['table'] 
-        else:
-            table = ""
-
-        self.radioWhere = wx.RadioButton(panel, id = wx.ID_ANY, label = "SELECT * FROM %s WHERE" % table, style = wx.RB_GROUP)
-        self.textCtrlWhere = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        
-        
-        if self.connection:
-            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
-        else:
-            cols = []
-
-        self.choiceColumns = wx.Choice(panel, id = wx.ID_ANY, choices = cols)
-        
-        self.radioCats = wx.RadioButton(panel, id = wx.ID_ANY, label = "Choose categories ")
-        self.textCtrlCats = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        self.textCtrlCats.SetToolTipString(_("list of categories (e.g. 1,3,5-7)"))
-        
-        if self.vPropertiesDict.has_key('cats'):
-            self.radioCats.SetValue(True)
-            self.textCtrlCats.SetValue(self.vPropertiesDict['cats'])
-        if self.vPropertiesDict.has_key('where'):
-            self.radioWhere.SetValue(True)
-            where = self.vPropertiesDict['where'].strip().split(" ",1)
-            self.choiceColumns.SetStringSelection(where[0])
-            self.textCtrlWhere.SetValue(where[1])
-            
-        row = 0
-        if not self.connection:
-            self.gridBagSizerL.Add(self.warning, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            row = 1
-        self.gridBagSizerL.Add(text, pos = (0 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerL.Add(self.layerChoice, pos = (0 + row,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        self.gridBagSizerL.Add(self.radioWhere, pos = (1 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerL.Add(self.choiceColumns, pos = (1 + row,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerL.Add(self.textCtrlWhere, pos = (1 + row,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerL.Add(self.radioCats, pos = (2 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerL.Add(self.textCtrlCats, pos = (2 + row,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(self.gridBagSizerL, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #mask
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Mask"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        
-        self.mask = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Use current mask"))
-        if self.vPropertiesDict['masked'] == 'y':
-            self.mask.SetValue(True) 
-        else:
-            self.mask.SetValue(False)
-        
-        sizer.Add(self.mask, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        self.Bind(wx.EVT_CHOICE, self.OnLayer, self.layerChoice)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-    
-    def _ColorsPointAreaPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Colors"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #colors - outline
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Outline"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        self.gridBagSizerO = wx.GridBagSizer(hgap = 5, vgap = 2)
-        
-        self.outlineCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw outline"))
-        self.outlineCheck.SetValue(self.vPropertiesDict['color'] != 'none')
-        
-        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
-        if fs:
-            self.widthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
-                                          increment = 0.5, value = 1, style = fs.FS_RIGHT)
-            self.widthSpin.SetFormat("%f")
-            self.widthSpin.SetDigits(2)
-        else:
-            self.widthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1,
-                                         size = self.spinCtrlSize)
-                                        
-        if self.vPropertiesDict['color'] == None:
-            self.vPropertiesDict['color'] = 'none'
- 
-        if self.vPropertiesDict['color'] != 'none':
-            self.widthSpin.SetValue(self.vPropertiesDict['width'] )
-        else:
-            self.widthSpin.SetValue(1)
-
-        colorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:"))
-        self.colorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        if self.vPropertiesDict['color'] != 'none':
-            self.colorPicker.SetColour(convertRGB(self.vPropertiesDict['color'])) 
-        else:
-            self.colorPicker.SetColour(convertRGB('black'))
-
-        self.gridBagSizerO.Add(self.outlineCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerO.Add(widthText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerO.Add(self.widthSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
-        self.gridBagSizerO.Add(colorText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)                
-        self.gridBagSizerO.Add(self.colorPicker, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        
-        sizer.Add(self.gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_CHECKBOX, self.OnOutline, self.outlineCheck)
-        
-        #colors - fill
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Fill")) 
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        self.gridBagSizerF = wx.GridBagSizer(hgap = 5, vgap = 2)
-       
-        self.fillCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("fill color"))
-        self.fillCheck.SetValue(self.vPropertiesDict['fcolor'] != 'none' or self.vPropertiesDict['rgbcolumn'] is not None)
-
-        self.colorPickerRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("choose color:"), style = wx.RB_GROUP)
-        #set choose color option if there is no db connection
-        if self.connection:
-            self.colorPickerRadio.SetValue(not self.vPropertiesDict['rgbcolumn'])
-        else:
-            self.colorPickerRadio.SetValue(False)            
-        self.fillColorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        if self.vPropertiesDict['fcolor'] != 'none':
-            self.fillColorPicker.SetColour(convertRGB(self.vPropertiesDict['fcolor'])) 
-        else:
-            self.fillColorPicker.SetColour(convertRGB('red'))        
-        
-        self.colorColRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("color from map table column:"))
-        self.colorColChoice = self.getColsChoice(parent = panel)
-        if self.connection:
-            if self.vPropertiesDict['rgbcolumn']:
-                self.colorColRadio.SetValue(True)
-                self.colorColChoice.SetStringSelection(self.vPropertiesDict['rgbcolumn'])
-            else:
-                self.colorColRadio.SetValue(False)
-                self.colorColChoice.SetSelection(0)
-        self.colorColChoice.Enable(self.connection)
-        self.colorColRadio.Enable(self.connection)
-        
-        self.gridBagSizerF.Add(self.fillCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerF.Add(self.colorPickerRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.fillColorPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.colorColRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.colorColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
-        
-        sizer.Add(self.gridBagSizerF, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        self.Bind(wx.EVT_CHECKBOX, self.OnFill, self.fillCheck)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorColRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorPickerRadio)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-    
-    def _ColorsLinePanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Colors"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #colors - outline
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Outline"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        self.gridBagSizerO = wx.GridBagSizer(hgap = 5, vgap = 2)
-        
-        if self.vPropertiesDict['hcolor'] == None:
-            self.vPropertiesDict['hcolor'] = 'none'
-        if self.vPropertiesDict['color'] == None:
-            self.vPropertiesDict['color'] = 'none'
-        
-        self.outlineCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw outline"))
-        self.outlineCheck.SetValue(self.vPropertiesDict['hcolor'] != 'none')
-        self.outlineCheck.SetToolTipString(_("No effect for fill color from table column"))
-        
-        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
-        
-        if fs:
-            self.outWidthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
-                                             increment = 0.5, value = 1, style = fs.FS_RIGHT)
-            self.outWidthSpin.SetFormat("%f")
-            self.outWidthSpin.SetDigits(1)
-        else:
-            self.outWidthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1,
-                                         size = self.spinCtrlSize)
-        
-        if self.vPropertiesDict['hcolor'] != 'none':
-            self.outWidthSpin.SetValue(self.vPropertiesDict['hwidth'] )
-        else:
-            self.outWidthSpin.SetValue(1)
-
-        colorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:"))
-        self.colorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        if self.vPropertiesDict['hcolor'] != 'none':
-            self.colorPicker.SetColour(convertRGB(self.vPropertiesDict['hcolor']) )
-        else:
-            self.colorPicker.SetColour(convertRGB('black'))
-
-        
-        self.gridBagSizerO.Add(self.outlineCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerO.Add(widthText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerO.Add(self.outWidthSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
-        self.gridBagSizerO.Add(colorText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)                
-        self.gridBagSizerO.Add(self.colorPicker, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        
-        sizer.Add(self.gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_CHECKBOX, self.OnOutline, self.outlineCheck)
-        
-        #colors - fill
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Fill"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        self.gridBagSizerF = wx.GridBagSizer(hgap = 5, vgap = 2)
-       
-        fillText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color of lines:"))
-
-        self.colorPickerRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("choose color:"), style = wx.RB_GROUP)
-
-        #set choose color option if there is no db connection
-        if self.connection:
-            self.colorPickerRadio.SetValue(not self.vPropertiesDict['rgbcolumn'])
-        else:
-            self.colorPickerRadio.SetValue(False)            
-        self.fillColorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        if self.vPropertiesDict['color'] != 'none':
-            self.fillColorPicker.SetColour(convertRGB(self.vPropertiesDict['color']) )
-        else:
-            self.fillColorPicker.SetColour(convertRGB('black'))
-        
-        self.colorColRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("color from map table column:"))
-        self.colorColChoice = self.getColsChoice(parent = panel)
-        if self.connection:
-            if self.vPropertiesDict['rgbcolumn']:
-                self.colorColRadio.SetValue(True)
-                self.colorColChoice.SetStringSelection(self.vPropertiesDict['rgbcolumn'])
-            else:
-                self.colorColRadio.SetValue(False)
-                self.colorColChoice.SetSelection(0)
-        self.colorColChoice.Enable(self.connection)
-        self.colorColRadio.Enable(self.connection)
-        
-        self.gridBagSizerF.Add(fillText, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerF.Add(self.colorPickerRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.fillColorPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.colorColRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        self.gridBagSizerF.Add(self.colorColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
-        
-        sizer.Add(self.gridBagSizerF, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorColRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorPickerRadio)
-
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-    
-    def _StylePointPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Size and style"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #symbology
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Symbology"))        
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-    
-        self.symbolRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("symbol:"), style = wx.RB_GROUP)
-        self.symbolRadio.SetValue(bool(self.vPropertiesDict['symbol']))
-            
-         
-        self.symbolChoice = wx.Choice(panel, id = wx.ID_ANY, choices = self.symbols)
-            
-        self.epsRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("eps file:"))
-        self.epsRadio.SetValue(bool(self.vPropertiesDict['eps']))
-        
-        self.epsFileCtrl = filebrowse.FileBrowseButton(panel, id = wx.ID_ANY, labelText = '',
-                                buttonText =  _("Browse"), toolTip = _("Type filename or click browse to choose file"), 
-                                dialogTitle = _("Choose a file"), startDirectory = '', initialValue = '',
-                                fileMask = "Encapsulated PostScript (*.eps)|*.eps|All files (*.*)|*.*", fileMode = wx.OPEN)
-        if self.vPropertiesDict['symbol']:
-            self.symbolChoice.SetStringSelection(self.vPropertiesDict['symbol'])
-            self.epsFileCtrl.SetValue('')
-        else: #eps chosen
-            self.epsFileCtrl.SetValue(self.vPropertiesDict['eps'])
-            self.symbolChoice.SetSelection(0)
-            
-        gridBagSizer.Add(self.symbolRadio, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.symbolChoice, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.epsRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.epsFileCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #size
-        
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))        
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(0)
-        
-        self.sizeRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("size:"), style = wx.RB_GROUP)
-        self.sizeSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 50, initial = 1)
-        self.sizecolumnRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("size from map table column:"))
-        self.sizeColChoice = self.getColsChoice(panel)
-        self.scaleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("scale:"))
-        self.scaleSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
-        
-        self.sizeRadio.SetValue(self.vPropertiesDict['size'] is not None)
-        self.sizecolumnRadio.SetValue(bool(self.vPropertiesDict['sizecolumn']))
-        if self.vPropertiesDict['size']:
-            self.sizeSpin.SetValue(self.vPropertiesDict['size'])
-        else: self.sizeSpin.SetValue(5)
-        if self.vPropertiesDict['sizecolumn']:
-            self.scaleSpin.SetValue(self.vPropertiesDict['scale'])
-            self.sizeColChoice.SetStringSelection(self.vPropertiesDict['sizecolumn'])
-        else:
-            self.scaleSpin.SetValue(1)
-            self.sizeColChoice.SetSelection(0)
-        if not self.connection:   
-            for each in (self.sizecolumnRadio, self.sizeColChoice, self.scaleSpin, self.scaleText):
-                each.Disable()
-            
-        gridBagSizer.Add(self.sizeRadio, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sizeSpin, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sizecolumnRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sizeColChoice, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.scaleText, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        gridBagSizer.Add(self.scaleSpin, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnSize, self.sizeRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnSize, self.sizecolumnRadio)
-        
-        #rotation
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Rotation"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-
-        
-        self.rotateCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("rotate symbols:"))
-        self.rotateRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("counterclockwise in degrees:"), style = wx.RB_GROUP)
-        self.rotateSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 360, initial = 0)
-        self.rotatecolumnRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("from map table column:"))
-        self.rotateColChoice = self.getColsChoice(panel)
-        
-        self.rotateCheck.SetValue(self.vPropertiesDict['rotation'])
-        self.rotateRadio.SetValue(self.vPropertiesDict['rotate'] is not None)
-        self.rotatecolumnRadio.SetValue(bool(self.vPropertiesDict['rotatecolumn']))
-        if self.vPropertiesDict['rotate']:
-            self.rotateSpin.SetValue(self.vPropertiesDict['rotate'])
-        else:
-            self.rotateSpin.SetValue(0)
-        if self.vPropertiesDict['rotatecolumn']:
-            self.rotateColChoice.SetStringSelection(self.vPropertiesDict['rotatecolumn'])
-        else:
-            self.rotateColChoice.SetSelection(0)
-            
-        gridBagSizer.Add(self.rotateCheck, pos = (0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.rotateRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.rotateSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.rotatecolumnRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.rotateColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotateCheck)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRotationType, self.rotateRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRotationType, self.rotatecolumnRadio)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-    
-    def _StyleLinePanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Size and style"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #width
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Width"))       
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Set width (pts):"))
-        if fs:
-            self.widthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
-                                        increment = 0.5, value = 1, style = fs.FS_RIGHT)
-            self.widthSpin.SetFormat("%f")
-            self.widthSpin.SetDigits(1)
-        else:
-            self.widthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1)
-            
-        self.cwidthCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("multiply width by category value"))
-        
-        if self.vPropertiesDict['width']:
-            self.widthSpin.SetValue(self.vPropertiesDict['width'])
-            self.cwidthCheck.SetValue(False)
-        else:
-            self.widthSpin.SetValue(self.vPropertiesDict['cwidth'])
-            self.cwidthCheck.SetValue(True)
-        
-        gridBagSizer.Add(widthText, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.widthSpin, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.cwidthCheck, pos = (1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #style
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Line style"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        styleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose line style:"))
-        penStyles = ["solid", "dashed", "dotted", "dashdotted"]
-        self.styleCombo = PenStyleComboBox(panel, choices = penStyles, validator = TCValidator(flag = 'ZERO_AND_ONE_ONLY'))
-##        self.styleCombo = wx.ComboBox(panel, id = wx.ID_ANY,
-##                            choices = ["solid", "dashed", "dotted", "dashdotted"],
-##                            validator = TCValidator(flag = 'ZERO_AND_ONE_ONLY'))
-##        self.styleCombo.SetToolTipString(_("It's possible to enter a series of 0's and 1's too. "\
-##                                    "The first block of repeated zeros or ones represents 'draw', "\
-##                                    "the second block represents 'blank'. An even number of blocks "\
-##                                    "will repeat the pattern, an odd number of blocks will alternate the pattern."))
-        linecapText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose linecap:"))
-        self.linecapChoice = wx.Choice(panel, id = wx.ID_ANY, choices = ["butt", "round", "extended_butt"])
-        
-        self.styleCombo.SetValue(self.vPropertiesDict['style'])
-        self.linecapChoice.SetStringSelection(self.vPropertiesDict['linecap'])
-        
-        gridBagSizer.Add(styleText, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.styleCombo, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(linecapText, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.linecapChoice, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-        
-    def _StyleAreaPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Size and style"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #pattern
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Pattern"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-        
-        self.patternCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use pattern:"))
-        self.patFileCtrl = filebrowse.FileBrowseButton(panel, id = wx.ID_ANY, labelText = _("Choose pattern file:"),
-                                buttonText =  _("Browse"), toolTip = _("Type filename or click browse to choose file"), 
-                                dialogTitle = _("Choose a file"), startDirectory = self.patternPath, initialValue = '',
-                                fileMask = "Encapsulated PostScript (*.eps)|*.eps|All files (*.*)|*.*", fileMode = wx.OPEN)
-        self.patWidthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("pattern line width (pts):"))
-        self.patWidthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
-        self.patScaleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("pattern scale factor:"))
-        self.patScaleSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
-        
-        self.patternCheck.SetValue(bool(self.vPropertiesDict['pat']))
-        if self.patternCheck.GetValue():
-            self.patFileCtrl.SetValue(self.vPropertiesDict['pat'])
-            self.patWidthSpin.SetValue(self.vPropertiesDict['pwidth'])
-            self.patScaleSpin.SetValue(self.vPropertiesDict['scale'])
-        
-        gridBagSizer.Add(self.patternCheck, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.patFileCtrl, pos = (1, 0), span = (1, 2),flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.patWidthText, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.patWidthSpin, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.patScaleText, pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.patScaleSpin, pos = (3, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_CHECKBOX, self.OnPattern, self.patternCheck)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        return panel
-
-    def OnLayer(self, event):
-        """!Change columns on layer change """
-        if self.layerChoice.GetStringSelection() == self.currLayer:
-            return
-        self.currLayer = self.layerChoice.GetStringSelection()
-        if self.connection:
-            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
-        else:
-            cols = []
-
-        self.choiceColumns.SetItems(cols)
-
-        self.choiceColumns.SetSelection(0)
-        if self.type in ('points', 'lines'):
-            self.colorColChoice.SetItems(cols)
-            self.colorColChoice.SetSelection(0)
-            
-    def OnOutline(self, event):
-        for widget in self.gridBagSizerO.GetChildren():
-            if widget.GetWindow() != self.outlineCheck:
-                widget.GetWindow().Enable(self.outlineCheck.GetValue())
-                
-    def OnFill(self, event):
-        enable = self.fillCheck.GetValue()
-        
-        self.colorColChoice.Enable(enable)
-        self.colorColRadio.Enable(enable)
-        self.fillColorPicker.Enable(enable)
-        self.colorPickerRadio.Enable(enable)
-        if enable:
-            self.OnColor(None)
-        if not self.connection:
-            self.colorColChoice.Disable()
-            self.colorColRadio.Disable()
-            
-    def OnColor(self, event):
-        self.colorColChoice.Enable(self.colorColRadio.GetValue())
-        self.fillColorPicker.Enable(self.colorPickerRadio.GetValue())
-            
-    def OnSize(self, event):
-        self.sizeSpin.Enable(self.sizeRadio.GetValue())
-        self.sizeColChoice.Enable(self.sizecolumnRadio.GetValue())
-        self.scaleText.Enable(self.sizecolumnRadio.GetValue())
-        self.scaleSpin.Enable(self.sizecolumnRadio.GetValue())
-        
-    def OnRotation(self, event):
-        for each in (self.rotateRadio, self.rotatecolumnRadio, self.rotateColChoice, self.rotateSpin):
-            if self.rotateCheck.GetValue():
-                each.Enable()
-                self.OnRotationType(event = None)     
-            else:
-                each.Disable()
-           
-    def OnRotationType(self, event):
-        self.rotateSpin.Enable(self.rotateRadio.GetValue())
-        self.rotateColChoice.Enable(self.rotatecolumnRadio.GetValue())
-        
-    def OnPattern(self, event):
-        for each in (self.patFileCtrl, self.patWidthText, self.patWidthSpin, self.patScaleText, self.patScaleSpin):
-            each.Enable(self.patternCheck.GetValue())
-            
-    def EnableLayerSelection(self, enable = True):
-        for widget in self.gridBagSizerL.GetChildren():
-            if widget.GetWindow() != self.warning:
-                widget.GetWindow().Enable(enable)
-                
-    def getColsChoice(self, parent):
-        """!Returns a wx.Choice with table columns"""
-        if self.connection:
-            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
-        else:
-            cols = []
-
-        choice = wx.Choice(parent = parent, id = wx.ID_ANY, choices = cols)
-        return choice
-        
-    def update(self):
-        #feature type
-        if self.type in ('lines', 'points'):
-            featureType = None
-            if self.checkType1.GetValue():
-                featureType = self.checkType1.GetName()
-                if self.checkType2.GetValue():
-                    featureType += " or " + self.checkType2.GetName()
-            elif self.checkType2.GetValue():
-                featureType = self.checkType2.GetName()
-            if featureType:
-                self.vPropertiesDict['type'] = featureType
-            
-        # is connection
-        self.vPropertiesDict['connection'] = self.connection
-        if self.connection:
-            self.vPropertiesDict['layer'] = self.layerChoice.GetStringSelection()
-            if self.radioCats.GetValue() and not self.textCtrlCats.IsEmpty():
-                self.vPropertiesDict['cats'] = self.textCtrlCats.GetValue()
-            elif self.radioWhere.GetValue() and not self.textCtrlWhere.IsEmpty():
-                self.vPropertiesDict['where'] = self.choiceColumns.GetStringSelection() + " " \
-                                                                + self.textCtrlWhere.GetValue()
-        #mask
-        if self.mask.GetValue():
-            self.vPropertiesDict['masked'] = 'y' 
-        else:
-            self.vPropertiesDict['masked'] = 'n'
-
-        #colors
-        if self.type in ('points', 'areas'):
-            if self.outlineCheck.GetValue():
-                self.vPropertiesDict['color'] = convertRGB(self.colorPicker.GetColour())
-                self.vPropertiesDict['width'] = self.widthSpin.GetValue()
-            else:
-                self.vPropertiesDict['color'] = 'none'
-                
-            if self.fillCheck.GetValue():
-                if self.colorPickerRadio.GetValue():
-                    self.vPropertiesDict['fcolor'] = convertRGB(self.fillColorPicker.GetColour())
-                    self.vPropertiesDict['rgbcolumn'] = None
-                if self.colorColRadio.GetValue():
-                    self.vPropertiesDict['fcolor'] = 'none'# this color is taken in case of no record in rgb column
-                    self.vPropertiesDict['rgbcolumn'] = self.colorColChoice.GetStringSelection()
-            else:
-                self.vPropertiesDict['fcolor'] = 'none'    
-                
-        if self.type == 'lines':
-                #hcolor only when no rgbcolumn
-            if self.outlineCheck.GetValue():# and self.fillCheck.GetValue() and self.colorColRadio.GetValue():
-                self.vPropertiesDict['hcolor'] = convertRGB(self.colorPicker.GetColour())
-                self.vPropertiesDict['hwidth'] = self.outWidthSpin.GetValue()
-                
-            else:
-                self.vPropertiesDict['hcolor'] = 'none'
-                
-            if self.colorPickerRadio.GetValue():
-                self.vPropertiesDict['color'] = convertRGB(self.fillColorPicker.GetColour())
-                self.vPropertiesDict['rgbcolumn'] = None
-            if self.colorColRadio.GetValue():
-                self.vPropertiesDict['color'] = 'none'# this color is taken in case of no record in rgb column
-                self.vPropertiesDict['rgbcolumn'] = self.colorColChoice.GetStringSelection()
-        #
-        #size and style
-        #
-        
-        if self.type == 'points':
-            #symbols
-            if self.symbolRadio.GetValue():
-                self.vPropertiesDict['symbol'] = self.symbolChoice.GetStringSelection()
-                self.vPropertiesDict['eps'] = None
-            else:
-                self.vPropertiesDict['eps'] = self.epsFileCtrl.GetValue()
-                self.vPropertiesDict['symbol'] = None
-            #size
-            if self.sizeRadio.GetValue():
-                self.vPropertiesDict['size'] = self.sizeSpin.GetValue()
-                self.vPropertiesDict['sizecolumn'] = None
-                self.vPropertiesDict['scale'] = None
-            else:
-                self.vPropertiesDict['sizecolumn'] = self.sizeColChoice.GetStringSelection()
-                self.vPropertiesDict['scale'] = self.scaleSpin.GetValue()
-                self.vPropertiesDict['size'] = None
-            
-            #rotation
-            self.vPropertiesDict['rotate'] = None
-            self.vPropertiesDict['rotatecolumn'] = None
-            self.vPropertiesDict['rotation'] = False
-            if self.rotateCheck.GetValue():
-                self.vPropertiesDict['rotation'] = True
-            if self.rotateRadio.GetValue():
-                self.vPropertiesDict['rotate'] = self.rotateSpin.GetValue()
-            else:
-                self.vPropertiesDict['rotatecolumn'] = self.rotateColChoice.GetStringSelection()
-                
-        if self.type == 'areas':
-            #pattern
-            self.vPropertiesDict['pat'] = None 
-            if self.patternCheck.GetValue() and bool(self.patFileCtrl.GetValue()):
-                self.vPropertiesDict['pat'] = self.patFileCtrl.GetValue()
-                self.vPropertiesDict['pwidth'] = self.patWidthSpin.GetValue()
-                self.vPropertiesDict['scale'] = self.patScaleSpin.GetValue()
-                
-        if self.type == 'lines':
-            #width
-            if self.cwidthCheck.GetValue():
-                self.vPropertiesDict['cwidth'] = self.widthSpin.GetValue()
-                self.vPropertiesDict['width'] = None
-            else:
-                self.vPropertiesDict['width'] = self.widthSpin.GetValue()
-                self.vPropertiesDict['cwidth'] = None
-            #line style
-            if self.styleCombo.GetValue():
-                self.vPropertiesDict['style'] = self.styleCombo.GetValue() 
-            else:
-                self.vPropertiesDict['style'] = 'solid'
-
-            self.vPropertiesDict['linecap'] = self.linecapChoice.GetStringSelection()
-            
-    def OnOK(self, event):
-        self.update()
-        event.Skip()
-        
-class LegendDialog(PsmapDialog):
-    def __init__(self, parent, id, settings, page):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Legend settings", settings = settings)
-        self.objectType = ('rasterLegend', 'vectorLegend')
-        self.instruction = settings
-        map = self.instruction.FindInstructionByType('map')
-        if map:
-            self.mapId = map.id 
-        else:
-            self.mapId = None
-
-        vector = self.instruction.FindInstructionByType('vector')
-        if vector:
-            self.vectorId = vector.id 
-        else:
-            self.vectorId = None
-
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            self.rasterId = raster.id 
-        else:
-            self.rasterId = None
-
-        self.pageId = self.instruction.FindInstructionByType('page').id
-        currPage = self.instruction[self.pageId].GetInstruction()
-        #raster legend
-        if self.id[0] is not None:
-            self.rasterLegend = self.instruction[self.id[0]]
-            self.rLegendDict = self.rasterLegend.GetInstruction()
-        else:
-            self.id[0] = wx.NewId()
-            self.rasterLegend = RasterLegend(self.id[0])
-            self.rLegendDict = self.rasterLegend.GetInstruction()
-            self.rLegendDict['where'] = currPage['Left'], currPage['Top']
-            
-            
-        #vector legend    
-        if self.id[1] is not None:
-            self.vLegendDict = self.instruction[self.id[1]].GetInstruction()
-        else:
-            self.id[1] = wx.NewId()
-            vectorLegend = VectorLegend(self.id[1])
-            self.vLegendDict = vectorLegend.GetInstruction()
-            self.vLegendDict['where'] = currPage['Left'], currPage['Top']
-            
-        if self.rasterId:
-            self.currRaster = self.instruction[self.rasterId]['raster'] 
-        else:
-            self.currRaster = None
-
-        #notebook
-        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-        self.panelRaster = self._rasterLegend(self.notebook)
-        self.panelVector = self._vectorLegend(self.notebook)  
-        self.OnRaster(None)
-        self.OnRange(None)
-        self.OnIsLegend(None)
-        self.OnSpan(None)
-        self.OnBorder(None)
-                
-        self._layout(self.notebook)
-        self.notebook.ChangeSelection(page)
-        self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
-        
-    def OnPageChanging(self, event):
-        """!Workaround to scroll up to see the checkbox"""
-        wx.CallAfter(self.FindWindowByName('rasterPanel').ScrollChildIntoView,
-                                            self.FindWindowByName('showRLegend'))
-        wx.CallAfter(self.FindWindowByName('vectorPanel').ScrollChildIntoView,
-                                            self.FindWindowByName('showVLegend'))
-                                            
-    def _rasterLegend(self, notebook):
-        panel = scrolled.ScrolledPanel(parent = notebook, id = wx.ID_ANY, size = (-1, 500), style = wx.TAB_TRAVERSAL)
-        panel.SetupScrolling(scroll_x = False, scroll_y = True)
-        panel.SetName('rasterPanel')
-        notebook.AddPage(page = panel, text = _("Raster legend"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-        # is legend
-        self.isRLegend = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Show raster legend"))
-        self.isRLegend.SetValue(self.rLegendDict['rLegend'])
-        self.isRLegend.SetName("showRLegend")
-        border.Add(item = self.isRLegend, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        # choose raster
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Source raster"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(1)
-        
-        self.rasterDefault = wx.RadioButton(panel, id = wx.ID_ANY, label = _("current raster"), style = wx.RB_GROUP)
-        self.rasterOther = wx.RadioButton(panel, id = wx.ID_ANY, label = _("select raster"))
-        self.rasterDefault.SetValue(self.rLegendDict['rasterDefault'])#
-        self.rasterOther.SetValue(not self.rLegendDict['rasterDefault'])#
-
-        rasterType = getRasterType(map = self.currRaster)
-
-        self.rasterCurrent = wx.StaticText(panel, id = wx.ID_ANY,
-                                label = _("%(rast)s: type %(type)s") % { 'rast' : self.currRaster,
-                                                                         'type' : rasterType })
-        self.rasterSelect = Select(panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
-                                    type = 'raster', multiple = False,
-                                    updateOnPopup = True, onPopup = None)
-        if not self.rLegendDict['rasterDefault']:
-            self.rasterSelect.SetValue(self.rLegendDict['raster'])
-        else:
-            self.rasterSelect.SetValue('')
-        flexSizer.Add(self.rasterDefault, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.rasterCurrent, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border = 10)
-        flexSizer.Add(self.rasterOther, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.rasterSelect, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # type of legend
-        
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Type of legend"))        
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        vbox = wx.BoxSizer(wx.VERTICAL)
-        self.discrete = wx.RadioButton(parent = panel, id = wx.ID_ANY, 
-                        label = " %s " % _("discrete legend (categorical maps)"), style = wx.RB_GROUP)
-        self.continuous = wx.RadioButton(parent = panel, id = wx.ID_ANY, 
-                        label = " %s " % _("continuous color gradient legend (floating point map)"))
-        
-        vbox.Add(self.discrete, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
-        vbox.Add(self.continuous, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
-        sizer.Add(item = vbox, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # size, position and font
-        self.sizePositionFont(legendType = 'raster', parent = panel, mainSizer = border)
-        
-        # advanced settings
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Advanced legend settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        # no data
-        self.nodata = wx.CheckBox(panel, id = wx.ID_ANY, label = _('draw "no data" box'))
-        if self.rLegendDict['nodata'] == 'y':
-            self.nodata.SetValue(True)
-        else: 
-            self.nodata.SetValue(False)
-        #tickbar
-        self.ticks = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw ticks across color table"))
-        if self.rLegendDict['tickbar'] == 'y':
-            self.ticks.SetValue(True)
-        else:
-            self.ticks.SetValue(False)
-        # range
-        if self.rasterId and self.instruction[self.rasterId]['raster']:
-            rinfo = grass.raster_info(self.instruction[self.rasterId]['raster'])
-            self.minim, self.maxim = rinfo['min'], rinfo['max']
-        else:
-            self.minim, self.maxim = 0,0
-        self.range = wx.CheckBox(panel, id = wx.ID_ANY, label = _("range"))
-        self.range.SetValue(self.rLegendDict['range'])
-        self.minText =  wx.StaticText(panel, id = wx.ID_ANY, label = "min (%s)" % self.minim)
-        self.maxText =  wx.StaticText(panel, id = wx.ID_ANY, label = "max (%s)" % self.maxim)       
-        self.min = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(self.rLegendDict['min']))
-        self.max = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(self.rLegendDict['max']))
-        
-        gridBagSizer.Add(self.nodata, pos = (0,0), span = (1,5), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.ticks, pos = (1,0), span = (1,5), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.range, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.minText, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        gridBagSizer.Add(self.min, pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.maxText, pos = (2,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
-        gridBagSizer.Add(self.max, pos = (2,4), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-   
-        panel.SetSizer(border)
-        panel.Fit()
-        
-        # bindings
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterDefault)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterOther)
-        self.Bind(wx.EVT_CHECKBOX, self.OnIsLegend, self.isRLegend)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.discrete)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.continuous)
-##        self.Bind(wx.EVT_CHECKBOX, self.OnDefaultSize, panel.defaultSize)
-        self.Bind(wx.EVT_CHECKBOX, self.OnRange, self.range)
-        self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster)
-        
-        return panel
-    
-    def _vectorLegend(self, notebook):
-        panel = scrolled.ScrolledPanel(parent = notebook, id = wx.ID_ANY, size = (-1, 500), style = wx.TAB_TRAVERSAL)
-        panel.SetupScrolling(scroll_x = False, scroll_y = True)
-        panel.SetName('vectorPanel')
-        notebook.AddPage(page = panel, text = _("Vector legend"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-        # is legend
-        self.isVLegend = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Show vector legend"))
-        self.isVLegend.SetValue(self.vLegendDict['vLegend'])
-        self.isVLegend.SetName("showVLegend")
-        border.Add(item = self.isVLegend, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #vector maps, their order, labels
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Source vector maps"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(0,3)
-        gridBagSizer.AddGrowableCol(1,1)
-        
-        vectorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose vector maps and their order in legend"))
-
-        self.vectorListCtrl = CheckListCtrl(panel)
-        
-        self.vectorListCtrl.InsertColumn(0, _("Vector map"))
-        self.vectorListCtrl.InsertColumn(1, _("Label"))
-        if self.vectorId:
-            vectors = sorted(self.instruction[self.vectorId]['list'], key = lambda x: x[3])
-            
-            for vector in vectors:
-                index = self.vectorListCtrl.InsertStringItem(sys.maxint, vector[0].split('@')[0])
-                self.vectorListCtrl.SetStringItem(index, 1, vector[4])
-                self.vectorListCtrl.SetItemData(index, index)
-                self.vectorListCtrl.CheckItem(index, True)
-                if vector[3] == 0:
-                    self.vectorListCtrl.CheckItem(index, False)
-        if not self.vectorId:
-            self.vectorListCtrl.SetColumnWidth(0, 100)
-        else:
-            self.vectorListCtrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-        self.vectorListCtrl.SetColumnWidth(1, wx.LIST_AUTOSIZE)
-        
-        self.btnUp = wx.Button(panel, id = wx.ID_ANY, label = _("Up"))
-        self.btnDown = wx.Button(panel, id = wx.ID_ANY, label = _("Down"))
-        self.btnLabel = wx.Button(panel, id = wx.ID_ANY, label = _("Edit label"))
-      
-        gridBagSizer.Add(vectorText, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.vectorListCtrl, pos = (1,0), span = (3,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(self.btnUp, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.btnDown, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.btnLabel, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # size, position and font
-        self.sizePositionFont(legendType = 'vector', parent = panel, mainSizer = border)
-         
-        # border
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Border"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexGridSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
-        
-        self.borderCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw border around legend"))
-        self.borderColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY, style = wx.FNTP_FONTDESC_AS_LABEL)
-        if self.vLegendDict['border'] == 'none':
-            self.borderColorCtrl.SetColour(wx.BLACK)
-            self.borderCheck.SetValue(False)
-        else:
-            self.borderColorCtrl.SetColour(convertRGB(self.vLegendDict['border']))
-            self.borderCheck.SetValue(True)
-            
-        flexGridSizer.Add(self.borderCheck, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)    
-        flexGridSizer.Add(self.borderColorCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        sizer.Add(item = flexGridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(wx.EVT_BUTTON, self.OnUp, self.btnUp)
-        self.Bind(wx.EVT_BUTTON, self.OnDown, self.btnDown)  
-        self.Bind(wx.EVT_BUTTON, self.OnEditLabel, self.btnLabel)
-        self.Bind(wx.EVT_CHECKBOX, self.OnIsLegend, self.isVLegend)    
-        self.Bind(wx.EVT_CHECKBOX, self.OnSpan, panel.spanRadio)  
-        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.borderCheck)
-        self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnFont, panel.font['fontCtrl']) 
-        
-        panel.SetSizer(border)
-        
-        panel.Fit()
-        return panel
-    
-    def sizePositionFont(self, legendType, parent, mainSizer):
-        """!Insert widgets for size, position and font control"""
-        if legendType == 'raster':
-            legendDict = self.rLegendDict  
-        else:
-            legendDict = self.vLegendDict
-        panel = parent
-        border = mainSizer
-        
-        # size and position        
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size and position"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        #unit
-        self.AddUnits(parent = panel, dialogDict = legendDict)
-        unitBox = wx.BoxSizer(wx.HORIZONTAL)
-        unitBox.Add(panel.units['unitsLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border = 10)
-        unitBox.Add(panel.units['unitsCtrl'], proportion = 1, flag = wx.ALL, border = 5)
-        sizer.Add(unitBox, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        hBox = wx.BoxSizer(wx.HORIZONTAL)
-        posBox = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Position"))
-        posSizer = wx.StaticBoxSizer(posBox, wx.VERTICAL)       
-        sizeBox = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))
-        sizeSizer = wx.StaticBoxSizer(sizeBox, wx.VERTICAL) 
-        posGridBagSizer = wx.GridBagSizer(hgap = 10, vgap = 5)
-        posGridBagSizer.AddGrowableRow(2)
-        
-        #position
-        self.AddPosition(parent = panel, dialogDict = legendDict)
-        
-        posGridBagSizer.Add(panel.position['xLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        posGridBagSizer.Add(panel.position['xCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        posGridBagSizer.Add(panel.position['yLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        posGridBagSizer.Add(panel.position['yCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        posGridBagSizer.Add(panel.position['comment'], pos = (2,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
-        posSizer.Add(posGridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        
-        #size
-        width = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width:"))
-        if legendDict['width']:
-            w = self.unitConv.convert(value = float(legendDict['width']), fromUnit = 'inch', toUnit = legendDict['unit'])
-        else: 
-            w = ''
-        panel.widthCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(w), validator = TCValidator("DIGIT_ONLY"))
-        panel.widthCtrl.SetToolTipString(_("Leave the edit field empty, to use default values."))
-        
-        if legendType == 'raster':
-##            panel.defaultSize = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Use default size"))
-##            panel.defaultSize.SetValue(legendDict['defaultSize'])
-            
-            panel.heightOrColumnsLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:"))
-            if legendDict['height']:
-                h = self.unitConv.convert(value = float(legendDict['height']), fromUnit = 'inch', toUnit = legendDict['unit'])
-            else:
-                h = ''
-            panel.heightOrColumnsCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(h), validator = TCValidator("DIGIT_ONLY"))
-            
-            self.rSizeGBSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-##            self.rSizeGBSizer.Add(panel.defaultSize, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.rSizeGBSizer.Add(width, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.rSizeGBSizer.Add(panel.widthCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.rSizeGBSizer.Add(panel.heightOrColumnsLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.rSizeGBSizer.Add(panel.heightOrColumnsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            sizeSizer.Add(self.rSizeGBSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-            
-        if legendType == 'vector':
-            panel.widthCtrl.SetToolTipString(_("Width of the color symbol (for lines)\nin front of the legend text")) 
-            #columns
-            minVect, maxVect = 0, 0
-            if self.vectorId:
-                minVect = 1
-                maxVect = min(10, len(self.instruction[self.vectorId]['list']))
-            cols = wx.StaticText(panel, id = wx.ID_ANY, label = _("Columns:"))
-            panel.colsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, value = "",
-                                        min = minVect, max = maxVect, initial = legendDict['cols'])
-            #span
-            panel.spanRadio = wx.CheckBox(panel, id = wx.ID_ANY, label = _("column span:"))
-            panel.spanTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = '')
-            panel.spanTextCtrl.SetToolTipString(_("Column separation distance between the left edges\n"\
-                                                "of two columns in a multicolumn legend"))
-            if legendDict['span']:
-                panel.spanRadio.SetValue(True)
-                s = self.unitConv.convert(value = float(legendDict['span']), fromUnit = 'inch', toUnit = legendDict['unit'])    
-                panel.spanTextCtrl.SetValue(str(s))
-            else:
-                panel.spanRadio.SetValue(False)
-                
-            self.vSizeGBSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-            self.vSizeGBSizer.AddGrowableCol(1)
-            self.vSizeGBSizer.Add(width, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.vSizeGBSizer.Add(panel.widthCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.vSizeGBSizer.Add(cols, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.vSizeGBSizer.Add(panel.colsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.vSizeGBSizer.Add(panel.spanRadio, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            self.vSizeGBSizer.Add(panel.spanTextCtrl, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-            sizeSizer.Add(self.vSizeGBSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)        
-        
-        hBox.Add(posSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 3)
-        hBox.Add(sizeSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 3)
-        sizer.Add(hBox, proportion = 0, flag = wx.EXPAND, border = 0)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-              
-        # font        
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        fontSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(1)
-        
-        if legendType == 'raster':
-            self.AddFont(parent = panel, dialogDict = legendDict, color = True)
-        else:
-            self.AddFont(parent = panel, dialogDict = legendDict, color = False)            
-        flexSizer.Add(panel.font['fontLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(panel.font['fontCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(panel.font['fontSizeLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(panel.font['fontSizeCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        if legendType == 'raster':
-            flexSizer.Add(panel.font['colorLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-            flexSizer.Add(panel.font['colorCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        fontSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = fontSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)    
-
-    #   some enable/disable methods  
-        
-    def OnIsLegend(self, event):
-        """!Enables and disables controls, it depends if raster or vector legend is checked"""
-        page = self.notebook.GetSelection()
-        if page == 0 or event is None:
-            children = self.panelRaster.GetChildren()
-            if self.isRLegend.GetValue():
-                for i,widget in enumerate(children):
-                        widget.Enable()
-                self.OnRaster(None)
-                self.OnRange(None)
-                self.OnDiscrete(None)
-            else:
-                for widget in children:
-                    if widget.GetName() != 'showRLegend':
-                        widget.Disable()
-        if page == 1 or event is None:
-            children = self.panelVector.GetChildren()
-            if self.isVLegend.GetValue():
-                for i, widget in enumerate(children):
-                        widget.Enable()
-                self.OnSpan(None)
-                self.OnBorder(None)
-            else:
-                for widget in children:
-                    if widget.GetName() != 'showVLegend':
-                        widget.Disable()
-                    
-    def OnRaster(self, event):
-        if self.rasterDefault.GetValue():#default
-            self.rasterSelect.Disable()
-            type = getRasterType(self.currRaster)
-        else:#select raster
-            self.rasterSelect.Enable()
-            map = self.rasterSelect.GetValue()
-            type = getRasterType(map)
-  
-        if type == 'CELL':
-            self.discrete.SetValue(True)
-        elif type in ('FCELL', 'DCELL'):
-            self.continuous.SetValue(True)
-        if event is None:
-            if self.rLegendDict['discrete'] == 'y':
-                self.discrete.SetValue(True)
-            elif self.rLegendDict['discrete'] == 'n':
-                self.continuous.SetValue(True)
-        self.OnDiscrete(None)
-        
-    def OnDiscrete(self, event):
-        """! Change control according to the type of legend"""
-        enabledSize = self.panelRaster.heightOrColumnsCtrl.IsEnabled()
-        self.panelRaster.heightOrColumnsCtrl.Destroy()
-        if self.discrete.GetValue():
-            self.panelRaster.heightOrColumnsLabel.SetLabel(_("Columns:"))
-            self.panelRaster.heightOrColumnsCtrl = wx.SpinCtrl(self.panelRaster, id = wx.ID_ANY, value = "", min = 1, max = 10, initial = self.rLegendDict['cols'])
-            self.panelRaster.heightOrColumnsCtrl.Enable(enabledSize)
-            self.nodata.Enable()
-            self.range.Disable()
-            self.min.Disable()
-            self.max.Disable()
-            self.minText.Disable()
-            self.maxText.Disable()
-            self.ticks.Disable()
-        else:
-            self.panelRaster.heightOrColumnsLabel.SetLabel(_("Height:"))
-            if self.rLegendDict['height']:
-                h = self.unitConv.convert(value = float(self.rLegendDict['height']), fromUnit = 'inch', toUnit = self.rLegendDict['unit'])
-            else:
-                h = ''
-            self.panelRaster.heightOrColumnsCtrl = wx.TextCtrl(self.panelRaster, id = wx.ID_ANY,
-                                                    value = str(h), validator = TCValidator("DIGIT_ONLY"))
-            self.panelRaster.heightOrColumnsCtrl.Enable(enabledSize)
-            self.nodata.Disable()
-            self.range.Enable()
-            if self.range.GetValue():
-                self.minText.Enable()
-                self.maxText.Enable()
-                self.min.Enable()
-                self.max.Enable()
-            self.ticks.Enable()
-        
-        self.rSizeGBSizer.Add(self.panelRaster.heightOrColumnsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.panelRaster.Layout()
-        self.panelRaster.Fit()   
-        
-    def OnRange(self, event):
-        if not self.range.GetValue():
-            self.min.Disable()        
-            self.max.Disable()
-            self.minText.Disable()
-            self.maxText.Disable()
-        else:
-            self.min.Enable()        
-            self.max.Enable() 
-            self.minText.Enable()
-            self.maxText.Enable()           
-     
-    def OnUp(self, event):
-        """!Moves selected map up, changes order in vector legend"""
-        if self.vectorListCtrl.GetFirstSelected() != -1:
-            pos = self.vectorListCtrl.GetFirstSelected()
-            if pos:
-                idx1 = self.vectorListCtrl.GetItemData(pos) - 1
-                idx2 = self.vectorListCtrl.GetItemData(pos - 1) + 1
-                self.vectorListCtrl.SetItemData(pos, idx1) 
-                self.vectorListCtrl.SetItemData(pos - 1, idx2) 
-                self.vectorListCtrl.SortItems(cmp)
-                if pos > 0:
-                    selected = (pos - 1) 
-                else:
-                    selected = 0
-
-                self.vectorListCtrl.Select(selected)
-       
-    def OnDown(self, event):
-        """!Moves selected map down, changes order in vector legend"""
-        if self.vectorListCtrl.GetFirstSelected() != -1:
-            pos = self.vectorListCtrl.GetFirstSelected()
-            if pos != self.vectorListCtrl.GetItemCount() - 1:
-                idx1 = self.vectorListCtrl.GetItemData(pos) + 1
-                idx2 = self.vectorListCtrl.GetItemData(pos + 1) - 1
-                self.vectorListCtrl.SetItemData(pos, idx1) 
-                self.vectorListCtrl.SetItemData(pos + 1, idx2) 
-                self.vectorListCtrl.SortItems(cmp)
-                if pos < self.vectorListCtrl.GetItemCount() -1:
-                    selected = (pos + 1) 
-                else:
-                    selected = self.vectorListCtrl.GetItemCount() -1
-
-                self.vectorListCtrl.Select(selected)
-                
-    def OnEditLabel(self, event):
-        """!Change legend label of vector map"""
-        if self.vectorListCtrl.GetFirstSelected() != -1:
-            idx = self.vectorListCtrl.GetFirstSelected()
-            default = self.vectorListCtrl.GetItem(idx, 1).GetText()
-            dlg = wx.TextEntryDialog(self, message = _("Edit legend label:"), caption = _("Edit label"),
-                                    defaultValue = default, style = wx.OK|wx.CANCEL|wx.CENTRE)
-            if dlg.ShowModal() == wx.ID_OK:
-                new = dlg.GetValue()
-                self.vectorListCtrl.SetStringItem(idx, 1, new)
-            dlg.Destroy()
-        
-    def OnSpan(self, event):
-        self.panelVector.spanTextCtrl.Enable(self.panelVector.spanRadio.GetValue())
-    def OnFont(self, event):
-        """!Changes default width according to fontsize, width [inch] = fontsize[pt]/24"""   
-##        fontsize = self.panelVector.font['fontCtrl'].GetSelectedFont().GetPointSize() 
-        fontsize = self.panelVector.font['fontSizeCtrl'].GetValue()
-        unit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
-        w = fontsize/24.
-        width = self.unitConv.convert(value = w, fromUnit = 'inch', toUnit = unit)
-        self.panelVector.widthCtrl.SetValue("%3.2f" % width)
-        
-    def OnBorder(self, event):
-        """!Enables/disables colorPickerCtrl for border"""    
-        self.borderColorCtrl.Enable(self.borderCheck.GetValue())
-    
-    def updateRasterLegend(self):
-        """!Save information from raster legend dialog to dictionary"""
-
-        #is raster legend
-        if not self.isRLegend.GetValue():
-            self.rLegendDict['rLegend'] = False
-        else:
-            self.rLegendDict['rLegend'] = True
-        #units
-        currUnit = self.unitConv.findUnit(self.panelRaster.units['unitsCtrl'].GetStringSelection())
-        self.rLegendDict['unit'] = currUnit
-        # raster
-        if self.rasterDefault.GetValue():
-            self.rLegendDict['rasterDefault'] = True
-            self.rLegendDict['raster'] = self.currRaster
-        else:
-            self.rLegendDict['rasterDefault'] = False
-            self.rLegendDict['raster'] = self.rasterSelect.GetValue()
-        if self.rLegendDict['rLegend'] and not self.rLegendDict['raster']:
-            wx.MessageBox(message = _("No raster map selected!"),
-                                    caption = _('No raster'), style = wx.OK|wx.ICON_ERROR)
-            return False
-            
-        if self.rLegendDict['raster']:
-            # type and range of map
-            rasterType = getRasterType(self.rLegendDict['raster'])
-            if rasterType is None:
-                return False
-            self.rLegendDict['type'] = rasterType
-            
-            
-            #discrete
-            if self.discrete.GetValue():
-                self.rLegendDict['discrete'] = 'y'
-            else:
-                self.rLegendDict['discrete'] = 'n'   
-                    
-            # font 
-            self.rLegendDict['font'] = self.panelRaster.font['fontCtrl'].GetStringSelection()
-            self.rLegendDict['fontsize'] = self.panelRaster.font['fontSizeCtrl'].GetValue()
-            color = self.panelRaster.font['colorCtrl'].GetColour()
-            self.rLegendDict['color'] = convertRGB(color)
-
-            # position
-            x = self.unitConv.convert(value = float(self.panelRaster.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-            y = self.unitConv.convert(value = float(self.panelRaster.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-            self.rLegendDict['where'] = (x, y)
-            # estimated size
-            width = self.panelRaster.widthCtrl.GetValue()
-            try:
-                width = float(width)
-                width = self.unitConv.convert(value = width, fromUnit = currUnit, toUnit = 'inch')
-            except ValueError:
-                width = None
-            self.rLegendDict['width'] = width
-            if self.rLegendDict['discrete'] == 'n':
-                height = self.panelRaster.heightOrColumnsCtrl.GetValue()    
-                try:
-                    height = float(height)
-                    height = self.unitConv.convert(value = height, fromUnit = currUnit, toUnit = 'inch')
-                except ValueError:
-                    height = None
-                self.rLegendDict['height'] = height
-            else:
-                cols = self.panelRaster.heightOrColumnsCtrl.GetValue()
-                self.rLegendDict['cols'] = cols
-            drawHeight = self.rasterLegend.EstimateHeight(raster = self.rLegendDict['raster'], discrete = self.rLegendDict['discrete'],
-                                            fontsize = self.rLegendDict['fontsize'], cols = self.rLegendDict['cols'],
-                                            height = self.rLegendDict['height'])
-            drawWidth = self.rasterLegend.EstimateWidth(raster = self.rLegendDict['raster'], discrete = self.rLegendDict['discrete'],
-                                            fontsize = self.rLegendDict['fontsize'], cols = self.rLegendDict['cols'],
-                                            width = self.rLegendDict['width'], paperInstr = self.instruction[self.pageId])
-            self.rLegendDict['rect'] = wx.Rect2D(x = x, y = y, w = drawWidth, h = drawHeight)
-                        
-            # no data
-            if self.rLegendDict['discrete'] == 'y':
-                if self.nodata.GetValue():
-                    self.rLegendDict['nodata'] = 'y'
-                else:
-                    self.rLegendDict['nodata'] = 'n'
-            # tickbar
-            elif self.rLegendDict['discrete'] == 'n':
-                if self.ticks.GetValue():
-                    self.rLegendDict['tickbar'] = 'y'
-                else:
-                    self.rLegendDict['tickbar'] = 'n'
-            # range
-                if self.range.GetValue():
-                    self.rLegendDict['range'] = True
-                    self.rLegendDict['min'] = self.min.GetValue()
-                    self.rLegendDict['max'] = self.max.GetValue()
-                else:
-                    self.rLegendDict['range'] = False
-         
-        if not self.id[0] in self.instruction:
-            rasterLegend = RasterLegend(self.id[0])
-            self.instruction.AddInstruction(rasterLegend)
-        self.instruction[self.id[0]].SetInstruction(self.rLegendDict)
-
-        if self.id[0] not in self.parent.objectId:
-            self.parent.objectId.append(self.id[0])
-        return True
-    
-    def updateVectorLegend(self):
-        """!Save information from vector legend dialog to dictionary"""
-
-        vector = self.instruction.FindInstructionByType('vector')
-        if vector:
-            self.vectorId = vector.id 
-        else:
-            self.vectorId = None
-
-        #is vector legend
-        if not self.isVLegend.GetValue():
-            self.vLegendDict['vLegend'] = False
-        else:
-            self.vLegendDict['vLegend'] = True   
-        if self.vLegendDict['vLegend'] == True and self.vectorId is not None:
-            # labels
-            #reindex order
-            idx = 1
-            for item in range(self.vectorListCtrl.GetItemCount()):
-                if self.vectorListCtrl.IsChecked(item):
-                    self.vectorListCtrl.SetItemData(item, idx)
-                    idx += 1
-                else:
-                    self.vectorListCtrl.SetItemData(item, 0)
-            if idx == 1: 
-                self.vLegendDict['vLegend'] = False     
-            else:
-                vList = self.instruction[self.vectorId]['list']
-                for i, vector in enumerate(vList):
-                    item = self.vectorListCtrl.FindItem(start = -1, str = vector[0].split('@')[0])
-                    vList[i][3] = self.vectorListCtrl.GetItemData(item)
-                    vList[i][4] = self.vectorListCtrl.GetItem(item, 1).GetText()
-                vmaps = self.instruction.FindInstructionByType('vProperties', list = True)
-                for vmap, vector in zip(vmaps, vList):
-                    self.instruction[vmap.id]['lpos'] = vector[3]
-                    self.instruction[vmap.id]['label'] = vector[4]
-                #units
-                currUnit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
-                self.vLegendDict['unit'] = currUnit
-                # position
-                x = self.unitConv.convert(value = float(self.panelVector.position['xCtrl'].GetValue()),
-                                                                fromUnit = currUnit, toUnit = 'inch')
-                y = self.unitConv.convert(value = float(self.panelVector.position['yCtrl'].GetValue()),
-                                                                fromUnit = currUnit, toUnit = 'inch')
-                self.vLegendDict['where'] = (x, y)
-                
-                # font 
-                self.vLegendDict['font'] = self.panelVector.font['fontCtrl'].GetStringSelection()
-                self.vLegendDict['fontsize'] = self.panelVector.font['fontSizeCtrl'].GetValue()
-                dc = wx.PaintDC(self)
-                font = dc.GetFont()
-                dc.SetFont(wx.Font(pointSize = self.vLegendDict['fontsize'], family = font.GetFamily(),
-                                   style = font.GetStyle(), weight = wx.FONTWEIGHT_NORMAL))
-                #size
-                width = self.unitConv.convert(value = float(self.panelVector.widthCtrl.GetValue()),
-                                              fromUnit = currUnit, toUnit = 'inch')
-                self.vLegendDict['width'] = width
-                self.vLegendDict['cols'] = self.panelVector.colsCtrl.GetValue()
-                if self.panelVector.spanRadio.GetValue() and self.panelVector.spanTextCtrl.GetValue():
-                    self.vLegendDict['span'] = self.panelVector.spanTextCtrl.GetValue()
-                else:
-                    self.vLegendDict['span'] = None
-                    
-                # size estimation
-                vectors = self.instruction[self.vectorId]['list']
-                labels = [vector[4] for vector in vectors if vector[3] != 0]
-                extent = dc.GetTextExtent(max(labels, key = len))
-                wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'pixel', toUnit = 'inch')
-                hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'pixel', toUnit = 'inch')
-                w = (width + wExtent) * self.vLegendDict['cols']
-                h = len(labels) * hExtent / self.vLegendDict['cols']
-                h *= 1.1
-                self.vLegendDict['rect'] = wx.Rect2D(x, y, w, h)
-                
-                #border
-                if self.borderCheck.GetValue():
-                    color = self.borderColorCtrl.GetColour()
-                    self.vLegendDict['border'] = convertRGB(color)
-                    
-                else:
-                    self.vLegendDict['border'] = 'none'
-                                 
-        if not self.id[1] in self.instruction:
-            vectorLegend = VectorLegend(self.id[1])
-            self.instruction.AddInstruction(vectorLegend)
-        self.instruction[self.id[1]].SetInstruction(self.vLegendDict)
-        if self.id[1] not in self.parent.objectId:
-            self.parent.objectId.append(self.id[1])
-        return True
-    
-    def update(self):
-        okR = self.updateRasterLegend()
-        okV = self.updateVectorLegend()
-        if okR and okV:
-            return True
-        return False
-        
-    def updateDialog(self):
-        """!Update legend coordinates after moving"""
-        
-        # raster legend    
-        if 'rect' in self.rLegendDict:
-            x, y = self.rLegendDict['rect'][:2]
-            currUnit = self.unitConv.findUnit(self.panelRaster.units['unitsCtrl'].GetStringSelection())
-            x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-            y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-            self.panelRaster.position['xCtrl'].SetValue("%5.3f" % x)
-            self.panelRaster.position['yCtrl'].SetValue("%5.3f" % y)
-        #update name and type of raster
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            self.rasterId = raster.id 
-        else:
-            self.rasterId = None 
-
-        if raster:
-            currRaster = raster['raster'] 
-        else:
-            currRaster = None
-            
-        rasterType = getRasterType(map = currRaster)
-        self.rasterCurrent.SetLabel(_("%(rast)s: type %(type)s") % \
-                                        { 'rast' : currRaster, 'type' : str(rasterType) })
-        
-        # vector legend       
-        if 'rect' in self.vLegendDict:
-            x, y = self.vLegendDict['rect'][:2]
-            currUnit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
-            x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-            y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-            self.panelVector.position['xCtrl'].SetValue("%5.3f" % x)
-            self.panelVector.position['yCtrl'].SetValue("%5.3f" % y)
-        # update vector maps
-        if self.instruction.FindInstructionByType('vector'):
-            vectors = sorted(self.instruction.FindInstructionByType('vector')['list'], key = lambda x: x[3])
-            self.vectorListCtrl.DeleteAllItems()
-            for vector in vectors:
-                index = self.vectorListCtrl.InsertStringItem(sys.maxint, vector[0].split('@')[0])
-                self.vectorListCtrl.SetStringItem(index, 1, vector[4])
-                self.vectorListCtrl.SetItemData(index, index)
-                self.vectorListCtrl.CheckItem(index, True)
-                if vector[3] == 0:
-                    self.vectorListCtrl.CheckItem(index, False)
-            self.panelVector.colsCtrl.SetRange(1, min(10, len(self.instruction.FindInstructionByType('vector')['list'])))
-            self.panelVector.colsCtrl.SetValue(1)
-        else:
-            self.vectorListCtrl.DeleteAllItems()
-            self.panelVector.colsCtrl.SetRange(0,0)
-            self.panelVector.colsCtrl.SetValue(0)
-             
-class MapinfoDialog(PsmapDialog):
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Mapinfo settings", settings = settings)
-        
-        self.objectType = ('mapinfo',)
-        if self.id is not None:
-            self.mapinfo = self.instruction[self.id]
-            self.mapinfoDict = self.mapinfo.GetInstruction()
-        else:
-            self.id = wx.NewId()
-            self.mapinfo = Mapinfo(self.id)
-            self.mapinfoDict = self.mapinfo.GetInstruction()
-            page = self.instruction.FindInstructionByType('page').GetInstruction()
-            self.mapinfoDict['where'] = page['Left'], page['Top']
-
-        self.panel = self._mapinfoPanel()
-        
-        self._layout(self.panel)
-        self.OnIsBackground(None)
-        self.OnIsBorder(None)
-
-    def _mapinfoPanel(self):
-        panel = wx.Panel(parent = self, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        #panel.SetupScrolling(scroll_x = False, scroll_y = True)
-        border = wx.BoxSizer(wx.VERTICAL)
-                
-        # position     
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-        
-        self.AddPosition(parent = panel, dialogDict = self.mapinfoDict)
-        self.AddUnits(parent = panel, dialogDict = self.mapinfoDict)
-        gridBagSizer.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # font
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-        
-        self.AddFont(parent = panel, dialogDict = self.mapinfoDict)#creates font color too, used below
-        
-        gridBagSizer.Add(panel.font['fontLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.font['fontCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.font['fontSizeLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.font['fontSizeCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.font['colorLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        gridBagSizer.Add(panel.font['colorCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(item = gridBagSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        # colors
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Color settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(1)
-        
-        self.colors = {}
-        self.colors['borderCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use border color:"))
-        self.colors['backgroundCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use background color:"))
-        self.colors['borderColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        self.colors['backgroundColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        
-        if self.mapinfoDict['border'] == None:
-            self.mapinfoDict['border'] = 'none'
-        if self.mapinfoDict['border'] != 'none':
-            self.colors['borderCtrl'].SetValue(True) 
-            self.colors['borderColor'].SetColour(convertRGB(self.mapinfoDict['border']))
-        else:
-            self.colors['borderCtrl'].SetValue(False)
-            self.colors['borderColor'].SetColour(convertRGB('black'))
-            
-        if self.mapinfoDict['background'] == None:
-            self.mapinfoDict['background'] == 'none'
-        if self.mapinfoDict['background'] != 'none':
-            self.colors['backgroundCtrl'].SetValue(True) 
-            self.colors['backgroundColor'].SetColour(convertRGB(self.mapinfoDict['background']))
-        else:
-            self.colors['backgroundCtrl'].SetValue(False)
-            self.colors['backgroundColor'].SetColour(convertRGB('white'))
-                    
-        flexSizer.Add(self.colors['borderCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.colors['borderColor'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.colors['backgroundCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexSizer.Add(self.colors['backgroundColor'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        
-        self.Bind(wx.EVT_CHECKBOX, self.OnIsBorder, self.colors['borderCtrl'])
-        self.Bind(wx.EVT_CHECKBOX, self.OnIsBackground, self.colors['backgroundCtrl'])
-        
-        return panel
-    
-    def OnIsBackground(self, event):
-        if self.colors['backgroundCtrl'].GetValue():
-            self.colors['backgroundColor'].Enable()
-            self.update()
-        else:
-            self.colors['backgroundColor'].Disable()
-                        
-    def OnIsBorder(self, event):
-        if self.colors['borderCtrl'].GetValue():
-            self.colors['borderColor'].Enable()
-            self.update()
-        else:
-            self.colors['borderColor'].Disable() 
-                                           
-    def update(self):
-
-        #units
-        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
-        self.mapinfoDict['unit'] = currUnit
-        
-        # position
-        if self.panel.position['xCtrl'].GetValue():
-            x = self.panel.position['xCtrl'].GetValue() 
-        else:
-            x = self.mapinfoDict['where'][0]
-
-        if self.panel.position['yCtrl'].GetValue():
-            y = self.panel.position['yCtrl'].GetValue() 
-        else:
-            y = self.mapinfoDict['where'][1]
-
-        x = self.unitConv.convert(value = float(self.panel.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-        y = self.unitConv.convert(value = float(self.panel.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-        self.mapinfoDict['where'] = (x, y)
-        
-        # font
-        self.mapinfoDict['font'] =  self.panel.font['fontCtrl'].GetStringSelection()
-        self.mapinfoDict['fontsize'] = self.panel.font['fontSizeCtrl'].GetValue()
-
-        #colors
-        color = self.panel.font['colorCtrl'].GetColour()
-        self.mapinfoDict['color'] = convertRGB(color)
-        
-        if self.colors['backgroundCtrl'].GetValue():    
-            background = self.colors['backgroundColor'].GetColour()
-            self.mapinfoDict['background'] = convertRGB(background)
-        else:
-            self.mapinfoDict['background'] = 'none'
-
-        if self.colors['borderCtrl'].GetValue():    
-            border = self.colors['borderColor'].GetColour()
-            self.mapinfoDict['border'] = convertRGB(border)
-        else:
-            self.mapinfoDict['border'] = 'none'
-        
-        # estimation of size
-        self.mapinfoDict['rect'] = self.mapinfo.EstimateRect(self.mapinfoDict)
-
-        if self.id not in self.instruction:
-            mapinfo = Mapinfo(self.id)
-            self.instruction.AddInstruction(mapinfo)
-            
-        self.instruction[self.id].SetInstruction(self.mapinfoDict)
-
-        if self.id not in self.parent.objectId:
-            self.parent.objectId.append(self.id)
-            
-        self.updateDialog()
-
-        return True
-    
-    def updateDialog(self):
-        """!Update mapinfo coordinates, after moving"""
-        x, y = self.mapinfoDict['where']
-        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
-        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-        self.panel.position['xCtrl'].SetValue("%5.3f" % x)
-        self.panel.position['yCtrl'].SetValue("%5.3f" % y)
-             
-class ScalebarDialog(PsmapDialog):
-    """!Dialog for scale bar"""
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Scale bar settings", settings = settings)
-        self.objectType = ('scalebar',)
-        if self.id is not None:
-            self.scalebar = self.instruction[id]
-            self.scalebarDict = self.scalebar.GetInstruction()
-        else:
-            self.id = wx.NewId()
-            self.scalebar = Scalebar(self.id)
-            self.scalebarDict = self.scalebar.GetInstruction()
-            page = self.instruction.FindInstructionByType('page').GetInstruction()
-            self.scalebarDict['where'] = page['Left'], page['Top']
-
-        self.panel = self._scalebarPanel()
-        
-        self._layout(self.panel)
-        
-        self.mapUnit = projInfo()['units'].lower()
-        if projInfo()['proj'] == 'xy':
-            self.mapUnit = 'meters'
-        if self.mapUnit not in self.unitConv.getAllUnits():
-            wx.MessageBox(message = _("Units of current projection are not supported,\n meters will be used!"),
-                            caption = _('Unsupported units'),
-                                    style = wx.OK|wx.ICON_ERROR)
-            self.mapUnit = 'meters'
-            
-    def _scalebarPanel(self):
-        panel = wx.Panel(parent = self, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-        border = wx.BoxSizer(wx.VERTICAL)
-        #        
-        # position
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-        
-        self.AddUnits(parent = panel, dialogDict = self.scalebarDict)
-        self.AddPosition(parent = panel, dialogDict = self.scalebarDict)
-        
-        if self.scalebarDict['rect']: # set position, ref point is center and not left top corner
-            
-            x = self.unitConv.convert(value = self.scalebarDict['where'][0] - self.scalebarDict['rect'].Get()[2]/2,
-                                                    fromUnit = 'inch', toUnit = self.scalebarDict['unit'])
-            y = self.unitConv.convert(value = self.scalebarDict['where'][1] - self.scalebarDict['rect'].Get()[3]/2,
-                                                    fromUnit = 'inch', toUnit = self.scalebarDict['unit'])
-            panel.position['xCtrl'].SetValue("%5.3f" % x)
-            panel.position['yCtrl'].SetValue("%5.3f" % y)
-        
-        gridBagSizer.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        # size
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(1)
-        
-        lengthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Length:"))
-        heightText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:"))
-        
-        self.lengthTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, validator = TCValidator('DIGIT_ONLY'))
-        self.lengthTextCtrl.SetToolTipString(_("Scalebar length is given in map units"))
-        
-        self.heightTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, validator = TCValidator('DIGIT_ONLY'))
-        self.heightTextCtrl.SetToolTipString(_("Scalebar height is real height on paper"))
-        
-        choices = [_('default')] + self.unitConv.getMapUnitsNames()
-        self.unitsLength = wx.Choice(panel, id = wx.ID_ANY, choices = choices)
-        choices = self.unitConv.getPageUnitsNames()
-        self.unitsHeight = wx.Choice(panel, id = wx.ID_ANY, choices = choices)
-        
-        # set values
-        unitName = self.unitConv.findName(self.scalebarDict['unitsLength'])
-        if unitName:
-            self.unitsLength.SetStringSelection(unitName)
-        else:
-            if self.scalebarDict['unitsLength'] == 'auto':
-                 self.unitsLength.SetSelection(0)
-            elif self.scalebarDict['unitsLength'] == 'nautmiles':
-                 self.unitsLength.SetStringSelection(self.unitConv.findName("nautical miles"))
-        self.unitsHeight.SetStringSelection(self.unitConv.findName(self.scalebarDict['unitsHeight']))
-        if self.scalebarDict['length']:
-            self.lengthTextCtrl.SetValue(str(self.scalebarDict['length']))
-        else: #estimate default
-            reg = grass.region()
-            w = int((reg['e'] - reg['w'])/3)
-            w = round(w, -len(str(w)) + 2) #12345 -> 12000
-            self.lengthTextCtrl.SetValue(str(w))
-            
-        h = self.unitConv.convert(value = self.scalebarDict['height'], fromUnit = 'inch',
-                                                toUnit =  self.scalebarDict['unitsHeight']) 
-        self.heightTextCtrl.SetValue(str(h))
-        
-        gridBagSizer.Add(lengthText, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.lengthTextCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.unitsLength, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(heightText, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.heightTextCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.unitsHeight, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-      
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        #
-        #style
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Style"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        
-        
-        sbTypeText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Type:"))
-        self.sbCombo = wx.combo.BitmapComboBox(panel, style = wx.CB_READONLY)
-        # only temporary, images must be moved away
-        imagePath = os.path.join(globalvar.ETCIMGDIR, "scalebar-fancy.png"), os.path.join(globalvar.ETCIMGDIR, "scalebar-simple.png") 
-        for item, path in zip(['fancy', 'simple'], imagePath):
-            if not os.path.exists(path):
-                bitmap = wx.EmptyBitmap(0,0)
-            else:
-                bitmap = wx.Bitmap(path)
-            self.sbCombo.Append(item = '', bitmap = bitmap, clientData = item[0])
-        #self.sbCombo.Append(item = 'simple', bitmap = wx.Bitmap("./images/scalebar-simple.png"), clientData = 's')
-        if self.scalebarDict['scalebar'] == 'f':
-            self.sbCombo.SetSelection(0)
-        elif self.scalebarDict['scalebar'] == 's':
-            self.sbCombo.SetSelection(1)
-            
-        sbSegmentsText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Number of segments:"))
-        self.sbSegmentsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 4)
-        self.sbSegmentsCtrl.SetValue(self.scalebarDict['segment'])
-        
-        sbLabelsText1 = wx.StaticText(panel, id = wx.ID_ANY, label = _("Label every "))
-        sbLabelsText2 = wx.StaticText(panel, id = wx.ID_ANY, label = _("segments"))
-        self.sbLabelsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1)
-        self.sbLabelsCtrl.SetValue(self.scalebarDict['numbers'])
-        
-        #font
-        fontsizeText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Font size:"))
-        self.fontsizeCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 4, max = 30, initial = 10)
-        self.fontsizeCtrl.SetValue(self.scalebarDict['fontsize'])
-        
-        self.backgroundCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent text background"))
-        if self.scalebarDict['background'] == 'y':
-            self.backgroundCheck.SetValue(False)
-        else:
-            self.backgroundCheck.SetValue(True)
-
-        gridBagSizer.Add(sbTypeText, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sbCombo, pos = (0,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-        gridBagSizer.Add(sbSegmentsText, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sbSegmentsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(sbLabelsText1, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.sbLabelsCtrl, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(sbLabelsText2, pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(fontsizeText, pos = (3,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.fontsizeCtrl, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.backgroundCheck, pos = (4, 0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        
-        return panel
-                           
-    def update(self):
-        """!Save information from dialog"""
-
-        #units
-        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
-        self.scalebarDict['unit'] = currUnit
-        # position
-        if self.panel.position['xCtrl'].GetValue():
-            x = self.panel.position['xCtrl'].GetValue() 
-        else:
-            x = self.scalebarDict['where'][0]
-
-        if self.panel.position['yCtrl'].GetValue():
-            y = self.panel.position['yCtrl'].GetValue() 
-        else:
-            y = self.scalebarDict['where'][1]
-
-        x = self.unitConv.convert(value = float(self.panel.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-        y = self.unitConv.convert(value = float(self.panel.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
-        
-        #style
-        self.scalebarDict['scalebar'] = self.sbCombo.GetClientData(self.sbCombo.GetSelection())
-        self.scalebarDict['segment'] = self.sbSegmentsCtrl.GetValue()
-        self.scalebarDict['numbers'] = self.sbLabelsCtrl.GetValue()
-        self.scalebarDict['fontsize'] = self.fontsizeCtrl.GetValue()
-        if self.backgroundCheck.GetValue():
-            self.scalebarDict['background'] = 'n' 
-        else:
-            self.scalebarDict['background'] = 'y'
-
-        
-        # size
-        
-        # height
-        self.scalebarDict['unitsHeight'] = self.unitConv.findUnit(self.unitsHeight.GetStringSelection())
-        try:
-            height = float(self.heightTextCtrl.GetValue())  
-            height = self.unitConv.convert(value = height, fromUnit = self.scalebarDict['unitsHeight'], toUnit = 'inch') 
-        except (ValueError, SyntaxError):
-            height = 0.1 #default in inch
-        self.scalebarDict['height'] = height    
-        
-        #length
-        if self.unitsLength.GetSelection() == 0:
-            selected = 'auto'
-        else:
-            selected = self.unitConv.findUnit(self.unitsLength.GetStringSelection())
-            if selected == 'nautical miles':
-                selected = 'nautmiles'
-        self.scalebarDict['unitsLength'] = selected
-        try:
-            length = float(self.lengthTextCtrl.GetValue())
-        except (ValueError, SyntaxError):
-            wx.MessageBox(message = _("Length of scale bar is not defined"),
-                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
-            return False
-        self.scalebarDict['length'] = length
-            
-        # estimation of size
-        map = self.instruction.FindInstructionByType('map')
-        if not map:
-            map = self.instruction.FindInstructionByType('initMap')
-        mapId = map.id
-         
-        rectSize = self.scalebar.EstimateSize(scalebarDict = self.scalebarDict,
-                                                                scale = self.instruction[mapId]['scale'])
-        self.scalebarDict['rect'] = wx.Rect2D(x = x, y = y, w = rectSize[0], h = rectSize[1])
-        self.scalebarDict['where'] = self.scalebarDict['rect'].GetCentre() 
-
-        if self.id not in self.instruction:
-            scalebar = Scalebar(self.id)
-            self.instruction.AddInstruction(scalebar)
-        self.instruction[self.id].SetInstruction(self.scalebarDict)
-        if self.id not in self.parent.objectId:
-            self.parent.objectId.append(self.id)
-            
-        return True
-    
-    def updateDialog(self):
-        """!Update scalebar coordinates, after moving"""
-        x, y = self.scalebarDict['rect'][:2]
-        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
-        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-        self.panel.position['xCtrl'].SetValue("%5.3f" % x)
-        self.panel.position['yCtrl'].SetValue("%5.3f" % y)
-        
- 
-        
-class TextDialog(PsmapDialog):
-    def __init__(self, parent, id, settings):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Text settings", settings = settings)
-        self.objectType = ('text',)
-        if self.id is not None:
-            self.textDict = self.instruction[id].GetInstruction()
-        else:
-            self.id = wx.NewId()  
-            text = Text(self.id)
-            self.textDict = text.GetInstruction()
-            page = self.instruction.FindInstructionByType('page').GetInstruction()
-            self.textDict['where'] = page['Left'], page['Top'] 
-                
-        map = self.instruction.FindInstructionByType('map')
-        if not map:
-            map = self.instruction.FindInstructionByType('initMap')
-        self.mapId = map.id
-
-        self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(map = map, x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
-        
-        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)     
-        self.textPanel = self._textPanel(notebook)
-        self.positionPanel = self._positionPanel(notebook)
-        self.OnBackground(None)
-        self.OnHighlight(None)
-        self.OnBorder(None)
-        self.OnPositionType(None)
-        self.OnRotation(None)
-     
-        self._layout(notebook)
-
-    def _textPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Text"))
-        
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        # text entry    
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        
-        textLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Enter text:"))
-        self.textCtrl = ExpandoTextCtrl(panel, id = wx.ID_ANY, value = self.textDict['text'])
-        
-        sizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        sizer.Add(self.textCtrl, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)        
-        
-        #font       
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexGridSizer = wx.FlexGridSizer (rows = 3, cols = 2, hgap = 5, vgap = 5)
-        flexGridSizer.AddGrowableCol(1)
-        
-        self.AddFont(parent = panel, dialogDict = self.textDict)
-        
-        flexGridSizer.Add(panel.font['fontLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexGridSizer.Add(panel.font['fontCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexGridSizer.Add(panel.font['fontSizeLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexGridSizer.Add(panel.font['fontSizeCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        flexGridSizer.Add(panel.font['colorLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
-        flexGridSizer.Add(panel.font['colorCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(item = flexGridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #text effects        
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text effects"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
-        
-        self.effect = {}
-        self.effect['backgroundCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text background"))
-        self.effect['backgroundColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        
-        self.effect['highlightCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("highlight"))
-        self.effect['highlightColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        self.effect['highlightWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 0, max = 5, initial = 1)
-        self.effect['highlightWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
-        
-        self.effect['borderCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text border"))
-        self.effect['borderColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
-        self.effect['borderWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 1, max = 25, initial = 1)
-        self.effect['borderWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
-
-        #set values
-        if self.textDict['background'] == None:
-            self.textDict['background'] = 'none'
-        if self.textDict['background'] != 'none':
-            self.effect['backgroundCtrl'].SetValue(True) 
-            self.effect['backgroundColor'].SetColour(convertRGB(self.textDict['background']))
-        else:
-            self.effect['backgroundCtrl'].SetValue(False)
-            self.effect['backgroundColor'].SetColour(convertRGB('white'))
-
-        if self.textDict['hcolor'] == None:
-             self.textDict['hcolor'] = 'none'
-        if self.textDict['hcolor'] != 'none':
-            self.effect['highlightCtrl'].SetValue(True) 
-            self.effect['highlightColor'].SetColour(convertRGB(self.textDict['hcolor']))
-        else:
-            self.effect['highlightCtrl'].SetValue(False)
-            self.effect['highlightColor'].SetColour(convertRGB('grey'))
-
-        self.effect['highlightWidth'].SetValue(float(self.textDict['hwidth']))
-        
-        if self.textDict['border'] == None:
-            self.textDict['border'] = 'none'
-        if self.textDict['border'] != 'none':
-            self.effect['borderCtrl'].SetValue(True) 
-            self.effect['borderColor'].SetColour(convertRGB(self.textDict['border'])) 
-        else:
-            self.effect['borderCtrl'].SetValue(False)
-            self.effect['borderColor'].SetColour(convertRGB('black'))
-
-        self.effect['borderWidth'].SetValue(float(self.textDict['width']))
-        
-        gridBagSizer.Add(self.effect['backgroundCtrl'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['backgroundColor'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['highlightCtrl'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['highlightColor'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['highlightWidthLabel'], pos = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['highlightWidth'], pos = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['borderCtrl'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['borderColor'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['borderWidthLabel'], pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizer.Add(self.effect['borderWidth'], pos = (2,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizer.Add(item = gridBagSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textCtrl)
-        self.Bind(wx.EVT_CHECKBOX, self.OnBackground, self.effect['backgroundCtrl'])
-        self.Bind(wx.EVT_CHECKBOX, self.OnHighlight, self.effect['highlightCtrl'])
-        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.effect['borderCtrl'])
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        
-        return panel 
-        
-    def _positionPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Position"))
-
-        border = wx.BoxSizer(wx.VERTICAL) 
-
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(0)
-        gridBagSizer.AddGrowableCol(1)
-        
-        #Position
-        self.AddExtendedPosition(panel, gridBagSizer, self.textDict)
-        
-        #offset
-        box3   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Offset"))
-        sizerO = wx.StaticBoxSizer(box3, wx.VERTICAL)
-        gridBagSizerO = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.xoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("horizontal (pts):"))
-        self.yoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("vertical (pts):"))
-        self.xoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0)
-        self.yoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0) 
-        self.xoffCtrl.SetValue(self.textDict['xoffset'])       
-        self.yoffCtrl.SetValue(self.textDict['yoffset'])
-        gridBagSizerO.Add(self.xoffLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizerO.Add(self.yoffLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizerO.Add(self.xoffCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridBagSizerO.Add(self.yoffCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizerO.Add(gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerO, pos = (3,0), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
-        # reference point
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_(" Reference point"))
-        sizerR = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer(rows = 3, cols = 3, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        flexSizer.AddGrowableCol(1)
-        flexSizer.AddGrowableCol(2)
-        ref = []
-        for row in ["upper", "center", "lower"]:
-            for col in ["left", "center", "right"]:
-                ref.append(row + " " + col)
-        self.radio = [wx.RadioButton(panel, id = wx.ID_ANY, label = '', style = wx.RB_GROUP, name = ref[0])]
-        self.radio[0].SetValue(False)
-        flexSizer.Add(self.radio[0], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
-        for i in range(1,9):
-            self.radio.append(wx.RadioButton(panel, id = wx.ID_ANY, label = '', name = ref[i]))
-            self.radio[-1].SetValue(False)
-            flexSizer.Add(self.radio[-1], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
-        self.FindWindowByName(self.textDict['ref']).SetValue(True)
-                
-        sizerR.Add(flexSizer, proportion = 1, flag = wx.EXPAND, border = 0)
-        gridBagSizer.Add(sizerR, pos = (3,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-                
-        #rotation
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text rotation"))
-        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
-        self.rotCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("rotate text (counterclockwise)"))
-        self.rotValue = wx.SpinCtrl(panel, wx.ID_ANY, size = (50, -1), min = 0, max = 360, initial = 0)
-        if self.textDict['rotate']:
-            self.rotValue.SetValue(int(self.textDict['rotate']))
-            self.rotCtrl.SetValue(True)
-        else:
-            self.rotValue.SetValue(0)
-            self.rotCtrl.SetValue(False)
-        sizer.Add(self.rotCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
-        sizer.Add(self.rotValue, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
-        
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-          
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
-        self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotCtrl)
-        
-        return panel
-     
-    def OnRefit(self, event):
-        self.Fit()
-        
-    def OnRotation(self, event):
-        if self.rotCtrl.GetValue():
-            self.rotValue.Enable()
-        else: 
-            self.rotValue.Disable()
-            
-    def OnPositionType(self, event):
-        if self.positionPanel.position['toPaper'].GetValue():
-            for widget in self.gridBagSizerP.GetChildren():
-                widget.GetWindow().Enable()
-            for widget in self.gridBagSizerM.GetChildren():
-                widget.GetWindow().Disable()
-        else:
-            for widget in self.gridBagSizerM.GetChildren():
-                widget.GetWindow().Enable()
-            for widget in self.gridBagSizerP.GetChildren():
-                widget.GetWindow().Disable()
-                
-    def OnBackground(self, event):
-        if self.effect['backgroundCtrl'].GetValue():
-            self.effect['backgroundColor'].Enable()
-            self.update()
-        else:
-            self.effect['backgroundColor'].Disable()
-    
-    def OnHighlight(self, event):
-        if self.effect['highlightCtrl'].GetValue():
-            self.effect['highlightColor'].Enable()
-            self.effect['highlightWidth'].Enable()
-            self.effect['highlightWidthLabel'].Enable()
-            self.update()
-        else:
-            self.effect['highlightColor'].Disable()
-            self.effect['highlightWidth'].Disable()
-            self.effect['highlightWidthLabel'].Disable()
-            
-    def OnBorder(self, event):
-        if self.effect['borderCtrl'].GetValue():
-            self.effect['borderColor'].Enable()
-            self.effect['borderWidth'].Enable()
-            self.effect['borderWidthLabel'].Enable()
-            self.update()
-        else:
-            self.effect['borderColor'].Disable()
-            self.effect['borderWidth'].Disable()
-            self.effect['borderWidthLabel'].Disable()
-            
-    def update(self): 
-        #text
-        self.textDict['text'] = self.textCtrl.GetValue()
-        if not self.textDict['text']:
-            wx.MessageBox(_("No text entered!"), _("Error"))
-            return False
-            
-        #font
-        self.textDict['font'] = self.textPanel.font['fontCtrl'].GetStringSelection()
-        self.textDict['fontsize'] = self.textPanel.font['fontSizeCtrl'].GetValue()
-        color = self.textPanel.font['colorCtrl'].GetColour()
-        self.textDict['color'] = convertRGB(color)
-
-        #effects
-        if self.effect['backgroundCtrl'].GetValue():
-            background = self.effect['backgroundColor'].GetColour()
-            self.textDict['background'] = convertRGB(background)
-        else:
-            self.textDict['background'] = 'none'        
-                
-        if self.effect['borderCtrl'].GetValue():
-            border = self.effect['borderColor'].GetColour()
-            self.textDict['border'] = convertRGB(border)
-        else:
-            self.textDict['border'] = 'none' 
-                     
-        self.textDict['width'] = self.effect['borderWidth'].GetValue()
-        
-        if self.effect['highlightCtrl'].GetValue():
-            highlight = self.effect['highlightColor'].GetColour()
-            self.textDict['hcolor'] = convertRGB(highlight)
-        else:
-            self.textDict['hcolor'] = 'none'
-
-        self.textDict['hwidth'] = self.effect['highlightWidth'].GetValue()
-        
-        #offset
-        self.textDict['xoffset'] = self.xoffCtrl.GetValue()
-        self.textDict['yoffset'] = self.yoffCtrl.GetValue()
-
-        #position
-        if self.positionPanel.position['toPaper'].GetValue():
-            self.textDict['XY'] = True
-            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
-            self.textDict['unit'] = currUnit
-            if self.positionPanel.position['xCtrl'].GetValue():
-                x = self.positionPanel.position['xCtrl'].GetValue() 
-            else:
-                x = self.textDict['where'][0]
-
-            if self.positionPanel.position['yCtrl'].GetValue():
-                y = self.positionPanel.position['yCtrl'].GetValue() 
-            else:
-                y = self.textDict['where'][1]
-
-            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
-            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
-            self.textDict['where'] = x, y
-            self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(self.instruction[self.mapId], x, y, paperToMap = True)
-        else:
-            self.textDict['XY'] = False
-            if self.positionPanel.position['eCtrl'].GetValue():
-                self.textDict['east'] = self.positionPanel.position['eCtrl'].GetValue() 
-            else:
-                self.textDict['east'] = self.textDict['east']
-
-            if self.positionPanel.position['nCtrl'].GetValue():
-                self.textDict['north'] = self.positionPanel.position['nCtrl'].GetValue() 
-            else:
-                self.textDict['north'] = self.textDict['north']
-
-            self.textDict['where'] = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.textDict['east']),
-                                                            y = float(self.textDict['north']), paperToMap = False)
-        #rotation
-        if self.rotCtrl.GetValue():
-            self.textDict['rotate'] = self.rotValue.GetValue()
-        else:
-            self.textDict['rotate'] = None
-        #reference point
-        for radio in self.radio:
-            if radio.GetValue() == True:
-                self.textDict['ref'] = radio.GetName()
-                
-        if self.id not in self.instruction:
-            text = Text(self.id)
-            self.instruction.AddInstruction(text)
-        self.instruction[self.id].SetInstruction(self.textDict)
-        
-        if self.id not in self.parent.objectId:
-            self.parent.objectId.append(self.id)
-
-#        self.updateDialog()
-
-        return True
-    
-    def updateDialog(self):
-        """!Update text coordinates, after moving"""
-        # XY coordinates
-        x, y = self.textDict['where'][:2]
-        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
-        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
-        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
-        # EN coordinates
-        e, n = self.textDict['east'], self.textDict['north']
-        self.positionPanel.position['eCtrl'].SetValue(str(self.textDict['east']))
-        self.positionPanel.position['nCtrl'].SetValue(str(self.textDict['north']))
-        
-class ImageDialog(PsmapDialog):
-    """!Dialog for setting image properties.
-    
-    It's base dialog for North Arrow dialog.
-    """
-    def __init__(self, parent, id, settings, imagePanelName = _("Image")):
-        PsmapDialog.__init__(self, parent = parent, id = id, title = "Image settings",
-                             settings = settings)
-        
-        self.objectType = ('image',)
-        if self.id is not None:
-            self.imageObj = self.instruction[self.id]
-            self.imageDict = self.instruction[id].GetInstruction()
-        else:
-            self.id = wx.NewId()
-            self.imageObj = self._newObject()
-            self.imageDict = self.imageObj.GetInstruction()
-            page = self.instruction.FindInstructionByType('page').GetInstruction()
-            self.imageDict['where'] = page['Left'], page['Top'] 
-                
-        map = self.instruction.FindInstructionByType('map')
-        if not map:
-            map = self.instruction.FindInstructionByType('initMap')
-        self.mapId = map.id
-
-        self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(map = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
-        
-        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-        self.imagePanelName = imagePanelName
-        self.imagePanel = self._imagePanel(notebook)
-        self.positionPanel = self._positionPanel(notebook)
-        self.OnPositionType(None)
-        
-        if self.imageDict['epsfile']:
-            self.imagePanel.image['dir'].SetValue(os.path.dirname(self.imageDict['epsfile']))
-        else:
-            self.imagePanel.image['dir'].SetValue(self._getImageDirectory())
-        self.OnDirChanged(None)
-     
-        self._layout(notebook)
-        
-        
-    def _newObject(self):
-        """!Create corresponding instruction object"""
-        return Image(self.id, self.instruction)
-        
-    def _imagePanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = self.imagePanelName)
-        border = wx.BoxSizer(wx.VERTICAL)
-        #
-        # choose image
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Image"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        # choose directory
-        panel.image = {}
-        if self.imageDict['epsfile']:
-            startDir = os.path.dirname(self.imageDict['epsfile'])
-        else:
-            startDir = self._getImageDirectory()
-        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
-                                         labelText = _("Choose a directory:"),
-                                         dialogTitle = _("Choose a directory with images"),
-                                         buttonText = _('Browse'),
-                                         startDirectory = startDir,
-                                         changeCallback = self.OnDirChanged)
-        panel.image['dir'] = dir
-       
-        
-        sizer.Add(item = dir, proportion = 0, flag = wx.EXPAND, border = 0)
-        
-        # image list
-        hSizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        imageList = wx.ListBox(parent = panel, id = wx.ID_ANY)
-        panel.image['list'] = imageList
-        imageList.Bind(wx.EVT_LISTBOX, self.OnImageSelectionChanged)
-        
-        hSizer.Add(item = imageList, proportion = 1, flag = wx.EXPAND | wx.RIGHT, border = 10)
-        
-        # image preview
-        vSizer = wx.BoxSizer(wx.VERTICAL)
-        self.previewSize = (150, 150)
-        img = wx.EmptyImage(*self.previewSize)
-        panel.image['preview'] = wx.StaticBitmap(parent = panel, id = wx.ID_ANY,
-                                                bitmap = wx.BitmapFromImage(img))
-        vSizer.Add(item = panel.image['preview'], proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
-        panel.image['sizeInfo'] = wx.StaticText(parent = panel, id = wx.ID_ANY)
-        vSizer.Add(item = panel.image['sizeInfo'], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
-        
-        hSizer.Add(item = vSizer, proportion = 0, flag = wx.EXPAND, border = 0)
-        sizer.Add(item = hSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 3)
-        
-        epsInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                label = _("Note: only EPS format supported"))
-        sizer.Add(item = epsInfo, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 3)
-        
-        
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        #
-        # rotation
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Scale And Rotation"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        
-        scaleLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Scale:"))
-        if fs:
-            panel.image['scale'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
-                                          increment = 0.5, value = 1, style = fs.FS_RIGHT, size = self.spinCtrlSize)
-            panel.image['scale'].SetFormat("%f")
-            panel.image['scale'].SetDigits(1)
-        else:
-            panel.image['scale'] = wx.TextCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize,
-                                                  validator = TCValidator(flag = 'DIGIT_ONLY'))
-        
-        if self.imageDict['scale']:
-            if fs:
-                value = float(self.imageDict['scale'])
-            else:
-                value = str(self.imageDict['scale'])
-        else:
-            if fs:
-                value = 0
-            else:
-                value = '0'
-        panel.image['scale'].SetValue(value)
-            
-        gridSizer.Add(item = scaleLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
-        gridSizer.Add(item = panel.image['scale'], pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        
-        rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
-        if fs:
-            panel.image['rotate'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 360,
-                                          increment = 0.5, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
-            panel.image['rotate'].SetFormat("%f")
-            panel.image['rotate'].SetDigits(1)
-        else:
-            panel.image['rotate'] = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
-                                                min = 0, max = 359, initial = 0)
-        panel.image['rotate'].SetToolTipString(_("Counterclockwise rotation in degrees"))
-        if self.imageDict['rotate']:
-            panel.image['rotate'].SetValue(int(self.imageDict['rotate']))
-        else:
-            panel.image['rotate'].SetValue(0)
-            
-        gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        gridSizer.Add(item = panel.image['rotate'], pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
-        
-        self._addConvergence(panel = panel, gridBagSizer = gridSizer)
-        sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        
-        return panel
-        
-    def _positionPanel(self, notebook):
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
-        notebook.AddPage(page = panel, text = _("Position"))
-        border = wx.BoxSizer(wx.VERTICAL)
-        #
-        # set position
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        gridBagSizer.AddGrowableCol(0)
-        gridBagSizer.AddGrowableCol(1)
-        
-        self.AddExtendedPosition(panel, gridBagSizer, self.imageDict)
-        
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
-        
-        
-        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-        
-        panel.SetSizer(border)
-        panel.Fit()
-        
-        return panel
-        
-    def OnDirChanged(self, event):
-        """!Image directory changed"""
-        path = self.imagePanel.image['dir'].GetValue()
-        try:
-            files = os.listdir(path)
-        except OSError: # no such directory
-            files = []
-        imageList = []
-        
-        # no setter for startDirectory?
-        try:
-            self.imagePanel.image['dir'].startDirectory = path
-        except AttributeError: # for sure
-            pass
-        for file in files:
-            if os.path.splitext(file)[1].lower() == '.eps':
-                imageList.append(file)
-        
-        imageList.sort()
-        self.imagePanel.image['list'].SetItems(imageList)
-        if self.imageDict['epsfile']:
-            file = os.path.basename(self.imageDict['epsfile'])
-            self.imagePanel.image['list'].SetStringSelection(file)
-        elif imageList:
-            self.imagePanel.image['list'].SetSelection(0)
-        self.OnImageSelectionChanged(None)
-        
-    def OnPositionType(self, event):
-        if self.positionPanel.position['toPaper'].GetValue():
-            for widget in self.gridBagSizerP.GetChildren():
-                widget.GetWindow().Enable()
-            for widget in self.gridBagSizerM.GetChildren():
-                widget.GetWindow().Disable()
-        else:
-            for widget in self.gridBagSizerM.GetChildren():
-                widget.GetWindow().Enable()
-            for widget in self.gridBagSizerP.GetChildren():
-                widget.GetWindow().Disable()
-                
-    def _getImageDirectory(self):
-        """!Default image directory"""
-        return os.getcwd()
-        
-    def _addConvergence(self, panel, gridBagSizer):
-        pass
-        
-    def OnImageSelectionChanged(self, event):
-        """!Image selected, show preview and size"""
-        if not self.imagePanel.image['dir']: # event is emitted when closing dialog an it causes error
-            return
-            
-        if not havePILImage:
-            self.DrawWarningText(_("PIL\nmissing"))
-            return
-        
-        imageName = self.imagePanel.image['list'].GetStringSelection()
-        if not imageName:
-            self.ClearPreview()
-            return
-        basePath = self.imagePanel.image['dir'].GetValue()
-        file = os.path.join(basePath, imageName)
-        if not os.path.exists(file):
-            return
-            
-        if os.path.splitext(file)[1].lower() == '.eps':
-            try:
-                pImg = PILImage.open(file)
-                img = PilImageToWxImage(pImg)
-            except IOError, e:
-                GError(message = _("Unable to read file %s") % file)
-                self.ClearPreview()
-                return
-            self.SetSizeInfoLabel(img)
-            img = self.ScaleToPreview(img)
-            bitmap = img.ConvertToBitmap()
-            self.DrawBitmap(bitmap)
-            
-        else:
-            # TODO: read other formats and convert by PIL to eps
-            pass
-    
-    def ScaleToPreview(self, img):
-        """!Scale image to preview size"""
-        w = img.GetWidth()
-        h = img.GetHeight()
-        if w <= self.previewSize[0] and h <= self.previewSize[1]:
-            return img
-        if w > h:
-            newW = self.previewSize[0]
-            newH = self.previewSize[0] * h / w
-        else:
-            newH = self.previewSize[0]
-            newW = self.previewSize[0] * w / h
-        return img.Scale(newW, newH, wx.IMAGE_QUALITY_HIGH)
-        
-    def DrawWarningText(self, warning):
-        """!Draw text on preview window"""
-        buffer = wx.EmptyBitmap(*self.previewSize)
-        dc = wx.MemoryDC()
-        dc.SelectObject(buffer)
-        dc.SetBrush(wx.Brush(wx.Color(250, 250, 250)))
-        dc.Clear()
-        extent = dc.GetTextExtent(warning)
-        posX = self.previewSize[0] / 2 - extent[0] / 2
-        posY = self.previewSize[1] / 2 - extent[1] / 2
-        dc.DrawText(warning, posX, posY)
-        self.imagePanel.image['preview'].SetBitmap(buffer)
-        dc.SelectObject(wx.NullBitmap)
-        
-    def DrawBitmap(self, bitmap):
-        """!Draw bitmap, center it if smaller than preview size"""
-        if bitmap.GetWidth() <= self.previewSize[0] and bitmap.GetHeight() <= self.previewSize[1]:
-            buffer = wx.EmptyBitmap(*self.previewSize)
-            dc = wx.MemoryDC()
-            dc.SelectObject(buffer)
-            dc.SetBrush(dc.GetBrush())
-            dc.Clear()
-            posX = self.previewSize[0] / 2 - bitmap.GetWidth() / 2
-            posY = self.previewSize[1] / 2 - bitmap.GetHeight() / 2
-            dc.DrawBitmap(bitmap, posX, posY)
-            self.imagePanel.image['preview'].SetBitmap(buffer)
-            dc.SelectObject(wx.NullBitmap)
-        else:
-            self.imagePanel.image['preview'].SetBitmap(bitmap)
-            
-    def SetSizeInfoLabel(self, image):
-        """!Update image size label"""
-        self.imagePanel.image['sizeInfo'].SetLabel(_("size: %s x %s pts") % (image.GetWidth(), image.GetHeight()))
-        self.imagePanel.image['sizeInfo'].GetContainingSizer().Layout()
-        
-    def ClearPreview(self):
-        """!Clear preview window"""
-        buffer = wx.EmptyBitmap(*self.previewSize)
-        dc = wx.MemoryDC()
-        dc.SelectObject(buffer)
-        dc.SetBrush(wx.WHITE_BRUSH)
-        dc.Clear()
-        mask = wx.Mask(buffer, wx.WHITE)
-        buffer.SetMask(mask)
-        self.imagePanel.image['preview'].SetBitmap(buffer)
-        dc.SelectObject(wx.NullBitmap)
-        
-    def update(self): 
-        # epsfile
-        selected = self.imagePanel.image['list'].GetStringSelection()
-        basePath = self.imagePanel.image['dir'].GetValue()
-        if not selected:
-            gcmd.GMessage(parent = self, message = _("No image selected."))
-            return False
-            
-        self.imageDict['epsfile'] = os.path.join(basePath, selected)
-        
-        #position
-        if self.positionPanel.position['toPaper'].GetValue():
-            self.imageDict['XY'] = True
-            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
-            self.imageDict['unit'] = currUnit
-            if self.positionPanel.position['xCtrl'].GetValue():
-                x = self.positionPanel.position['xCtrl'].GetValue() 
-            else:
-                x = self.imageDict['where'][0]
-
-            if self.positionPanel.position['yCtrl'].GetValue():
-                y = self.positionPanel.position['yCtrl'].GetValue() 
-            else:
-                y = self.imageDict['where'][1]
-
-            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
-            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
-            self.imageDict['where'] = x, y
-            
-        else:
-            self.imageDict['XY'] = False
-            if self.positionPanel.position['eCtrl'].GetValue():
-                e = self.positionPanel.position['eCtrl'].GetValue() 
-            else:
-                self.imageDict['east'] = self.imageDict['east']
-
-            if self.positionPanel.position['nCtrl'].GetValue():
-                n = self.positionPanel.position['nCtrl'].GetValue() 
-            else:
-                self.imageDict['north'] = self.imageDict['north']
-
-            x, y = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.imageDict['east']),
-                                       y = float(self.imageDict['north']), paperToMap = False)
-
-        #rotation
-        rot = self.imagePanel.image['rotate'].GetValue()
-        if rot == 0:
-            self.imageDict['rotate'] = None
-        else:
-            self.imageDict['rotate'] = rot
-        
-        #scale
-        self.imageDict['scale'] = self.imagePanel.image['scale'].GetValue()
-                
-        # scale
-        w, h = self.imageObj.GetImageOrigSize(self.imageDict['epsfile'])
-        if self.imageDict['rotate']:
-            self.imageDict['size'] = BBoxAfterRotation(w, h, self.imageDict['rotate'])
-        else:
-            self.imageDict['size'] = w, h
-            
-        w = self.unitConv.convert(value = self.imageDict['size'][0],
-                                  fromUnit = 'point', toUnit = 'inch')
-        h = self.unitConv.convert(value = self.imageDict['size'][1],
-                                  fromUnit = 'point', toUnit = 'inch')
-                                  
-    
-        self.imageDict['rect'] = wx.Rect2D(x = x, y = y,
-                                       w = w * self.imageDict['scale'],
-                                       h = h * self.imageDict['scale'])
-        
-        if self.id not in self.instruction:
-            image = self._newObject()
-            self.instruction.AddInstruction(image)
-        self.instruction[self.id].SetInstruction(self.imageDict)
-        
-        if self.id not in self.parent.objectId:
-            self.parent.objectId.append(self.id)
-
-        return True
-        
-    def updateDialog(self):
-        """!Update text coordinates, after moving"""
-        # XY coordinates
-        x, y = self.imageDict['where'][:2]
-        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
-        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
-        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
-        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
-        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
-        # EN coordinates
-        e, n = self.imageDict['east'], self.imageDict['north']
-        self.positionPanel.position['eCtrl'].SetValue(str(self.imageDict['east']))
-        self.positionPanel.position['nCtrl'].SetValue(str(self.imageDict['north']))
-        
-        
-class NorthArrowDialog(ImageDialog):
-    def __init__(self, parent, id, settings):
-        ImageDialog.__init__(self, parent = parent, id = id, settings = settings,
-                             imagePanelName = _("North Arrow"))
-        
-        self.objectType = ('northArrow',)
-        self.SetTitle(_("North Arrow settings"))
-    
-    def _newObject(self):
-        return NorthArrow(self.id, self.instruction)
-        
-    def _getImageDirectory(self):
-        gisbase = os.getenv("GISBASE")
-        return os.path.join(gisbase, 'etc', 'paint', 'decorations')
-    
-    def _addConvergence(self, panel, gridBagSizer):
-        convergence = wx.Button(parent = panel, id = wx.ID_ANY,
-                                               label = _("Compute convergence"))
-        gridBagSizer.Add(item = convergence, pos = (1, 2),
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
-        convergence.Bind(wx.EVT_BUTTON, self.OnConvergence)
-        panel.image['convergence'] = convergence
-        
-    def OnConvergence(self, event):
-        ret = RunCommand('g.region', read = True, flags = 'ng')
-        if ret:
-            convergence = float(ret.strip().split('=')[1])
-            if convergence < 0:
-                self.imagePanel.image['rotate'].SetValue(abs(convergence))
-            else:
-                self.imagePanel.image['rotate'].SetValue(360 - convergence)
-            
-        
-def convertRGB(rgb):
-    """!Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color,
-            or named color/r:g:b string to wx.Colour, depending on input""" 
-    # transform a wx.Colour tuple into an r:g:b string    
-    if type(rgb) == wx.Colour:
-        for name, color in grass.named_colors.items(): 
-            if  rgb.Red() == int(color[0] * 255) and\
-                rgb.Green() == int(color[1] * 255) and\
-                rgb.Blue() == int(color[2] * 255):
-                return name
-        return str(rgb.Red()) + ':' + str(rgb.Green()) + ':' + str(rgb.Blue())
-    # transform a GRASS named color or an r:g:b string into a wx.Colour tuple
-    else:
-        color = (grass.parse_color(rgb)[0]*255,
-                 grass.parse_color(rgb)[1]*255,
-                 grass.parse_color(rgb)[2]*255)
-        color = wx.Color(*color)
-        if color.IsOk():
-            return color
-        else:  
-            return None
-        
-def PaperMapCoordinates(map, x, y, paperToMap = True):
-    """!Converts paper (inch) coordinates -> map coordinates"""
-    unitConv = UnitConversion()
-    currRegionDict = grass.region()
-    cornerEasting, cornerNorthing = currRegionDict['w'], currRegionDict['n']
-    xMap = map['rect'][0]
-    yMap = map['rect'][1]
-    widthMap = map['rect'][2] * 0.0254 # to meter
-    heightMap = map['rect'][3] * 0.0254
-    xScale = widthMap / abs(currRegionDict['w'] - currRegionDict['e'])
-    yScale = heightMap / abs(currRegionDict['n'] - currRegionDict['s'])
-    currScale = (xScale + yScale) / 2
- 
-    if not paperToMap:
-        textEasting, textNorthing = x, y
-        eastingDiff = textEasting - cornerEasting 
-        if currRegionDict['w'] > currRegionDict['e']:
-            eastingDiff = - eastingDiff
-        else:
-            eastingDiff = eastingDiff
-
-        northingDiff = textNorthing - cornerNorthing
-        if currRegionDict['n'] > currRegionDict['s']:
-            northingDiff = - northingDiff 
-        else:
-            northingDiff = northingDiff
-
-        xPaper = xMap + unitConv.convert(value = eastingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
-        yPaper = yMap + unitConv.convert(value = northingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
-        return xPaper, yPaper
-    else:
-        if currRegionDict['w'] < currRegionDict['e']:
-            eastingDiff = (x - xMap) 
-        else:
-            eastingDiff = (xMap - x)
-        if currRegionDict['n'] < currRegionDict['s']:
-            northingDiff = (y - yMap) 
-        else:
-            northingDiff = (yMap - y)
-
-        textEasting = cornerEasting + unitConv.convert(value = eastingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
-        textNorthing = cornerNorthing + unitConv.convert(value = northingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
-        return int(textEasting), int(textNorthing)
-        
-def AutoAdjust(self, scaleType,  rect, map = None, mapType = None, region = None):
-    """!Computes map scale, center and map frame rectangle to fit region (scale is not fixed)"""
-    currRegionDict = {}
-    if scaleType == 0 and map:# automatic, region from raster or vector
-        res = ''
-        if mapType == 'raster': 
-            try:
-                res = grass.read_command("g.region", flags = 'gu', rast = map)
-            except grass.ScriptError:
-                pass
-        elif mapType == 'vector':
-            res = grass.read_command("g.region", flags = 'gu', vect = map)
-        currRegionDict = grass.parse_key_val(res, val_type = float)
-    elif scaleType == 1 and region: # saved region
-        res = grass.read_command("g.region", flags = 'gu', region = region)
-        currRegionDict = grass.parse_key_val(res, val_type = float)
-    elif scaleType == 2: # current region
-        env = grass.gisenv()
-        windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
-        try:
-            windFile = open(windFilePath, 'r').read()
-        except IOError:
-            currRegionDict = grass.region()
-        regionDict = grass.parse_key_val(windFile, sep = ':', val_type = float)
-        region = grass.read_command("g.region", flags = 'gu', n = regionDict['north'], s = regionDict['south'],
-                                    e = regionDict['east'], w = regionDict['west'])
-        currRegionDict = grass.parse_key_val(region, val_type = float)
-                                                                
-    else:
-        return None, None, None
-    
-    if not currRegionDict:
-        return None, None, None
-    rX = rect.x
-    rY = rect.y
-    rW = rect.width
-    rH = rect.height
-    if not hasattr(self, 'unitConv'):
-        self.unitConv = UnitConversion(self)
-    toM = 1
-    if projInfo()['proj'] != 'xy':
-        toM = float(projInfo()['meters'])
-
-    mW = self.unitConv.convert(value = (currRegionDict['e'] - currRegionDict['w']) * toM, fromUnit = 'meter', toUnit = 'inch')
-    mH = self.unitConv.convert(value = (currRegionDict['n'] - currRegionDict['s']) * toM, fromUnit = 'meter', toUnit = 'inch')
-    scale = min(rW/mW, rH/mH)
-    
-    if rW/rH > mW/mH:
-        x = rX - (rH*(mW/mH) - rW)/2
-        y = rY
-        rWNew = rH*(mW/mH)
-        rHNew = rH
-    else:
-        x = rX
-        y = rY - (rW*(mH/mW) - rH)/2
-        rHNew = rW*(mH/mW)
-        rWNew = rW
-
-    # center
-    cE = (currRegionDict['w'] + currRegionDict['e'])/2
-    cN = (currRegionDict['n'] + currRegionDict['s'])/2
-    return scale, (cE, cN), wx.Rect2D(x, y, rWNew, rHNew) #inch
-
-def SetResolution(dpi, width, height):
-    """!If resolution is too high, lower it
-    
-    @param dpi max DPI
-    @param width map frame width
-    @param height map frame height
-    """
-    region = grass.region()
-    if region['cols'] > width * dpi or region['rows'] > height * dpi:
-        rows = height * dpi
-        cols = width * dpi
-        RunCommand('g.region', rows = rows, cols = cols)
-               
-def ComputeSetRegion(self, mapDict):
-    """!Computes and sets region from current scale, map center coordinates and map rectangle"""
-
-    if mapDict['scaleType'] == 3: # fixed scale
-        scale = mapDict['scale']
-            
-        if not hasattr(self, 'unitConv'):
-            self.unitConv = UnitConversion(self)
-        
-        fromM = 1
-        if projInfo()['proj'] != 'xy':
-            fromM = float(projInfo()['meters'])
-        rectHalfInch = (mapDict['rect'].width/2, mapDict['rect'].height/2)
-        rectHalfMeter = (self.unitConv.convert(value = rectHalfInch[0], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale,
-                         self.unitConv.convert(value = rectHalfInch[1], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale) 
-        
-        centerE = mapDict['center'][0]
-        centerN = mapDict['center'][1]
-        
-        raster = self.instruction.FindInstructionByType('raster')
-        if raster:
-            rasterId = raster.id 
-        else:
-            rasterId = None
-
-        if rasterId:
-            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
-                       s = floor(centerN - rectHalfMeter[1]),
-                       e = ceil(centerE + rectHalfMeter[0]),
-                       w = floor(centerE - rectHalfMeter[0]),
-                       rast = self.instruction[rasterId]['raster'])
-        else:
-            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
-                       s = floor(centerN - rectHalfMeter[1]),
-                       e = ceil(centerE + rectHalfMeter[0]),
-                       w = floor(centerE - rectHalfMeter[0]))
-                    
-def projInfo():
-    """!Return region projection and map units information,
-    taken from render.py"""
-    
-    projinfo = dict()
-    
-    ret = RunCommand('g.proj', read = True, flags = 'p')
-    
-    if not ret:
-        return projinfo
-    
-    for line in ret.splitlines():
-        if ':' in line:
-            key, val = line.split(':')
-            projinfo[key.strip()] = val.strip()
-        elif "XY location (unprojected)" in line:
-            projinfo['proj'] = 'xy'
-            projinfo['units'] = ''
-            break
-    
-    return projinfo
-
-def GetMapBounds(filename, portrait = True):
-    """!Run ps.map -b to get information about map bounding box
-    
-        @param filename psmap input file
-        @param portrait page orientation"""
-    orient = ''
-    if not portrait:
-        orient = 'r'
-    try:
-        bb = map(float, grass.read_command('ps.map',
-                                           flags = 'b' + orient,
-                                           quiet = True,
-                                           input = filename).strip().split('=')[1].split(','))
-    except (grass.ScriptError, IndexError):
-        GError(message = _("Unable to run `ps.map -b`"))
-        return None
-    return wx.Rect2D(bb[0], bb[3], bb[2] - bb[0], bb[1] - bb[3])
-
-def getRasterType(map):
-    """!Returns type of raster map (CELL, FCELL, DCELL)"""
-    if map is None:
-        map = ''
-    file = grass.find_file(name = map, element = 'cell')
-    if file['file']:
-        rasterType = grass.raster_info(map)['datatype']
-        return rasterType
-    else:
-        return None
-   
-def PilImageToWxImage(pilImage, copyAlpha = True):
-    """!Convert PIL image to wx.Image
-    
-    Based on http://wiki.wxpython.org/WorkingWithImages
-    """
-    hasAlpha = pilImage.mode[-1] == 'A'
-    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.
-        wxImage = wx.EmptyImage( *pilImage.size )
-        pilImageCopyRGBA = pilImage.copy()
-        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
-        pilImageRgbData = pilImageCopyRGB.tostring()
-        wxImage.SetData(pilImageRgbData)
-        wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4])  # Create layer and insert alpha values.
-
-    else :    # The resulting image will not have alpha.
-        wxImage = wx.EmptyImage(*pilImage.size)
-        pilImageCopy = pilImage.copy()
-        pilImageCopyRGB = pilImageCopy.convert('RGB')    # Discard any alpha from the PIL image.
-        pilImageRgbData = pilImageCopyRGB.tostring()
-        wxImage.SetData(pilImageRgbData)
-
-    return wxImage
-
-def BBoxAfterRotation(w, h, angle):
-    """!Compute bounding box or rotated rectangle
-    
-    @param w rectangle width
-    @param h rectangle height
-    @param angle angle (0, 360) in degrees
-    """
-    angleRad = angle / 180. * pi
-    ct = cos(angleRad)
-    st = sin(angleRad)
-    
-    hct = h * ct
-    wct = w * ct
-    hst = h * st
-    wst = w * st
-    y = x = 0
-    
-    if 0 < angle <= 90:
-        y_min = y
-        y_max = y + hct + wst
-        x_min = x - hst
-        x_max = x + wct
-    elif 90 < angle <= 180:
-        y_min = y + hct
-        y_max = y + wst
-        x_min = x - hst + wct
-        x_max = x
-    elif 180 < angle <= 270:
-        y_min = y + wst + hct
-        y_max = y
-        x_min = x + wct
-        x_max = x - hst
-    elif 270 < angle <= 360:
-        y_min = y + wst
-        y_max = y + hct
-        x_min = x
-        x_max = x + wct - hst
-        
-    width = int(ceil(abs(x_max) + abs(x_min)))
-    height = int(ceil(abs(y_max) + abs(y_min)))
-    return width, height

Deleted: grass/trunk/gui/wxpython/gui_modules/render.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/render.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/render.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1425 +0,0 @@
-"""!
- at package render
-
-Rendering map layers and overlays into map composition image.
-
-Classes:
- - Layer
- - MapLayer
- - Overlay
- - Map
-
-(C) 2006-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import glob
-import math
-import copy
-import tempfile
-import stat
-import types
-
-import wx
-from wx.lib.newevent import NewEvent
-
-from grass.script import core as grass
-
-import globalvar
-import utils
-import gcmd
-from debug import Debug as Debug
-from preferences import globalSettings as UserSettings
-
-wxUpdateProgressBar, EVT_UPDATE_PRGBAR = NewEvent()
-
-USE_GPNMCOMP = True
-
-class Layer(object):
-    """!Virtual class which stores information about layers (map layers and
-    overlays) of the map composition.
-    
-    - For map layer use MapLayer class.
-    - For overlays use Overlay class.
-    """
-    def __init__(self, type, cmd, name = None,
-                 active = True, hidden = False, opacity = 1.0):
-        """!Create new instance
-        
-        @todo pass cmd as tuple instead of list
-        
-        @param type layer type ('raster', 'vector', 'overlay', 'command', etc.)
-        @param cmd GRASS command to render layer,
-        given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
-        @param name layer name, e.g. 'elevation at PERMANENT' (for layer tree)
-        @param active layer is active, will be rendered only if True
-        @param hidden layer is hidden, won't be listed in Layer Manager if True
-        @param opacity layer opacity <0;1>
-        """
-        self.type  = type
-        self.name  = name
-        
-        if self.type == 'command':
-            self.cmd = list()
-            for c in cmd:
-                self.cmd.append(utils.CmdToTuple(c))
-        else:
-            self.cmd = utils.CmdToTuple(cmd)
-        
-        self.active  = active
-        self.hidden  = hidden
-        self.opacity = opacity
-        
-        self.force_render = True
-        
-        Debug.msg (3, "Layer.__init__(): type=%s, cmd='%s', name=%s, " \
-                       "active=%d, opacity=%d, hidden=%d" % \
-                       (self.type, self.GetCmd(string = True), self.name, self.active,
-                        self.opacity, self.hidden))
-        
-        # generated file for each layer
-        if USE_GPNMCOMP or self.type == 'overlay':
-            tmpfile = tempfile.mkstemp()[1]
-            self.maskfile = tmpfile + '.pgm'
-            if self.type == 'overlay':
-                self.mapfile  = tmpfile + '.png'
-            else:
-                self.mapfile  = tmpfile + '.ppm'
-            grass.try_remove(tmpfile)
-        else:
-            self.mapfile = self.maskfile = None
-        
-    def __del__(self):
-        Debug.msg (3, "Layer.__del__(): layer=%s, cmd='%s'" %
-                   (self.name, self.GetCmd(string = True)))
-        
-    def Render(self):
-        """!Render layer to image
-        
-        @return rendered image filename
-        @return None on error or if cmdfile is defined
-        """
-        if not self.cmd:
-            return None
-        
-        # ignore in 2D
-        if self.type == '3d-raster':
-            return None
-        
-        Debug.msg (3, "Layer.Render(): type=%s, name=%s" % \
-                       (self.type, self.name))
-        
-        # prepare command for each layer
-        layertypes = ('raster', 'rgb', 'his', 'shaded', 'rastarrow', 'rastnum',
-                      'vector','thememap','themechart',
-                      'grid', 'geodesic', 'rhumb', 'labels',
-                      'command', 'rastleg','maplegend',
-                      'overlay')
-        
-        if self.type not in layertypes:
-            raise gcmd.GException(_("<%(name)s>: layer type <%(type)s> is not supported") % \
-                                      {'type' : self.type, 'name' : self.name})
-        
-        # start monitor
-	if self.mapfile:
-	    os.environ["GRASS_PNGFILE"] = self.mapfile
-        
-        # execute command
-        try:
-            if self.type == 'command':
-                read = False
-                for c in self.cmd:
-                    ret, msg = gcmd.RunCommand(c[0],
-                                          getErrorMsg = True,
-                                          quiet = True,
-                                          **c[1])
-                    if ret != 0:
-                        break
-                    if not read:
-                        os.environ["GRASS_PNG_READ"] = "TRUE"
-                
-                os.environ["GRASS_PNG_READ"] = "FALSE"
-            else:
-                ret, msg = gcmd.RunCommand(self.cmd[0],
-                                           getErrorMsg = True,
-                                           quiet = True,
-                                           **self.cmd[1])
-                
-            if msg:
-                sys.stderr.write(_("Command '%s' failed\n") % self.GetCmd(string = True))
-                sys.stderr.write(_("Details: %s\n") % msg)
-            if ret != 0:
-                raise gcmd.GException()
-        
-        except gcmd.GException:
-            # clean up after problems
-            for f in [self.mapfile, self.maskfile]:
-                if not f:
-                    continue
-                grass.try_remove(f)
-                f = None
-        
-        # stop monitor
-        if self.mapfile and "GRASS_PNGFILE" in os.environ:
-            del os.environ["GRASS_PNGFILE"]
-        
-        self.force_render = False
-        
-        return self.mapfile
-    
-    def GetCmd(self, string = False):
-        """!Get GRASS command as list of string.
-        
-        @param string get command as string if True otherwise as list
-        
-        @return command list/string
-        """
-        if string:
-            if self.type == 'command':
-                scmd = []
-                for c in self.cmd:
-                    scmd.append(utils.GetCmdString(c))
-                
-                return ';'.join(scmd)
-            else:
-                return utils.GetCmdString(self.cmd)
-        else:
-            return self.cmd
-
-    def GetType(self):
-        """!Get map layer type"""
-        return self.type
-    
-    def GetElement(self):
-        """!Get map element type"""
-        if self.type == 'raster':
-            return 'cell'
-        return self.type
-    
-    def GetOpacity(self, float = False):
-        """
-        Get layer opacity level
-        
-        @param float get opacity level in <0,1> otherwise <0,100>
-        
-        @return opacity level
-        """
-        if float:
-            return self.opacity
-        
-        return int (self.opacity * 100)
-
-    def GetName(self, fullyQualified = True):
-        """!Get map layer name
-
-        @param fullyQualified True to return fully qualified name as a
-        string 'name at mapset' otherwise directory { 'name', 'mapset' }
-        is returned
-
-        @return string / directory
-        """
-        if fullyQualified:
-            return self.name
-        else:
-            if '@' in self.name:
-                return { 'name' : self.name.split('@')[0],
-                         'mapset' : self.name.split('@')[1] }
-            else:
-                return { 'name' : self.name,
-                         'mapset' : '' }
-        
-    def IsActive(self):
-        """!Check if layer is activated for rendering"""
-        return self.active
-    
-    def SetType(self, type):
-        """!Set layer type"""
-        if type not in ('raster', '3d-raster', 'vector',
-                        'overlay', 'command',
-                        'shaded', 'rgb', 'his', 'rastarrow', 'rastnum','maplegend',
-                        'thememap', 'themechart', 'grid', 'labels',
-                        'geodesic','rhumb'):
-            raise gcmd.GException(_("Unsupported map layer type '%s'") % type)
-        
-        self.type = type
-
-    def SetName(self, name):
-        """!Set layer name"""
-        self.name = name
-        
-    def SetActive(self, enable = True):
-        """!Active or deactive layer"""
-        self.active = bool(enable)
-
-    def SetHidden(self, enable = False):
-        """!Hide or show map layer in Layer Manager"""
-        self.hidden = bool(enable)
-
-    def SetOpacity(self, value):
-        """!Set opacity value"""
-        if value < 0:
-            value = 0.
-        elif value > 1:
-            value = 1.
-        
-        self.opacity = float(value)
-        
-    def SetCmd(self, cmd):
-        """!Set new command for layer"""
-        if self.type == 'command':
-            self.cmd = []
-            for c in cmd:
-                self.cmd.append(utils.CmdToTuple(c))
-        else:
-            self.cmd  = utils.CmdToTuple(cmd)
-        Debug.msg(3, "Layer.SetCmd(): cmd='%s'" % self.GetCmd(string = True))
-        
-        # for re-rendering
-        self.force_render = True
-        
-class MapLayer(Layer):
-    def __init__(self, type, cmd, name = None,
-                 active = True, hidden = False, opacity = 1.0): 
-        """!Represents map layer in the map canvas
-        
-        @param type layer type ('raster', 'vector', 'command', etc.)
-        @param cmd GRASS command to render layer,
-        given as list, e.g. ['d.rast', 'map=elevation at PERMANENT']
-        @param name layer name, e.g. 'elevation at PERMANENT' (for layer tree) or None
-        @param active layer is active, will be rendered only if True
-        @param hidden layer is hidden, won't be listed in Layer Manager if True
-        @param opacity layer opacity <0;1>
-        """
-        Layer.__init__(self, type, cmd, name,
-                       active, hidden, opacity)
-        
-    def GetMapset(self):
-        """!Get mapset of map layer
-        
-        @return mapset name
-        @return '' on error (no name given)
-        """
-        if not self.name:
-            return ''
-        
-        try:
-            return self.name.split('@')[1]
-        except IndexError:
-            return self.name
-        
-class Overlay(Layer):
-    def __init__(self, id, type, cmd,
-                 active = True, hidden = True, opacity = 1.0):
-        """!Represents overlay displayed in map canvas
-        
-        @param id overlay id (for PseudoDC)
-        @param type overlay type ('barscale', 'legend', etc.)
-        @param cmd GRASS command to render overlay,
-        given as list, e.g. ['d.legend', 'map=elevation at PERMANENT']
-        @param active layer is active, will be rendered only if True
-        @param hidden layer is hidden, won't be listed in Layer Manager if True
-        @param opacity layer opacity <0;1>
-        """
-        Layer.__init__(self, 'overlay', cmd, type,
-                       active, hidden, opacity)
-        
-        self.id = id
-        
-class Map(object):
-    def __init__(self, gisrc = None, cmdfile = None, mapfile = None, envfile = None, monitor = None):
-        """!Map composition (stack of map layers and overlays)
-
-        @param gisrc alternative gisrc (used eg. by georectifier)
-        @param cmdline full path to the cmd file (defined by d.mon)
-        @param mapfile full path to the map file (defined by d.mon)
-        @param envfile full path to the env file (defined by d.mon)
-        @param monitor name of monitor (defined by d.mon)
-        """
-        # region/extent settigns
-        self.wind      = dict() # WIND settings (wind file)
-        self.region    = dict() # region settings (g.region)
-        self.width     = 640    # map width
-        self.height    = 480    # map height
-        
-        # list of layers
-        self.layers    = list()  # stack of available GRASS layer
-        
-        self.overlays  = list()  # stack of available overlays
-        self.ovlookup  = dict()  # lookup dictionary for overlay items and overlays
-        
-        # environment settings
-        self.env   = dict()
-        # path to external gisrc
-        self.gisrc = gisrc
-        
-        self.cmdfile = cmdfile
-        self.envfile = envfile
-        self.monitor = monitor
-        
-        if mapfile:
-            self.mapfileCmd = mapfile
-            self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
-        
-        # generated file for g.pnmcomp output for rendering the map
-        self.mapfile = grass.tempfile(create = False) + '.ppm'
-        
-        # setting some initial env. variables
-        self._initGisEnv() # g.gisenv
-        self.GetWindow()
-        # GRASS environment variable (for rendering)
-        env = {"GRASS_BACKGROUNDCOLOR" : "FFFFFF",
-               "GRASS_COMPRESSION"     : "0",
-               "GRASS_TRUECOLOR"       : "TRUE",
-               "GRASS_TRANSPARENT"     : "TRUE",
-               "GRASS_PNG_READ"        : "FALSE",
-               }
-        
-        self._writeEnvFile(env)
-        self._writeEnvFile({"GRASS_PNG_READ" : "TRUE"})
-        for k, v in env.iteritems():
-            os.environ[k] = v
-        
-        # projection info
-        self.projinfo = self._projInfo()
-        
-    def _runCommand(self, cmd, **kwargs):
-        """!Run command in environment defined by self.gisrc if
-        defined"""
-        # use external gisrc if defined
-        gisrc_orig = os.getenv("GISRC")
-        if self.gisrc:
-            os.environ["GISRC"] = self.gisrc
-        
-        ret = cmd(**kwargs)
-        
-        # back to original gisrc
-        if self.gisrc:
-            os.environ["GISRC"] = gisrc_orig
-        
-        return ret
-    
-    def _initGisEnv(self):
-        """!Stores GRASS variables (g.gisenv) to self.env variable
-        """
-        if not os.getenv("GISBASE"):
-            sys.exit(_("GISBASE not set. You must be in GRASS GIS to run this program."))
-        
-        self.env = self._runCommand(grass.gisenv)
-            
-    def GetProjInfo(self):
-        """!Get projection info"""
-        return self.projinfo
-    
-    def _projInfo(self):
-        """!Return region projection and map units information
-        """
-        projinfo = dict()
-        if not grass.find_program('g.proj', ['--help']):
-            sys.exit(_("GRASS module '%s' not found. Unable to start map "
-                       "display window.") % 'g.proj')
-        
-        ret = self._runCommand(gcmd.RunCommand, prog = 'g.proj',
-                               read = True, flags = 'p')
-        
-        if not ret:
-            return projinfo
-        
-        for line in ret.splitlines():
-            if ':' in line:
-                key, val = map(lambda x: x.strip(), line.split(':'))
-                if key in ['units']:
-                    val = val.lower()
-                projinfo[key] = val
-            elif "XY location (unprojected)" in line:
-                projinfo['proj'] = 'xy'
-                projinfo['units'] = ''
-                break
-        
-        return projinfo
-    
-    def GetWindow(self):
-        """!Read WIND file and set up self.wind dictionary"""
-        # FIXME: duplicated region WIND == g.region (at least some values)
-        filename = os.path.join (self.env['GISDBASE'],
-                                 self.env['LOCATION_NAME'],
-                                 self.env['MAPSET'],
-                                 "WIND")
-        try:
-            windfile = open (filename, "r")
-        except IOError, e:
-            sys.exit(_("Error: Unable to open '%(file)s'. Reason: %(ret)s. wxGUI exited.\n") % \
-                         { 'file' : filename, 'ret' : e})
-        
-        for line in windfile.readlines():
-            line = line.strip()
-            key, value = line.split(":", 1)
-            self.wind[key.strip()] = value.strip()
-        
-        windfile.close()
-        
-        return self.wind
-        
-    def AdjustRegion(self):
-        """!Adjusts display resolution to match monitor size in
-        pixels. Maintains constant display resolution, not related to
-        computational region. Do NOT use the display resolution to set
-        computational resolution. Set computational resolution through
-        g.region.
-        """
-        mapwidth    = abs(self.region["e"] - self.region["w"])
-        mapheight   = abs(self.region['n'] - self.region['s'])
-        
-        self.region["nsres"] =  mapheight / self.height
-        self.region["ewres"] =  mapwidth  / self.width
-        self.region['rows']  = round(mapheight / self.region["nsres"])
-        self.region['cols']  = round(mapwidth / self.region["ewres"])
-        self.region['cells'] = self.region['rows'] * self.region['cols']
-        
-        Debug.msg (3, "Map.AdjustRegion(): %s" % self.region)
-        
-        return self.region
-
-    def AlignResolution(self):
-        """!Sets display extents to even multiple of current
-        resolution defined in WIND file from SW corner. This must be
-        done manually as using the -a flag can produce incorrect
-        extents.
-        """
-        # new values to use for saving to region file
-        new = {}
-        n = s = e = w = 0.0
-        nwres = ewres = 0.0
-        
-        # Get current values for region and display
-        reg = self.GetRegion()
-        nsres = reg['nsres']
-        ewres = reg['ewres']
-        
-        n = float(self.region['n'])
-        s = float(self.region['s'])
-        e = float(self.region['e'])
-        w = float(self.region['w'])
-        
-        # Calculate rows, columns, and extents
-        new['rows'] = math.fabs(round((n-s)/nsres))
-        new['cols'] = math.fabs(round((e-w)/ewres))
-        
-        # Calculate new extents
-        new['s'] = nsres * round(s / nsres)
-        new['w'] = ewres * round(w / ewres)
-        new['n'] = new['s'] + (new['rows'] * nsres)
-        new['e'] = new['w'] + (new['cols'] * ewres)
-        
-        return new
-
-    def AlignExtentFromDisplay(self):
-        """!Align region extent based on display size from center
-        point"""
-        # calculate new bounding box based on center of display
-        if self.region["ewres"] > self.region["nsres"]:
-            res = self.region["ewres"]
-        else:
-            res = self.region["nsres"]
-        
-        Debug.msg(3, "Map.AlignExtentFromDisplay(): width=%d, height=%d, res=%f, center=%f,%f" % \
-                      (self.width, self.height, res, self.region['center_easting'],
-                       self.region['center_northing']))
-            
-        ew = (self.width / 2) * res
-        ns = (self.height / 2) * res
-        
-        self.region['n'] = self.region['center_northing'] + ns
-        self.region['s'] = self.region['center_northing'] - ns
-        self.region['e'] = self.region['center_easting'] + ew
-        self.region['w'] = self.region['center_easting'] - ew
-        
-        # LL locations
-        if self.projinfo['proj'] == 'll':
-            self.region['n'] = min(self.region['n'], 90.0)
-            self.region['s'] = max(self.region['s'], -90.0)
-        
-    def _writeEnvFile(self, data):
-        """!Write display-related variable to the file (used for
-        standalone app)
-        """
-        if not self.envfile:
-            return
-        
-        try:
-            fd = open(self.envfile, "r")
-            for line in fd.readlines():
-                key, value = line.split('=')
-                if key not in data.keys():
-                    data[key] = value
-            fd.close()
-            
-            fd = open(self.envfile, "w")
-            for k, v in data.iteritems():
-                fd.write('%s=%s\n' % (k.strip(), str(v).strip()))
-        except IOError, e:
-            grass.warning(_("Unable to open file '%(file)s' for writting. Details: %(det)s") % \
-                              { 'cmd' : self.envfile, 'det' : e })
-            return
-        
-        fd.close()
-        
-    def ChangeMapSize(self, (width, height)):
-        """!Change size of rendered map.
-        
-        @param width,height map size
-        """
-        try:
-            self.width  = int(width)
-            self.height = int(height)
-        except:
-            self.width  = 640
-            self.height = 480
-
-        Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
-                      (self.width, self.height))
-        self._writeEnvFile({'GRASS_WIDTH' : self.width,
-                            'GRASS_HEIGHT' : self.height})
-        
-    def GetRegion(self, rast = [], zoom = False, vect = [], regionName = None,
-                  n = None, s = None, e = None, w = None, default = False,
-                  update = False):
-        """!Get region settings (g.region -upgc)
-        
-        Optionally extent, raster or vector map layer can be given.
-        
-        @param rast list of raster maps
-        @param zoom zoom to raster map (ignore NULLs)
-        @param vect list of vector maps
-        @param regionName  named region or None
-        @param n,s,e,w force extent
-        @param default force default region settings
-        @param update if True update current display region settings
-        
-        @return region settings as directory, e.g. {
-        'n':'4928010', 's':'4913700', 'w':'589980',...}
-        
-        @see GetCurrentRegion()
-        """
-        region = {}
-        
-        tmpreg = os.getenv("GRASS_REGION")
-        if tmpreg:
-            del os.environ["GRASS_REGION"]
-        
-        # use external gisrc if defined
-        gisrc_orig = os.getenv("GISRC")
-        if self.gisrc:
-            os.environ["GISRC"] = self.gisrc
-        
-        # do not update & shell style output
-        cmd = {}
-        cmd['flags'] = 'ugpc'
-        
-        if default:
-            cmd['flags'] += 'd'
-        
-        if regionName:
-            cmd['region'] = regionName
-        
-        if n:
-            cmd['n'] = n
-        if s:
-            cmd['s'] = s
-        if e:
-            cmd['e'] = e
-        if w:
-            cmd['w'] = w
-        
-        if rast:
-            if zoom:
-                cmd['zoom'] = rast[0]
-            else:
-                cmd['rast'] = ','.join(rast)
-        
-        if vect:
-            cmd['vect'] = ','.join(vect)
-        
-        ret, reg, msg = gcmd.RunCommand('g.region',
-                                        read = True,
-                                        getErrorMsg = True,
-                                        **cmd)
-        
-        if ret != 0:
-            if rast:
-                message = _("Unable to zoom to raster map <%s>.") % rast[0] + \
-                    "\n\n" + _("Details:") + " %s" % msg
-            elif vect:
-                message = _("Unable to zoom to vector map <%s>.") % vect[0] + \
-                    "\n\n" + _("Details:") + " %s" % msg
-            else:
-                message = _("Unable to get current geographic extent. "
-                            "Force quiting wxGUI. Please manually run g.region to "
-                            "fix the problem.")
-            gcmd.GError(message)
-            return self.region
-        
-        for r in reg.splitlines():
-            key, val = r.split("=", 1)
-            try:
-                region[key] = float(val)
-            except ValueError:
-                region[key] = val
-        
-        # back to original gisrc
-        if self.gisrc:
-            os.environ["GISRC"] = gisrc_orig
-        
-        # restore region
-        if tmpreg:
-            os.environ["GRASS_REGION"] = tmpreg
-        
-        Debug.msg (3, "Map.GetRegion(): %s" % region)
-        
-        if update:
-            self.region = region
-        
-        return region
-
-    def GetCurrentRegion(self):
-        """!Get current display region settings
-        
-        @see GetRegion()
-        """
-        return self.region
-
-    def SetRegion(self, windres = False):
-        """!Render string for GRASS_REGION env. variable, so that the
-        images will be rendered from desired zoom level.
-        
-        @param windres uses resolution from WIND file rather than
-        display (for modules that require set resolution like
-        d.rast.num)
-
-        @return String usable for GRASS_REGION variable or None
-        """
-        grass_region = ""
-        
-        if windres:
-            compRegion = self.GetRegion()
-            region = copy.copy(self.region)
-            for key in ('nsres', 'ewres', 'cells'):
-                region[key] = compRegion[key]
-        else:
-            # adjust region settings to match monitor
-            region = self.AdjustRegion()
-        
-        # read values from wind file
-        try:
-            for key in self.wind.keys():
-                if key == 'north':
-                    grass_region += "north: %s; " % \
-                        (region['n'])
-                    continue
-                elif key == "south":
-                    grass_region += "south: %s; " % \
-                        (region['s'])
-                    continue
-                elif key == "east":
-                    grass_region += "east: %s; " % \
-                        (region['e'])
-                    continue
-                elif key == "west":
-                    grass_region += "west: %s; " % \
-                        (region['w'])
-                    continue
-                elif key == "e-w resol":
-                    grass_region += "e-w resol: %f; " % \
-                        (region['ewres'])
-                    continue
-                elif key == "n-s resol":
-                    grass_region += "n-s resol: %f; " % \
-                        (region['nsres'])
-                    continue
-                elif key == "cols":
-                    if windres:
-                        continue
-                    grass_region += 'cols: %d; ' % \
-                        region['cols']
-                    continue
-                elif key == "rows":
-                    if windres:
-                        continue
-                    grass_region += 'rows: %d; ' % \
-                        region['rows']
-                    continue
-                else:
-                    grass_region += key + ": "  + self.wind[key] + "; "
-            
-            Debug.msg (3, "Map.SetRegion(): %s" % grass_region)
-            
-            return grass_region
-        
-        except:
-            return None
-        
-    def GetListOfLayers(self, l_type = None, l_mapset = None, l_name = None,
-                        l_active = None, l_hidden = None):
-        """!Returns list of layers of selected properties or list of
-        all layers.
-
-        @param l_type layer type, e.g. raster/vector/wms/overlay (value or tuple of values)
-        @param l_mapset all layers from given mapset (only for maplayers)
-        @param l_name all layers with given name
-        @param l_active only layers with 'active' attribute set to True or False
-        @param l_hidden only layers with 'hidden' attribute set to True or False
-        
-        @return list of selected layers
-        """
-        selected = []
-        
-        if type(l_type) == types.StringType:
-            one_type = True
-        else:
-            one_type = False
-        
-        if one_type and l_type == 'overlay':
-            llist = self.overlays
-        else:
-            llist = self.layers
-        
-        # ["raster", "vector", "wms", ... ]
-        for layer in llist:
-            # specified type only
-            if l_type != None:
-                if one_type and layer.type != l_type:
-                    continue
-                elif not one_type and layer.type not in l_type:
-                    continue
-            
-            # mapset
-            if (l_mapset != None and l_type != 'overlay') and \
-                    layer.GetMapset() != l_mapset:
-                continue
-            
-            # name
-            if l_name != None and layer.name != l_name:
-                continue
-            
-            # hidden and active layers
-            if l_active != None and \
-                   l_hidden != None:
-                if layer.active == l_active and \
-                       layer.hidden == l_hidden:
-                    selected.append(layer)
-            
-            # active layers
-            elif l_active != None:
-                if layer.active == l_active:
-                    selected.append(layer)
-            
-            # hidden layers
-            elif l_hidden != None:
-                if layer.hidden == l_hidden:
-                    selected.append(layer)
-            
-            # all layers
-            else:
-                selected.append(layer)
-        
-        Debug.msg (3, "Map.GetListOfLayers(): numberof=%d" % len(selected))
-        
-        return selected
-
-    def _renderLayers(self, force = False, mapWindow = None, overlaysOnly = False):
-        maps = list()
-        masks = list()
-        opacities = list()
-        # render map layers
-        ilayer = 1
-        if overlaysOnly:
-            layers = self.overlays
-        else:
-            layers = self.layers + self.overlays
-        
-        for layer in layers:
-            # skip non-active map layers
-            if not layer or not layer.active:
-                continue
-            
-            # render
-            if force or layer.force_render:
-                if not layer.Render():
-                    continue
-            
-            if mapWindow:
-                # update progress bar
-                ### wx.SafeYield(mapWindow)
-                event = wxUpdateProgressBar(value = ilayer)
-                wx.PostEvent(mapWindow, event)
-            
-            # add image to compositing list
-            if layer.type != "overlay":
-                maps.append(layer.mapfile)
-                masks.append(layer.maskfile)
-                opacities.append(str(layer.opacity))
-            
-            Debug.msg(3, "Map.Render() type=%s, layer=%s " % (layer.type, layer.name))
-            ilayer += 1
-        
-        return maps, masks, opacities
-    
-    def GetLayersFromCmdFile(self):
-        """!Get list of map layers from cmdfile
-        """
-        if not self.cmdfile:
-            return
-        
-        nlayers = 0
-        try:
-            fd = open(self.cmdfile, 'r')
-            for line in fd.readlines():
-                cmd = utils.split(line.strip())
-                ltype = None
-                if cmd[0] == 'd.rast':
-                    ltype = 'raster'
-                elif cmd[0] == 'd.vect':
-                    ltype = 'vector'
-                
-                name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
-                                                 layerType = ltype)[0]
-                
-                self.AddLayer(type = ltype, command = cmd, l_active = False, name = name)
-                nlayers += 1
-        except IOError, e:
-            grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
-                              { 'cmd' : self.cmdfile, 'det' : e })
-            return
-        
-        fd.close()
-
-        Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
-        Debug.msg(1, "                            nlayers=%d" % nlayers)
-                
-    def _parseCmdFile(self):
-        """!Parse cmd file for standalone application
-        """
-        nlayers = 0
-        try:
-            fd = open(self.cmdfile, 'r')
-            grass.try_remove(self.mapfile)
-            cmdLines = fd.readlines()
-            gcmd.RunCommand('g.gisenv',
-                            set = 'MONITOR_%s_CMDFILE=' % self.monitor)
-
-            for cmd in cmdLines:
-                cmdStr = utils.split(cmd.strip())
-                cmd = utils.CmdToTuple(cmdStr)
-                gcmd.RunCommand(cmd[0], **cmd[1])
-                nlayers += 1
-            
-            gcmd.RunCommand('g.gisenv',
-                            set = 'MONITOR_%s_CMDFILE=%s' % (self.monitor, self.cmdfile))
-        except IOError, e:
-            grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
-                              { 'cmd' : self.cmdfile, 'det' : e })
-            return
-        
-        fd.close()
-
-        Debug.msg(1, "Map.__parseCmdFile(): cmdfile=%s" % self.cmdfile)
-        Debug.msg(1, "                      nlayers=%d" % nlayers)
-        
-        return nlayers
-
-    def _renderCmdFile(self, force, windres):
-        if not force:
-            return ([self.mapfileCmd],
-                    [self.maskfileCmd],
-                    ['1.0'])
-        
-        region = os.environ["GRASS_REGION"] = self.SetRegion(windres)
-        self._writeEnvFile({'GRASS_REGION' : region})
-        currMon = grass.gisenv()['MONITOR']
-        if currMon != self.monitor:
-            gcmd.RunCommand('g.gisenv',
-                            set = 'MONITOR=%s' % self.monitor)
-        
-        grass.try_remove(self.mapfileCmd) # GRASS_PNG_READ is TRUE
-        
-        nlayers = self._parseCmdFile()
-        if self.overlays:
-            gcmd.RunCommand('g.gisenv',
-                            unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
-            driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
-            if driver == 'png':
-                os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
-            else:
-                os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
-            self._renderLayers(overlaysOnly = True)
-            del os.environ["GRASS_RENDER_IMMEDIATE"]
-            gcmd.RunCommand('g.gisenv',
-                            set = 'MONITOR=%s' % currMon)
-        
-        if currMon != self.monitor:
-            gcmd.RunCommand('g.gisenv',
-                            set = 'MONITOR=%s' % currMon)
-            
-        if nlayers > 0:
-            return ([self.mapfileCmd],
-                    [self.maskfileCmd],
-                    ['1.0'])
-        else:
-            return ([], [], [])
-    
-    def Render(self, force = False, mapWindow = None, windres = False):
-        """!Creates final image composite
-        
-        This function can conditionaly use high-level tools, which
-        should be avaliable in wxPython library
-        
-        @param force force rendering
-        @param reference for MapFrame instance (for progress bar)
-        @param windres use region resolution (True) otherwise display resolution
-        
-        @return name of file with rendered image or None
-        """
-        wx.BeginBusyCursor()
-        # use external gisrc if defined
-        gisrc_orig = os.getenv("GISRC")
-        if self.gisrc:
-            os.environ["GISRC"] = self.gisrc
-        
-        tmp_region = os.getenv("GRASS_REGION")
-        os.environ["GRASS_REGION"] = self.SetRegion(windres)
-        os.environ["GRASS_WIDTH"]  = str(self.width)
-        os.environ["GRASS_HEIGHT"] = str(self.height)
-        driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
-        if driver == 'png':
-            os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
-        else:
-            os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
-        
-        if self.cmdfile:
-            maps, masks, opacities = self._renderCmdFile(force, windres)
-        else:
-            maps, masks, opacities = self._renderLayers(force, mapWindow)
-        
-        # ugly hack for MSYS
-        if sys.platform != 'win32':
-            mapstr = ",".join(maps)
-            maskstr = ",".join(masks)
-            mapoutstr = self.mapfile
-        else:
-            mapstr = ""
-            for item in maps:
-                mapstr += item.replace('\\', '/')		
-            mapstr = mapstr.rstrip(',')
-            maskstr = ""
-            for item in masks:
-                maskstr += item.replace('\\', '/')
-            maskstr = maskstr.rstrip(',')
-            mapoutstr = self.mapfile.replace('\\', '/')
-            
-        # run g.pngcomp to get composite image
-        bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
-                                                     subkey = 'color')))
-        
-        if maps:
-            ret, msg = gcmd.RunCommand('g.pnmcomp',
-                                       getErrorMsg = True,
-                                       overwrite = True,
-                                       input = '%s' % ",".join(maps),
-                                       mask = '%s' % ",".join(masks),
-                                       opacity = '%s' % ",".join(opacities),
-                                       bgcolor = bgcolor,
-                                       width = self.width,
-                                       height = self.height,
-                                       output = self.mapfile)
-            
-            if ret != 0:
-                print >> sys.stderr, _("ERROR: Rendering failed. Details: %s") % msg
-                wx.EndBusyCursor()
-                return None
-        
-        Debug.msg (3, "Map.Render() force=%s file=%s" % (force, self.mapfile))
-        
-        # back to original region
-        if tmp_region:
-            os.environ["GRASS_REGION"] = tmp_region
-        else:
-            del os.environ["GRASS_REGION"]
-        
-        # back to original gisrc
-        if self.gisrc:
-            os.environ["GISRC"] = gisrc_orig
-        
-        wx.EndBusyCursor()
-        if not maps:
-            return None
-        
-        return self.mapfile
-
-    def AddLayer(self, type, command, name = None,
-                 l_active = True, l_hidden = False, l_opacity = 1.0, l_render = False,
-                 pos = -1):
-        """!Adds generic map layer to list of layers
-        
-        @param type layer type ('raster', 'vector', etc.)
-        @param command  GRASS command given as list
-        @param name layer name
-        @param l_active layer render only if True
-        @param l_hidden layer not displayed in layer tree if True
-        @param l_opacity opacity level range from 0(transparent) - 1(not transparent)
-        @param l_render render an image if True
-        @param pos position in layer list (-1 for append)
-        
-        @return new layer on success
-        @return None on failure
-        """
-        wx.BeginBusyCursor()
-        # l_opacity must be <0;1>
-        if l_opacity < 0:
-            l_opacity = 0
-        elif l_opacity > 1:
-            l_opacity = 1
-        layer = MapLayer(type = type, name = name, cmd = command,
-                         active = l_active, hidden = l_hidden, opacity = l_opacity)
-        
-        # add maplayer to the list of layers
-        if pos > -1:
-            self.layers.insert(pos, layer)
-        else:
-            self.layers.append(layer)
-        
-        Debug.msg (3, "Map.AddLayer(): layer=%s" % layer.name)
-        if l_render:
-            if not layer.Render():
-                raise gcmd.GException(_("Unable to render map layer <%s>.") % name)
-        
-        wx.EndBusyCursor()
-        
-        return layer
-
-    def DeleteAllLayers(self, overlay = False):
-        """!Delete all layers 
-
-        @param overlay True to delete also overlayes
-        """
-        self.layers = []
-        if overlay:
-            self.overlays = []
-        
-    def DeleteLayer(self, layer, overlay = False):
-        """!Removes layer from list of layers
-        
-        @param layer layer instance in layer tree
-        @param overlay delete overlay (use self.DeleteOverlay() instead)
-
-        @return removed layer on success or None
-        """
-        Debug.msg (3, "Map.DeleteLayer(): name=%s" % layer.name)
-        
-        if overlay:
-            list = self.overlays
-        else:
-            list = self.layers
-        
-        if layer in list:
-            if layer.mapfile:
-                base = os.path.split(layer.mapfile)[0]
-                mapfile = os.path.split(layer.mapfile)[1]
-                tempbase = mapfile.split('.')[0]
-                if base == '' or tempbase == '':
-                    return None
-                basefile = os.path.join(base, tempbase) + r'.*'
-                for f in glob.glob(basefile):
-                    os.remove(f)
-            list.remove(layer)
-            
-            return layer
-        
-        return None
-
-    def ReorderLayers(self, layerList):
-        """!Reorder list to match layer tree
-        
-        @param layerList list of layers
-        """
-        self.layers = layerList
-        
-        layerNameList = ""
-        for layer in self.layers:
-            if layer.name:
-                layerNameList += layer.name + ','
-        Debug.msg (4, "Map.ReoderLayers(): layers=%s" % \
-                   (layerNameList))
-        
-    def ChangeLayer(self, layer, render = False, **kargs):
-        """!Change map layer properties
-
-        @param layer map layer instance
-        @param type layer type ('raster', 'vector', etc.)
-        @param command  GRASS command given as list
-        @param name layer name
-        @param active layer render only if True
-        @param hidden layer not displayed in layer tree if True
-        @param opacity opacity level range from 0(transparent) - 1(not transparent)
-        @param render render an image if True
-        """
-        Debug.msg (3, "Map.ChangeLayer(): layer=%s" % layer.name)
-        
-        if 'type' in kargs:
-            layer.SetType(kargs['type']) # check type
-        
-        if 'command' in kargs:
-            layer.SetCmd(kargs['command'])
-        
-        if 'name' in kargs:
-            layer.SetName(kargs['name'])
-        
-        if 'active' in kargs:
-            layer.SetActive(kargs['active'])
-        
-        if 'hidden' in kargs:
-            layer.SetHidden(kargs['hidden'])
-        
-        if 'opacity' in kargs:
-            layer.SetOpacity(kargs['opacity'])
-        
-        if render and not layer.Render():
-            raise gcmd.GException(_("Unable to render map layer <%s>.") % 
-                                  name)
-        
-        return layer
-
-    def ChangeOpacity(self, layer, l_opacity):
-        """!Changes opacity value of map layer
-
-        @param layer layer instance in layer tree
-        @param l_opacity opacity level <0;1>
-        """
-        # l_opacity must be <0;1>
-        if l_opacity < 0: l_opacity = 0
-        elif l_opacity > 1: l_opacity = 1
-        
-        layer.opacity = l_opacity
-        Debug.msg (3, "Map.ChangeOpacity(): layer=%s, opacity=%f" % \
-                   (layer.name, layer.opacity))
-
-    def ChangeLayerActive(self, layer, active):
-        """!Enable or disable map layer
-        
-        @param layer layer instance in layer tree
-        @param active to be rendered (True)
-        """
-        layer.active = active
-        
-        Debug.msg (3, "Map.ChangeLayerActive(): name='%s' -> active=%d" % \
-                   (layer.name, layer.active))
-
-    def ChangeLayerName (self, layer, name):
-        """!Change name of the layer
-        
-        @param layer layer instance in layer tree
-        @param name  layer name to set up
-        """
-        Debug.msg (3, "Map.ChangeLayerName(): from=%s to=%s" % \
-                   (layer.name, name))
-        layer.name =  name
-
-    def RemoveLayer(self, name = None, id = None):
-        """!Removes layer from layer list
-        
-        Layer is defined by name at mapset or id.
-        
-        @param name layer name (must be unique)
-        @param id layer index in layer list
-
-        @return removed layer on success
-        @return None on failure
-        """
-        # delete by name
-        if name:
-            retlayer = None
-            for layer in self.layers:
-                if layer.name == name:
-                    retlayer = layer
-                    os.remove(layer.mapfile)
-                    os.remove(layer.maskfile)
-                    self.layers.remove(layer)
-                    return layer
-        # del by id
-        elif id != None:
-            return self.layers.pop(id)
-        
-        return None
-
-    def GetLayerIndex(self, layer, overlay = False):
-        """!Get index of layer in layer list.
-        
-        @param layer layer instace in layer tree
-        @param overlay use list of overlays instead
-        
-        @return layer index
-        @return -1 if layer not found
-        """
-        if overlay:
-            list = self.overlay
-        else:
-            list = self.layers
-            
-        if layer in list:
-            return list.index(layer)
-        
-        return -1
-
-    def AddOverlay(self, id, type, command,
-                   l_active = True, l_hidden = True, l_opacity = 1.0, l_render = False):
-        """!Adds overlay (grid, barscale, legend, etc.) to list of
-        overlays
-        
-        @param id overlay id (PseudoDC)
-        @param type overlay type (barscale, legend)
-        @param command GRASS command to render overlay
-        @param l_active overlay activated (True) or disabled (False)
-        @param l_hidden overlay is not shown in layer tree (if True)
-        @param l_render render an image (if True)
-        
-        @return new layer on success
-        @retutn None on failure
-        """
-        Debug.msg (2, "Map.AddOverlay(): cmd=%s, render=%d" % (command, l_render))
-        overlay = Overlay(id = id, type = type, cmd = command,
-                          active = l_active, hidden = l_hidden, opacity = l_opacity)
-        
-        # add maplayer to the list of layers
-        self.overlays.append(overlay)
-        
-        if l_render and command != '' and not overlay.Render():
-            raise gcmd.GException(_("Unable render overlay <%s>.") % 
-                                  name)
-        
-        return self.overlays[-1]
-
-    def ChangeOverlay(self, id, render = False, **kargs):
-        """!Change overlay properities
-        
-        Add new overlay if overlay with 'id' doesn't exist.
-        
-        @param id overlay id (PseudoDC)
-        @param type overlay type (barscale, legend)
-        @param command GRASS command to render overlay
-        @param l_active overlay activated (True) or disabled (False)
-        @param l_hidden overlay is not shown in layer tree (if True)
-        @param l_render render an image (if True)
-        
-        @return new layer on success
-        """
-        overlay = self.GetOverlay(id, list = False)
-        if  overlay is None:
-            overlay = Overlay(id, type = None, cmd = None)
-        
-        if 'type' in kargs:
-            overlay.SetName(kargs['type']) # type -> overlay
-        
-        if 'command' in kargs:
-            overlay.SetCmd(kargs['command'])
-        
-        if 'active' in kargs:
-            overlay.SetActive(kargs['active'])
-        
-        if 'hidden' in kargs:
-            overlay.SetHidden(kargs['hidden'])
-        
-        if 'opacity' in kargs:
-            overlay.SetOpacity(kargs['opacity'])
-        
-        if render and overlay.GetCmd() != [] and not overlay.Render():
-            raise gcmd.GException(_("Unable render overlay <%s>") % 
-                                  name)
-        
-        return overlay
-
-    def GetOverlay(self, id, list = False):
-        """!Return overlay(s) with 'id'
-        
-        @param id overlay id
-        @param list return list of overlays of True
-        otherwise suppose 'id' to be unique
-        
-        @return list of overlays (list=True)
-        @return overlay (list=False)
-        @retur None (list=False) if no overlay or more overlays found
-        """
-        ovl = []
-        for overlay in self.overlays:
-            if overlay.id == id:
-                ovl.append(overlay)
-                
-        if not list:
-            if len(ovl) != 1:
-                return None
-            else:
-                return ovl[0]
-        
-        return ovl
-
-    def DeleteOverlay(self, overlay):
-        """!Delete overlay
-        
-        @param overlay overlay layer
-        
-        @return removed overlay on success or None
-        """
-        return self.DeleteLayer(overlay, overlay = True)
-
-    def _clean(self, llist):
-        for layer in llist:
-            if layer.maskfile:
-                grass.try_remove(layer.maskfile)
-            if layer.mapfile:
-                grass.try_remove(layer.mapfile)
-            llist.remove(layer)
-        
-    def Clean(self):
-        """!Clean layer stack - go trough all layers and remove them
-        from layer list.
-
-        Removes also mapfile and maskfile.
-        """
-        self._clean(self.layers)
-        self._clean(self.overlays)
-        
-    def ReverseListOfLayers(self):
-        """!Reverse list of layers"""
-        return self.layers.reverse()
-
-    def RenderOverlays(self, force):
-        """!Render overlays only (for nviz)"""
-        for layer in self.overlays:
-            if force or layer.force_render:
-                layer.Render()
-                
-if __name__ == "__main__":
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-    
-    Map = Map()
-    Map.GetRegion(update = True)
-    
-    Map.AddLayer(type = "raster",
-                 name = "elevation",
-                 command = ["d.rast", "map=elevation at PERMANENT"],
-                 l_opacity = .7)
-    
-    Map.AddLayer(type = "vector",
-                 name = "roadsmajor",
-                 command = ["d.vect", "map=roadsmajor at PERMANENT", "color=red", "width=3", "type=line"])
-    
-    image = Map.Render(force = True)
-    
-    if image:
-        grass.call(["display", image])

Deleted: grass/trunk/gui/wxpython/gui_modules/sqlbuilder.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/sqlbuilder.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/sqlbuilder.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,461 +0,0 @@
-"""!
- at package sqlbuilder.py
-
- at brief GRASS SQL Builder
-
-Classes:
- - SQLFrame
-
-Usage:
- at code
-python sqlbuilder.py vector_map
- at endcode
-
-(C) 2007-2009, 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Jachym Cepicky <jachym.cepicky gmail.com> (original author)
- at author Martin Landa <landa.martin gmail.com>
- at author Hamish Bowman <hamish_b yahoo com>
-"""
-
-import os
-import sys
-import time
-
-import globalvar
-import wx
-
-import grass.script as grass
-
-import gcmd
-import dbm_base
-
-class SQLFrame(wx.Frame):
-    """!SQL Frame class"""
-    def __init__(self, parent, title, vectmap, id = wx.ID_ANY,
-                 layer = 1, qtype = "select", evtheader = None):
-        
-        wx.Frame.__init__(self, parent, id, title)
-        
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'),
-                             wx.BITMAP_TYPE_ICO))
-        
-        self.parent = parent
-        self.evtHeader = evtheader
-
-        #
-        # variables
-        #
-        self.vectmap = vectmap # fullname
-        if not "@" in self.vectmap:
-            self.vectmap = grass.find_file(self.vectmap, element = 'vector')['fullname']
-        self.mapname, self.mapset = self.vectmap.split("@", 1)
-        
-        # db info
-        self.layer = layer
-        self.dbInfo = dbm_base.VectorDBInfo(self.vectmap)
-        self.tablename = self.dbInfo.GetTable(self.layer)
-        self.driver, self.database = self.dbInfo.GetDbSettings(self.layer)
-        
-        self.qtype = qtype      # type of query: SELECT, UPDATE, DELETE, ...
-        self.colvalues = []     # array with unique values in selected column
-
-        # set dialog title
-        self.SetTitle(_("GRASS SQL Builder (%(type)s): vector map <%(map)s>") % \
-                          { 'type' : self.qtype.upper(), 'map' : self.vectmap })
-        
-        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-
-        # statusbar
-        self.statusbar = self.CreateStatusBar(number=1)
-        self.statusbar.SetStatusText(_("SQL statement not verified"), 0)
-       
-        self._doLayout()
-
-    def _doLayout(self):
-        """!Do dialog layout"""
-      
-        pagesizer = wx.BoxSizer(wx.VERTICAL)
-
-        
-        # dbInfo
-        databasebox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                   label = " %s " % _("Database connection"))
-        databaseboxsizer = wx.StaticBoxSizer(databasebox, wx.VERTICAL)
-        databaseboxsizer.Add(item=dbm_base.createDbInfoDesc(self.panel, self.dbInfo, layer = self.layer),
-                             proportion=1,
-                             flag=wx.EXPAND | wx.ALL,
-                             border=3)
-
-        #
-        # text areas
-        #
-        # sql box
-        sqlbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                              label = " %s " % _("Query"))
-        sqlboxsizer = wx.StaticBoxSizer(sqlbox, wx.VERTICAL)
-
-        self.text_sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
-                                    value = '', size = (-1, 50),
-                                    style=wx.TE_MULTILINE)
-        if self.qtype.lower() == "select":
-            self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
-        self.text_sql.SetInsertionPointEnd()
-        self.text_sql.SetToolTipString(_("Example: %s") % "SELECT * FROM roadsmajor WHERE MULTILANE = 'no' OR OBJECTID < 10")
-        wx.CallAfter(self.text_sql.SetFocus)
-
-        sqlboxsizer.Add(item = self.text_sql, flag = wx.EXPAND)
-        
-        #
-        # buttons
-        #
-        self.btn_clear  = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
-        self.btn_clear.SetToolTipString(_("Set SQL statement to default"))
-        self.btn_verify = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("Verify"))
-        self.btn_verify.SetToolTipString(_("Verify SQL statement"))
-        self.btn_apply  = wx.Button(parent = self.panel, id = wx.ID_APPLY)
-        self.btn_apply.SetToolTipString(_("Apply SQL statement and close the dialog"))
-        self.btn_close  = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-        self.btn_close.SetToolTipString(_("Close the dialog"))
-        
-        self.btn_lv = { 'is'    : ['=', ],
-                        'isnot' : ['!=', ],
-                        'like'  : ['LIKE', ],
-                        'gt'    : ['>', ],
-                        'ge'    : ['>=', ],
-                        'lt'    : ['<', ],
-                        'le'    : ['<=', ],
-                        'or'    : ['OR', ],
-                        'not'   : ['NOT', ],
-                        'and'   : ['AND', ],
-                        'brac'  : ['()', ],
-                        'prc'   : ['%', ] }
-        
-        for key, value in self.btn_lv.iteritems():
-            btn = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                            label = value[0])
-            self.btn_lv[key].append(btn.GetId())
-        
-        buttonsizer = wx.FlexGridSizer(cols = 4, hgap = 5, vgap = 5)
-        buttonsizer.Add(item = self.btn_clear)
-        buttonsizer.Add(item = self.btn_verify)
-        buttonsizer.Add(item = self.btn_apply)
-        buttonsizer.Add(item = self.btn_close)
-        
-        buttonsizer2 = wx.GridBagSizer(5, 5)
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['is'][1]), pos = (0,0))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['isnot'][1]), pos = (1,0))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['like'][1]), pos = (2, 0))
-
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['gt'][1]), pos = (0, 1))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['ge'][1]), pos = (1, 1))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['or'][1]), pos = (2, 1))
-
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['lt'][1]), pos = (0, 2))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['le'][1]), pos = (1, 2))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['not'][1]), pos = (2, 2))
-
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['brac'][1]), pos = (0, 3))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['prc'][1]), pos = (1, 3))
-        buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['and'][1]), pos = (2, 3))
-        
-        #
-        # list boxes (columns, values)
-        #
-        hsizer = wx.BoxSizer(wx.HORIZONTAL)
-        
-        columnsbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                  label = " %s " % _("Columns"))
-        columnsizer = wx.StaticBoxSizer(columnsbox, wx.VERTICAL)
-        self.list_columns = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
-                                       choices = self.dbInfo.GetColumns(self.tablename),
-                                       style = wx.LB_MULTIPLE)
-        columnsizer.Add(item = self.list_columns, proportion = 1,
-                        flag = wx.EXPAND)
-
-        radiosizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.radio_cv = wx.RadioBox(parent = self.panel, id = wx.ID_ANY,
-                                    label = " %s " % _("Add on double-click"),
-                                    choices = [_("columns"), _("values")])
-        self.radio_cv.SetSelection(1) # default 'values'
-        radiosizer.Add(item = self.radio_cv, proportion = 1,
-                       flag = wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND, border = 5)
-
-        columnsizer.Add(item = radiosizer, proportion = 0,
-                        flag = wx.TOP | wx.EXPAND, border = 5)
-        # self.list_columns.SetMinSize((-1,130))
-        # self.list_values.SetMinSize((-1,100))
-
-        valuesbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
-                                 label = " %s " % _("Values"))
-        valuesizer = wx.StaticBoxSizer(valuesbox, wx.VERTICAL)
-        self.list_values = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
-                                      choices = self.colvalues,
-                                      style = wx.LB_MULTIPLE)
-        valuesizer.Add(item = self.list_values, proportion = 1,
-                       flag = wx.EXPAND)
-        
-        self.btn_unique = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                    label = _("Get all values"))
-        self.btn_unique.Enable(False)
-        self.btn_uniquesample = wx.Button(parent = self.panel, id = wx.ID_ANY,
-                                          label = _("Get sample"))
-        self.btn_uniquesample.Enable(False)
-
-        buttonsizer3 = wx.BoxSizer(wx.HORIZONTAL)
-        buttonsizer3.Add(item = self.btn_uniquesample, proportion = 0,
-                         flag = wx.ALIGN_CENTER_HORIZONTAL | wx.RIGHT, border = 5)
-        buttonsizer3.Add(item = self.btn_unique, proportion = 0,
-                         flag = wx.ALIGN_CENTER_HORIZONTAL)
-
-        valuesizer.Add(item = buttonsizer3, proportion = 0,
-                       flag = wx.TOP, border = 5)
-        
-        # hsizer1.Add(wx.StaticText(self.panel,-1, "Unique values: "), border=0, proportion=1)
- 
-        hsizer.Add(item = columnsizer, proportion = 1,
-                   flag = wx.EXPAND)
-        hsizer.Add(item = valuesizer, proportion = 1,
-                   flag = wx.EXPAND)
-        
-        self.close_onapply = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
-                                         label = _("Close dialog on apply"))
-        self.close_onapply.SetValue(True)
- 
-        pagesizer.Add(item = databaseboxsizer,
-                      flag = wx.ALL | wx.EXPAND, border = 5)
-        pagesizer.Add(item = hsizer, proportion = 1,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-        # pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5)
-        # pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5)
-        pagesizer.Add(item = buttonsizer2, proportion = 0,
-                      flag = wx.ALIGN_CENTER_HORIZONTAL)
-        pagesizer.Add(item = sqlboxsizer, proportion = 0,
-                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
-        pagesizer.Add(item = buttonsizer, proportion = 0,
-                      flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        pagesizer.Add(item = self.close_onapply, proportion = 0,
-                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-
-        #
-        # bindings
-        #
-        self.btn_unique.Bind(wx.EVT_BUTTON,       self.OnUniqueValues)
-        self.btn_uniquesample.Bind(wx.EVT_BUTTON, self.OnSampleValues)
-        
-        for key, value in self.btn_lv.iteritems():
-            self.FindWindowById(value[1]).Bind(wx.EVT_BUTTON, self.OnAddMark)
-        
-        self.btn_close.Bind(wx.EVT_BUTTON,       self.OnClose)
-        self.btn_clear.Bind(wx.EVT_BUTTON,       self.OnClear)
-        self.btn_verify.Bind(wx.EVT_BUTTON,      self.OnVerify)
-        self.btn_apply.Bind(wx.EVT_BUTTON,       self.OnApply)
-
-        self.list_columns.Bind(wx.EVT_LISTBOX,   self.OnAddColumn)
-        self.list_values.Bind(wx.EVT_LISTBOX,    self.OnAddValue)
-        
-        self.text_sql.Bind(wx.EVT_TEXT,          self.OnText)
-        
-        self.panel.SetAutoLayout(True)
-        self.panel.SetSizer(pagesizer)
-        pagesizer.Fit(self.panel)
-        
-        self.Layout()
-        self.SetMinSize((660, 525))
-        self.SetClientSize(self.panel.GetSize())
-        self.CenterOnParent()
-        
-    def OnUniqueValues(self, event, justsample = False):
-        """!Get unique values"""
-        vals = []
-        try:
-            idx = self.list_columns.GetSelections()[0]
-            column = self.list_columns.GetString(idx)
-        except:
-            self.list_values.Clear()
-            return
-        
-        self.list_values.Clear()
-        
-        querystring = "SELECT %s FROM %s" % (column, self.tablename)
-        
-        data = grass.db_select(table = self.tablename,
-                               sql = querystring,
-                               database = self.database,
-                               driver = self.driver)
-        if not data:
-            return
-
-        desc = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]
-        
-        i = 0
-        for item in sorted(map(desc['ctype'], data)):
-            if justsample and i < 256 or \
-               not justsample:
-                if desc['type'] != 'character':
-                    item = str(item)
-                self.list_values.Append(item)
-            else:
-                break
-            i += 1
-        
-    def OnSampleValues(self, event):
-        """!Get sample values"""
-        self.OnUniqueValues(None, True)
-
-    def OnAddColumn(self, event):
-        """!Add column name to the query"""
-        idx = self.list_columns.GetSelections()
-        for i in idx:
-            column = self.list_columns.GetString(i)
-            self._add(element = 'column', value = column)
-        
-        if not self.btn_uniquesample.IsEnabled():
-            self.btn_uniquesample.Enable(True)
-            self.btn_unique.Enable(True)
-        
-    def OnAddValue(self, event):
-        """!Add value"""
-        selection = self.list_values.GetSelections()
-        if not selection:
-            event.Skip()
-            return
-
-        idx = selection[0]
-        value = self.list_values.GetString(idx)
-        idx = self.list_columns.GetSelections()[0]
-        column = self.list_columns.GetString(idx)
-        
-        ctype = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]['type']
-        
-        if ctype == 'character':
-            value = "'%s'" % value
-        
-        self._add(element = 'value', value = value)
-
-    def OnAddMark(self, event):
-        """!Add mark"""
-        mark = None
-        for key, value in self.btn_lv.iteritems():
-            if event.GetId() == value[1]:
-                mark = value[0]
-                break
-        
-        self._add(element = 'mark', value = mark)
-
-    def _add(self, element, value):
-        """!Add element to the query
-
-        @param element element to add (column, value)
-        """
-        sqlstr = self.text_sql.GetValue()
-        newsqlstr = ''
-        if element == 'column':
-            if self.radio_cv.GetSelection() == 0: # -> column
-                idx1 = len('select')
-                idx2 = sqlstr.lower().find('from')
-                colstr = sqlstr[idx1:idx2].strip()
-                if colstr == '*':
-                    cols = []
-                else:
-                    cols = colstr.split(',')
-                if value in cols:
-                        cols.remove(value)
-                else:
-                    cols.append(value)
-                
-                if len(cols) < 1:
-                    cols = ['*',]
-                
-                newsqlstr = 'SELECT ' + ','.join(cols) + ' ' + sqlstr[idx2:]
-            else: # -> where
-                newsqlstr = sqlstr
-                if sqlstr.lower().find('where') < 0:
-                    newsqlstr += ' WHERE'
-                
-                newsqlstr += ' ' + value
-        
-        elif element == 'value':
-            newsqlstr = sqlstr + ' ' + value
-        elif element == 'mark':
-            newsqlstr = sqlstr + ' ' + value
-        
-        if newsqlstr:
-            self.text_sql.SetValue(newsqlstr)
-
-    def GetSQLStatement(self):
-        """!Return SQL statement"""
-        return self.text_sql.GetValue().strip().replace("\n"," ")
-    
-    def CloseOnApply(self):
-        """!Return True if the dialog will be close on apply"""
-        return self.close_onapply.IsChecked()
-    
-    def OnText(self, event):
-        """Query string changed"""
-        if len(self.text_sql.GetValue()) > 0:
-            self.btn_verify.Enable(True)
-        else:
-            self.btn_verify.Enable(False)
-        
-    def OnApply(self, event):
-        """Apply button pressed"""
-        if self.evtHeader:
-            self.evtHeader(event = 'apply')
-
-        if self.close_onapply.IsChecked():
-            self.Destroy()
-            
-        event.Skip()
-    
-    def OnVerify(self, event):
-        """!Verify button pressed"""
-        ret, msg = gcmd.RunCommand('db.select',
-                                   getErrorMsg = True,
-                                   table = self.tablename,
-                                   sql = self.text_sql.GetValue(),
-                                   flags = 't',
-                                   driver = self.driver,
-                                   database = self.database)
-        
-        if ret != 0 and msg:
-            self.statusbar.SetStatusText(_("SQL statement is not valid"), 0)
-            gcmd.GError(parent = self,
-                        message = _("SQL statement is not valid.\n\n%s") % msg)
-        else:
-            self.statusbar.SetStatusText(_("SQL statement is valid"), 0)
-                        
-    def OnClear(self, event):
-        """!Clear button pressed"""
-        if self.qtype.lower() == "select":
-            self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
-        else:
-            self.text_sql.SetValue("")
-    
-    def OnClose(self, event):
-        """!Close button pressed"""
-        if self.evtHeader:
-            self.evtHeader(event = 'close')
-        
-        self.Destroy()
-        
-        event.Skip()
-        
-if __name__ == "__main__":
-    if len(sys.argv) != 2:
-        print >>sys.stderr, __doc__
-        sys.exit()
-    
-    import gettext
-    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
-    
-    app = wx.App(0)
-    sqlb = SQLFrame(parent = None, title = _('SQL Builder'), vectmap = sys.argv[1])
-    sqlb.Show()
-    
-    app.MainLoop()

Deleted: grass/trunk/gui/wxpython/gui_modules/states.txt
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/states.txt	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/states.txt	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,185 +0,0 @@
-Afghanistan; 59.9,28.66 75.65,39.11
-Africa; -20.2,-37.6 53.4,35.75
-Albania; 19.36,39.42 21.39,42.71
-Algeria; -9.47,17.94 13.19,38.14
-Angola; 11.31,-18.68 24.97,-3.84
-Antarctic; -180,-90 180,-66
-Antarctica; -180,-90 180,-62.83
-Arctic; -180,66 180,90
-Argentina; -74.97,-56.71 -51.76,-20.25
-Armenia; 43.53,38.68 47.07,41.48
-Asia; 40,-10 180,83.5
-Australia; 111.22,-45.73 155.72,-8.88
-Austria; 9.27,45.99 17.93,49.38
-Azerbaijan; 44.58,38.04 50.96,42.2
-Bangladesh; 87.95,20.75 93.07,26.62
-Belgium; 2.54,49.31 6.69,51.69
-Belize; -89.18,15.78 -87.78,18.64
-Benin; 0.74,5.97 4.34,12.66
-Bhutan; 88.8,26.54 92.37,28.46
-Bolivia; -70.05,-23.63 -56.72,-9.13
-Bosnia and Herzegovina; 15.76,42.38 20.02,45.45
-Botswana; 19.57,-27.41 29.94,-17.32
-Brazil; -75.64,-35.81 -32.74,7.12
-Brunei; 114.22,3.96 115.42,5.09
-Bulgaria; 22.19,40.86 29.02,44.59
-Burkina Faso; -5.72,9.19 2.98,15.54
-Burma; 91.41,9.22 102.13,29.34
-Burundi; 28.98,-4.85 31.17,-2.35
-Byelarus; 22.91,50.82 33.38,56.65
-Cambodia; 102.28,10.07 107.98,14.86
-Cameroon; 8.22,1.06 16.85,13.65
-Canada; -145.27,37.3 -48.11,87.61
-Caribbean; -91.4,27.36 -55.4,6.48
-Central African Republic; 13.96,1.5 28.11,11.67
-Central America; -94.1,21.8 -75.8,6.61
-Chad; 12.88,6.67 24.97,24.19
-Chile; -77.16,-56.79 -64.9,-15.72
-China; 70.83,15.06 137.97,56.58
-Colombia; -79.69,-5 -66.15,13.28
-Congo; 10.93,-5.41 19.19,3.98
-Costa Rica; -85.83,7.9 -82.18,11.38
-Croatia; 13.47,42.09 19.92,46.84
-Cuba; -85.03,19.36 -73.44,23.68
-Cyprus; 32.23,34.44 34.78,35.78
-Czech Republic; 12.13,48.23 19.38,51.42
-Denmark; 8.02,54.68 12.89,58
-Djibouti; 41.89,10.78 43.77,12.81
-Dominican Republic; -71.87,17.54 -67.99,20.12
-East Pacific Ocean; -180,64.8 -72.7,-75.6
-Ecuador; -81.08,-5.35 -74.68,1.72
-Egypt; 24.29,21.29 37.61,32.14
-El Salvador; -90.05,13.07 -87.41,14.6
-Equatorial Guinea; 8.39,0.76 11.59,3.82
-Eritrea; 36.31,12 43.58,18.41
-Estonia; 23.3,57.29 28.59,59.75
-Ethiopia; 32.49,2.63 48.85,15.56
-Europe; -25.1,71.3 35,34.9
-Finland; 20.46,59.3 32.14,70.44
-France; -5.29,40.65 10.4,51.82
-French Guiana; -54.37,1.84 -51.23,5.89
-Gabon; 8.71,-4.23 15.01,2.6
-Gambia; -16.71,13.02 -13.66,13.96
-Germany; 5.68,46.86 15.68,55.41
-Ghana; -3.31,4.39 1.7,11.47
-Greece; 19.99,34.62 27.19,42.01
-Greenland; -75.34,56.78 -9.36,86.6
-Guatemala; -92.24,13.59 -87.87,18.06
-Guinea; -15.19,6.77 -6.87,13.02
-Guinea-Bissau; -16.51,10.97 -13.34,12.8
-Guyana; -61.41,0.81 -56.12,8.79
-Haiti; -74.38,17.88 -71.34,20.1
-Honduras; -89.47,12.75 -82.92,16.31
-Hungary; 16.12,45.44 23.57,48.95
-Iceland; -24.55,62.81 -12.79,67.01
-India; 66.79,6.58 99.01,36.96
-Indian Ocean; 22.3,-55.4 119.5,25.2
-Indonesia; 93.11,-12.65 143.45,7.88
-Iran; 43.31,24.08 64.42,40.73
-Iraq; 38.47,28.5 49.25,37.84
-Ireland; -10.52,51.23 -5.62,55.49
-Israel; 34.17,29.25 36.09,33.31
-Italy; 6.11,36.15 19.33,47.71
-Ivory Coast; -8.64,4.03 -2.01,10.96
-Jamaica; -78.22,17.72 -76,18.63
-Japan; 128.74,30.1 146.46,46.26
-Jordan; 34.97,28.87 39.75,33.44
-Kazakhstan; 44.73,38.62 89.65,57.49
-Kenya; 33,-5.3 42.44,5.07
-Democratic People's Republic of Korea; 124.02,43.29 37.55,130.95
-Republic of Korea; 125.95,38.76 33.06,129.88
-Kuwait; 46.62,28.34 48.74,30
-Kyrgyzstan; 69.01,38.7 81.03,43.77
-Laos; 99.77,13.47 108.1,22.98
-Latvia; 20.76,55.32 28.76,58.44
-Lebanon; 35.09,32.84 36.79,34.63
-Lesotho; 27.16,-30.89 29.76,-28.59
-Liberia; -11.47,4.16 -6.95,8.66
-Libya; 8.79,18.7 26.1,33.95
-Lithuania; 20.86,53.6 27.25,56.73
-Luxembourg; 5.9,49.42 6.77,50.21
-Macedonia; 20.62,40.62 23.27,42.48
-Madagascar; 42.83,-26.31 51.38,-11.58
-Malawi; 32.55,-17.51 36.46,-9.26
-Malaysia; 99.4,-0.2 120.19,7.86
-Mali; -12.77,9.25 5.27,25.83
-Mauritania; -17.47,14.21 -4.04,27.81
-Mexico; -118.48,13.05 -85.18,34.17
-Middle East; 25,10.7 59.7,36.1
-Moldova; 26.64,45.31 30.47,48.64
-Mongolia; 86.47,40 121.62,53.65
-Montenegro; 18.56,41.77 20.67,43.64
-Morocco; -13.52,26.96 -0.28,36.48
-Mozambique; 29.67,-27.82 41.89,-9.63
-Namibia; 11.32,-29.61 25.86,-16.31
-Nepal; 79.9,26 88.84,30.88
-Netherlands; 3.54,50.56 7.62,53.59
-New Hampshire; -72.68,42.57 -70.58,45.43
-New Jersey; -75.69,38.8 -73.78,41.47
-New Mexico; -109.35,31.04 -102.7,37.3
-New Zealand; 166.05,-47.31 179.41,-33.89
-Nicaragua; -87.7,10.55 -82.87,15.24
-Niger; -0.39,10.95 16.95,24.28
-Nigeria; 2.33,3.72 15.34,14.4
-North America; -168.5,18 -50.4,85.7
-North Atlantic Ocean; -82,0 12,80
-Northern Temperate; -180,23 180,60
-Norway; 3.88,56.69 32.56,81.95
-Oman; 51.53,16.19 60.52,26.73
-Pakistan; 60.18,22.94 78.66,37.86
-Panama; -83.06,6.9 -76.63,9.95
-Papua New Guinea; 140.37,-11.3 153.05,-2.2
-Paraguay; -62.83,-27.85 -53.6,-18.87
-Peru; -82.13,-19.35 -67.52,0.79
-Philippines; 116.68,4.85 127.23,19.22
-Poland; 13.77,48.57 24.85,55.24
-Portugal; -9.6,36.75 -5.65,42.36
-Qatar; 50.97,24.33 51.89,26.17
-Romania; 20.05,43.29 30.38,48.76
-Russia; 25,23.21 180,71
-Rwanda; 28.9,-3.01 31.2,-1.03
-Saudi Arabia; 33.9,14.01 57.3,33.22
-Senegal; -17.53,12.02 -10.89,17.14
-Serbia; 18.8,41.66 23.35,46.39
-Sierra Leone; -13.16,6.71 -10.02,10.09
-Slovakia; 16.84,47.61 23.06,49.93
-Slovenia; 13.39,45.28 16.87,47.06
-Somalia; 40.53,-2.55 52.14,12.66
-South Africa; 13.68,-35.9 33.98,-21.27
-South America; -84.9,-57.6 -32.4,13.7
-South Atlantic Ocean; -67,-55.4 23,0
-Southern Ocean; -180,-77 180,-32
-Southern Temperate; -180,-60 180,-23
-Spain; -9.69,35.4 3.98,44.38
-Sri Lanka; 79.69,5.76 82.26,9.89
-Sudan; 21.06,2.6 39.77,22.86
-Suriname; -58.01,1.53 -53.42,6.23
-Swaziland; 30.93,-27.52 32.45,-25.72
-Sweden; 10.56,54.63 24.84,69.68
-Switzerland; 5.92,45.66 10.84,48.02
-Syria; 35.36,31.84 43.11,37.69
-Taiwan; 119.99,21.78 122.14,25.31
-Tajikistan; 67.34,36.34 75.59,41.46
-Tanzania United Republic of; 0,-0.54 28.96,41.23
-Thailand; 96.83,4.8 106.42,21.22
-Togo; -0.09,5.85 2.21,11.33
-Trinidad; -61.88,10.01 -60.86,10.89
-Tropics; -180,-23 180,23
-Tunisia; 7.38,29.87 12.03,37.65
-Turkey; 25.29,34.91 45.94,43
-Turkmenistan; 52.05,34.56 67.66,43.46
-Uganda; 29.45,-1.82 35.52,4.32
-Ukraine; 21.4,43.61 41.24,53.31
-United Arab Emirates; 51.06,21.82 56.87,26.25
-United Kingdom; -8.41,49.49 2.39,59.07
-United States; -180,13.71 -61.48,76.63
-Uruguay; -58.46,-35.26 -52.77,-29.97
-Uzbekistan; 55.44,36.08 74.31,46.46
-Venezuela; -73.81,-0.11 -58.91,12.92
-Vietnam; 101.43,7.75 110.25,24.05
-Virginia; -84.1,36.12 -74.82,39.88
-Western Sahara; -17.23,20.87 -8.01,28
-Yemen; 42.45,12.12 53.74,19.51
-Zaire; 11.45,-14.4 32.4,6.28
-Zambia; 21.55,-18.7 34.45,-7.69
-Zimbabwe; 25.11,-22.93 33.65,15.22

Deleted: grass/trunk/gui/wxpython/gui_modules/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/toolbars.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1741 +0,0 @@
-"""!
- at package toolbar
-
- at brief wxGUI toolbar widgets
-
-Classes:
- - AbstractToolbar
- - MapToolbar
- - GCPMapToolbar
- - GCPDisplayToolbar
- - VDigitToolbar
- - ProfileToolbar
- - LMNvizToolbar
- - ModelToolbar
- - HistogramToolbar
- - Histogram2Toolbar
- - ScatterplotToolbar
- - LMWorkspaceToolbar
- - LMDataToolbar
- - LMToolsToolbar
- - LMMiscToolbar
- - LMVectorToolbar
- - PsMapToolbar
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
- at author Anna Kratochvilova <kratochanna gmail.com>
-"""
-
-import os
-import sys
-import platform
-
-from grass.script import core as grass
-
-import wx
-
-import globalvar
-from gdialogs    import CreateNewVector
-from vdigit      import VDigitSettingsDialog, haveVDigit, VDigit
-from debug       import Debug
-from preferences import globalSettings as UserSettings
-from gcmd        import RunCommand, GError
-from nviz        import haveNviz
-from nviz_preferences import NvizPreferencesDialog
-
-sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
-from icon import Icons
-
-class AbstractToolbar(wx.ToolBar):
-    """!Abstract toolbar class"""
-    def __init__(self, parent):
-        self.parent = parent
-        wx.ToolBar.__init__(self, parent = self.parent, id = wx.ID_ANY)
-        
-        self.action = dict()
-        
-        self.Bind(wx.EVT_TOOL, self.OnTool)
-        
-        self.SetToolBitmapSize(globalvar.toolbarSize)
-        
-    def InitToolbar(self, toolData):
-        """!Initialize toolbar, add tools to the toolbar
-        """
-        for tool in toolData:
-            self.CreateTool(*tool)
-        
-        self._data = toolData
-        
-    def _toolbarData(self):
-        """!Toolbar data (virtual)"""
-        return None
-    
-    def CreateTool(self, label, bitmap, kind,
-                   shortHelp, longHelp, handler, pos = -1):
-        """!Add tool to the toolbar
-        
-        @param pos if -1 add tool, if > 0 insert at given pos
-        @return id of tool
-        """
-        bmpDisabled = wx.NullBitmap
-        tool = -1
-        if label:
-            tool = vars(self)[label] = wx.NewId()
-            Debug.msg(3, "CreateTool(): tool=%d, label=%s bitmap=%s" % \
-                          (tool, label, bitmap))
-            if pos < 0:
-                toolWin = self.AddLabelTool(tool, label, bitmap,
-                                            bmpDisabled, kind,
-                                            shortHelp, longHelp)
-            else:
-                toolWin = self.InsertLabelTool(pos, tool, label, bitmap,
-                                            bmpDisabled, kind,
-                                            shortHelp, longHelp)
-            self.Bind(wx.EVT_TOOL, handler, toolWin)
-        else: # separator
-            self.AddSeparator()
-        
-        return tool
-    
-    def EnableLongHelp(self, enable = True):
-        """!Enable/disable long help
-        
-        @param enable True for enable otherwise disable
-        """
-        for tool in self._data:
-            if tool[0] == '': # separator
-                continue
-            
-            if enable:
-                self.SetToolLongHelp(vars(self)[tool[0]], tool[4])
-            else:
-                self.SetToolLongHelp(vars(self)[tool[0]], "")
-        
-    def OnTool(self, event):
-        """!Tool selected
-        """
-        if self.parent.GetName() == "GCPFrame":
-            return
-        
-        if hasattr(self.parent, 'toolbars'):
-            if self.parent.GetToolbar('vdigit'):
-                # update vdigit toolbar (unselect currently selected tool)
-                id = self.parent.toolbars['vdigit'].GetAction(type = 'id')
-                self.parent.toolbars['vdigit'].ToggleTool(id, False)
-        
-        if event:
-            # deselect previously selected tool
-            id = self.action.get('id', -1)
-            if id != event.GetId():
-                self.ToggleTool(self.action['id'], False)
-            else:
-                self.ToggleTool(self.action['id'], True)
-            
-            self.action['id'] = event.GetId()
-            
-            event.Skip()
-        else:
-            # initialize toolbar
-            self.ToggleTool(self.action['id'], True)
-        
-    def GetAction(self, type = 'desc'):
-        """!Get current action info"""
-        return self.action.get(type, '')
-    
-    def SelectDefault(self, event):
-        """!Select default tool"""
-        self.ToggleTool(self.defaultAction['id'], True)
-        self.defaultAction['bind'](event)
-        self.action = { 'id' : self.defaultAction['id'],
-                        'desc' : self.defaultAction.get('desc', '') }
-        
-    def FixSize(self, width):
-        """!Fix toolbar width on Windows
-            
-        @todo Determine why combobox causes problems here
-        """
-        if platform.system() == 'Windows':
-            size = self.GetBestSize()
-            self.SetSize((size[0] + width, size[1]))
-
-    def Enable(self, tool, enable = True):
-        """!Enable/Disable defined tool
-        
-        @param tool name
-        @param enable True to enable otherwise disable tool
-        """
-        try:
-            id = getattr(self, tool)
-        except AttributeError:
-            return
-        
-        self.EnableTool(id, enable)
-
-    def EnableAll(self, enable = True):
-        """!Enable/Disable all tools
-        
-        @param enable True to enable otherwise disable tool
-        """
-        for item in self._toolbarData():
-            if not item[0]:
-                continue
-            self.Enable(item[0], enable)
-        
-    def _getToolbarData(self, data):
-        """!Define tool
-        """
-        retData = list()
-        for args in data:
-            retData.append(self._defineTool(*args))
-        return retData
-
-    def _defineTool(self, name = None, icon = None, handler = None, item = wx.ITEM_NORMAL, pos = -1):
-        """!Define tool
-        """
-        if name:
-            return (name, icon.GetBitmap(),
-                    item, icon.GetLabel(), icon.GetDesc(),
-                    handler, pos)
-        return ("", "", "", "", "", "") # separator
-    
-class MapToolbar(AbstractToolbar):
-    """!Map Display toolbar
-    """
-    def __init__(self, parent, mapcontent):
-        """!Map Display constructor
-
-        @param parent reference to MapFrame
-        @param mapcontent reference to render.Map (registred by MapFrame)
-        """
-        self.mapcontent = mapcontent # render.Map
-        AbstractToolbar.__init__(self, parent = parent) # MapFrame
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # optional tools
-        choices = [ _('2D view'), ]
-        self.toolId = { '2d' : 0 }
-        if self.parent.GetLayerManager():
-            log = self.parent.GetLayerManager().GetLogWindow()
-        
-        if haveNviz:
-            choices.append(_('3D view'))
-            self.toolId['3d'] = 1
-        else:
-            from nviz import errorMsg
-            log.WriteCmdLog(_('3D view mode not available'))
-            log.WriteWarning(_('Reason: %s') % str(errorMsg))
-            log.WriteLog(_('Note that the wxGUI\'s 3D view mode is currently disabled '
-                           'on MS Windows (hopefully this will be fixed soon). '
-                           'Please keep an eye out for updated versions of GRASS. '
-                           'In the meantime you can use "NVIZ" from the File menu.'), wrap = 60)
-            
-            self.toolId['3d'] = -1
-
-        if haveVDigit:
-            choices.append(_('Digitize'))
-            if self.toolId['3d'] > -1:
-                self.toolId['vdigit'] = 2
-            else:
-                self.toolId['vdigit'] = 1
-        else:
-            from vdigit import errorMsg
-            log.WriteCmdLog(_('Vector digitizer not available'))
-            log.WriteWarning(_('Reason: %s') % errorMsg)
-            log.WriteLog(_('Note that the wxGUI\'s vector digitizer is currently disabled '
-                           '(hopefully this will be fixed soon). '
-                           'Please keep an eye out for updated versions of GRASS. '
-                           'In the meantime you can use "v.digit" from the Develop Vector menu.'), wrap = 60)
-            
-            self.toolId['vdigit'] = -1
-        
-        self.combo = wx.ComboBox(parent = self, id = wx.ID_ANY,
-                                 choices = choices,
-                                 style = wx.CB_READONLY, size = (110, -1))
-        self.combo.SetSelection(0)
-        
-        self.comboid = self.AddControl(self.combo)
-        self.parent.Bind(wx.EVT_COMBOBOX, self.OnSelectTool, self.comboid)
-        
-        # realize the toolbar
-        self.Realize()
-        
-        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
-        self.combo.Hide()
-        self.combo.Show()
-        
-        self.action = { 'id' : self.pointer }
-        self.defaultAction = { 'id' : self.pointer,
-                               'bind' : self.parent.OnPointer }
-        
-        self.OnTool(None)
-        
-        self.EnableTool(self.zoomback, False)
-        
-        self.FixSize(width = 90)
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['displayWindow']
-        return self._getToolbarData((('displaymap', icons['display'],
-                                      self.parent.OnDraw),
-                                     ('rendermap', icons['render'],
-                                      self.parent.OnRender),
-                                     ('erase', icons['erase'],
-                                      self.parent.OnErase),
-                                     (None, ),
-                                     ('pointer', icons['pointer'],
-                                      self.parent.OnPointer,
-                                      wx.ITEM_CHECK),
-                                     ('query', icons['query'],
-                                      self.parent.OnQuery,
-                                      wx.ITEM_CHECK),
-                                     ('pan', icons['pan'],
-                                      self.parent.OnPan,
-                                      wx.ITEM_CHECK),
-                                     ('zoomin', icons['zoomIn'],
-                                      self.parent.OnZoomIn,
-                                      wx.ITEM_CHECK),
-                                     ('zoomout', icons['zoomOut'],
-                                      self.parent.OnZoomOut,
-                                      wx.ITEM_CHECK),
-                                     ('zoomextent', icons['zoomExtent'],
-                                      self.parent.OnZoomToMap),
-                                     ('zoomback', icons['zoomBack'],
-                                      self.parent.OnZoomBack),
-                                     ('zoommenu', icons['zoomMenu'],
-                                      self.parent.OnZoomMenu),
-                                     (None, ),
-                                     ('analyze', icons['analyze'],
-                                      self.parent.OnAnalyze),
-                                     (None, ),
-                                     ('dec', icons['overlay'],
-                                      self.parent.OnDecoration),
-                                     (None, ),
-                                     ('savefile', icons['saveFile'],
-                                      self.parent.SaveToFile),
-                                     ('printmap', icons['print'],
-                                      self.parent.PrintMenu),
-                                     (None, ))
-                                    )
-    def InsertTool(self, data):
-        """!Insert tool to toolbar
-        
-        @param data toolbar data"""
-        data = self._getToolbarData(data)
-        for tool in data:
-            self.CreateTool(*tool)
-        self.Realize()
-        
-        self.parent._mgr.GetPane('mapToolbar').BestSize(self.GetBestSize())
-        self.parent._mgr.Update()
-        
-    def RemoveTool(self, tool):
-        """!Remove tool from toolbar
-        
-        @param tool tool id"""
-        self.DeleteTool(tool)
-        
-        self.parent._mgr.GetPane('mapToolbar').BestSize(self.GetBestSize())
-        self.parent._mgr.Update()
-        
-    def ChangeToolsDesc(self, mode2d):
-        """!Change description of zoom tools for 2D/3D view"""
-        if mode2d:
-            set = 'displayWindow'
-        else:
-            set = 'nviz'
-        for i, data in enumerate(self._data):
-            for tool, toolname in (('zoomin', 'zoomIn'),('zoomout', 'zoomOut')):
-                if data[0] == tool:
-                    tmp = list(data)
-                    tmp[4] = Icons[set][toolname].GetDesc()
-                    self._data[i] = tuple(tmp)
-                
-    def OnSelectTool(self, event):
-        """!Select / enable tool available in tools list
-        """
-        tool =  event.GetSelection()
-        
-        if tool == self.toolId['2d']:
-            self.ExitToolbars()
-            self.Enable2D(True)
-            self.ChangeToolsDesc(mode2d = True)            
-        
-        elif tool == self.toolId['3d'] and \
-                not (self.parent.MapWindow3D and self.parent.IsPaneShown('3d')):
-            self.ExitToolbars()
-            self.parent.AddNviz()
-            
-        elif tool == self.toolId['vdigit'] and \
-                not self.parent.GetToolbar('vdigit'):
-            self.ExitToolbars()
-            self.parent.AddToolbar("vdigit")
-            self.parent.MapWindow.SetFocus()
-        
-    def ExitToolbars(self):
-        if self.parent.GetToolbar('vdigit'):
-            self.parent.toolbars['vdigit'].OnExit()
-        if self.parent.GetLayerManager().IsPaneShown('toolbarNviz'):
-            self.parent.RemoveNviz()
-        
-    def Enable2D(self, enabled):
-        """!Enable/Disable 2D display mode specific tools"""
-        for tool in (self.zoommenu,
-                     self.analyze,
-                     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):
-        icons = Icons['georectify']
-        return self._getToolbarData((('gcpSave', icons["gcpSave"],
-                                      self.parent.SaveGCPs),
-                                     ('gcpReload', icons["gcpReload"],
-                                      self.parent.ReloadGCPs),
-                                     (None, ),
-                                     ('gcpAdd', icons["gcpAdd"],
-                                      self.parent.AddGCP),
-                                     ('gcpDelete', icons["gcpDelete"],
-                                      self.parent.DeleteGCP),
-                                     ('gcpClear', icons["gcpClear"],
-                                      self.parent.ClearGCP),
-                                     (None, ),
-                                     ('rms', icons["gcpRms"],
-                                      self.parent.OnRMS),
-                                     ('georect', icons["georectify"],
-                                      self.parent.OnGeorect))
-                                    )
-    
-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['displayWindow']["zoomBack"].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"""
-        icons = Icons['displayWindow']
-        return self._getToolbarData((("displaymap", icons["display"],
-                                      self.parent.OnDraw),
-                                     ("rendermap", icons["render"],
-                                      self.parent.OnRender),
-                                     ("erase", icons["erase"],
-                                      self.parent.OnErase),
-                                     (None, ),
-                                     ("gcpset", Icons["georectify"]["gcpSet"],
-                                      self.parent.OnPointer),
-                                     ("pan", icons["pan"],
-                                      self.parent.OnPan),
-                                     ("zoomin", icons["zoomIn"],
-                                      self.parent.OnZoomIn),
-                                     ("zoomout", icons["zoomOut"],
-                                      self.parent.OnZoomOut),
-                                     ("zoommenu", icons["zoomMenu"],
-                                      self.parent.OnZoomMenuGCP),
-                                     (None, ),
-                                     ("zoomback", icons["zoomBack"],
-                                      self.parent.OnZoomBack),
-                                     ("zoomtomap", icons["zoomExtent"],
-                                      self.parent.OnZoomToMap),
-                                     (None, ),
-                                     ('settings', Icons["georectify"]["settings"],
-                                      self.parent.OnSettings),
-                                     ('help', Icons["misc"]["help"],
-                                      self.parent.OnHelp),
-                                     (None, ),
-                                     ('quit', Icons["georectify"]["quit"],
-                                      self.parent.OnQuit))
-                                    )
-    
-class VDigitToolbar(AbstractToolbar):
-    """!Toolbar for digitization
-    """
-    def __init__(self, parent, MapWindow, tools = [], layerTree = None, log = None):
-        self.MapWindow     = MapWindow
-        self.Map           = MapWindow.GetMap() # Map class instance
-        self.layerTree     = layerTree  # reference to layer tree associated to map display
-        self.log           = log        # log area
-        self.tools         = tools
-        AbstractToolbar.__init__(self, parent)
-        self.digit         = None
-        
-        # currently selected map layer for editing (reference to MapLayer instance)
-        self.mapLayer = None
-        # list of vector layers from Layer Manager (only in the current mapset)
-        self.layers   = [] 
-        
-        self.comboid  = self.combo = None
-        self.undo     = -1
-        
-        # only one dialog can be open
-        self.settingsDialog   = None
-        
-        # create toolbars (two rows optionally)
-        self.InitToolbar(self._toolbarData())
-        self.Bind(wx.EVT_TOOL, self.OnTool)
-        
-        # default action (digitize new point, line, etc.)
-        self.action = { 'desc' : '',
-                        'type' : '',
-                        'id'   : -1 }
-        
-        # list of available vector maps
-        self.UpdateListOfLayers(updateTool = True)
-        
-        # realize toolbar
-        self.Realize()
-        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
-        if self.combo:
-            self.combo.Hide()
-            self.combo.Show()
-        
-        # disable undo/redo
-        if self.undo:
-            self.EnableTool(self.undo, False)
-        
-        # toogle to pointer by default
-        self.OnTool(None)
-        
-        self.FixSize(width = 105)
-        
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        data = []
-        icons = Icons['vdigit']
-        if not self.tools or 'selector' in self.tools:
-            data.append((None, ))
-        if not self.tools or 'addPoint' in self.tools:
-            data.append(("addPoint", icons["addPoint"],
-                         self.OnAddPoint,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'addLine' in self.tools:
-            data.append(("addLine", icons["addLine"],
-                        self.OnAddLine,
-                        wx.ITEM_CHECK))
-        if not self.tools or 'addBoundary' in self.tools:
-            data.append(("addBoundary", icons["addBoundary"],
-                         self.OnAddBoundary,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'addCentroid' in self.tools:
-            data.append(("addCentroid", icons["addCentroid"],
-                         self.OnAddCentroid,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'addArea' in self.tools:
-            data.append(("addArea", icons["addArea"],
-                         self.OnAddArea,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'moveVertex' in self.tools:            
-            data.append(("moveVertex", icons["moveVertex"],
-                         self.OnMoveVertex,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'addVertex' in self.tools:
-            data.append(("addVertex", icons["addVertex"],
-                         self.OnAddVertex,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'removeVertex' in self.tools:
-            data.append(("removeVertex", icons["removeVertex"],
-                         self.OnRemoveVertex,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'editLine' in self.tools:            
-            data.append(("editLine", icons["editLine"],
-                         self.OnEditLine,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'moveLine' in self.tools:
-            data.append(("moveLine", icons["moveLine"],
-                         self.OnMoveLine,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'deleteLine' in self.tools:
-            data.append(("deleteLine", icons["deleteLine"],
-                         self.OnDeleteLine,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'displayCats' in self.tools:
-            data.append(("displayCats", icons["displayCats"],
-                         self.OnDisplayCats,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'displayAttr' in self.tools:
-            data.append(("displayAttr", icons["displayAttr"],
-                         self.OnDisplayAttr,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'additionalSelf.Tools' in self.tools:
-            data.append(("additionalTools", icons["additionalTools"],
-                         self.OnAdditionalToolMenu,
-                         wx.ITEM_CHECK))
-        if not self.tools or 'undo' in self.tools or \
-                'settings' in self.tools or \
-                'quit' in self.tools:
-            data.append((None, ))
-        if not self.tools or 'undo' in self.tools:
-            data.append(("undo", icons["undo"],
-                         self.OnUndo))
-        if not self.tools or 'settings' in self.tools:
-            data.append(("settings", icons["settings"],
-                         self.OnSettings))
-        if not self.tools or 'quit' in self.tools:
-            data.append(("quit", icons["quit"],
-                         self.OnExit))
-        
-        return self._getToolbarData(data)
-    
-    def OnTool(self, event):
-        """!Tool selected -> disable selected tool in map toolbar"""
-        if self.parent.GetName() == 'IClassWindow':
-            toolbarName = 'iClassMap'
-        else:
-            toolbarName = 'map'
-        aId = self.parent.toolbars[toolbarName].GetAction(type = 'id')
-        self.parent.toolbars[toolbarName].ToggleTool(aId, False)
-                
-        # set cursor
-        cursor = self.parent.cursors["cross"]
-        self.MapWindow.SetCursor(cursor)
-        
-        # pointer
-        self.parent.OnPointer(None)
-                
-        if event:
-            # deselect previously selected tool
-            aId = self.action.get('id', -1)
-            if aId != event.GetId() and \
-                    self.action['id'] != -1:
-                self.ToggleTool(self.action['id'], False)
-            else:
-                self.ToggleTool(self.action['id'], True)
-            
-            self.action['id'] = event.GetId()
-            
-            event.Skip()
-        
-        if self.action['id'] != -1:
-            self.ToggleTool(self.action['id'], True)
-        
-        # clear tmp canvas
-        if self.action['id'] != aId:
-            self.MapWindow.ClearLines(pdc = self.MapWindow.pdcTmp)
-            if self.digit and \
-                    len(self.MapWindow.digit.GetDisplay().GetSelected()) > 0:
-                # cancel action
-                self.MapWindow.OnMiddleDown(None)
-        
-        # set focus
-        self.MapWindow.SetFocus()
-        
-    def OnAddPoint(self, event):
-        """!Add point to the vector map Laier"""
-        Debug.msg (2, "VDigitToolbar.OnAddPoint()")
-        self.action = { 'desc' : "addLine",
-                        'type' : "point",
-                        'id'   : self.addPoint }
-        self.MapWindow.mouse['box'] = 'point'
-        
-    def OnAddLine(self, event):
-        """!Add line to the vector map layer"""
-        Debug.msg (2, "VDigitToolbar.OnAddLine()")
-        self.action = { 'desc' : "addLine",
-                        'type' : "line",
-                        'id'   : self.addLine }
-        self.MapWindow.mouse['box'] = 'line'
-        ### self.MapWindow.polycoords = [] # reset temp line
-                
-    def OnAddBoundary(self, event):
-        """!Add boundary to the vector map layer"""
-        Debug.msg (2, "VDigitToolbar.OnAddBoundary()")
-        if self.action['desc'] != 'addLine' or \
-                self.action['type'] != 'boundary':
-            self.MapWindow.polycoords = [] # reset temp line
-        self.action = { 'desc' : "addLine",
-                        'type' : "boundary",
-                        'id'   : self.addBoundary }
-        self.MapWindow.mouse['box'] = 'line'
-        
-    def OnAddCentroid(self, event):
-        """!Add centroid to the vector map layer"""
-        Debug.msg (2, "VDigitToolbar.OnAddCentroid()")
-        self.action = { 'desc' : "addLine",
-                        'type' : "centroid",
-                        'id'   : self.addCentroid }
-        self.MapWindow.mouse['box'] = 'point'
-
-    def OnAddArea(self, event):
-        """!Add area to the vector map layer"""
-        Debug.msg (2, "VDigitToolbar.OnAddCentroid()")
-        self.action = { 'desc' : "addLine",
-                        'type' : "area",
-                        'id'   : self.addArea }
-        self.MapWindow.mouse['box'] = 'line'
-
-    def OnExit (self, event=None):
-        """!Quit digitization tool"""
-        # stop editing of the currently selected map layer
-        if self.mapLayer:
-            self.StopEditing()
-        
-        # close dialogs if still open
-        if self.settingsDialog:
-            self.settingsDialog.OnCancel(None)
-            
-        # set default mouse settings
-        self.MapWindow.mouse['use'] = "pointer"
-        self.MapWindow.mouse['box'] = "point"
-        self.MapWindow.polycoords = []
-        
-        # disable the toolbar
-        self.parent.RemoveToolbar("vdigit")
-        
-    def OnMoveVertex(self, event):
-        """!Move line vertex"""
-        Debug.msg(2, "Digittoolbar.OnMoveVertex():")
-        self.action = { 'desc' : "moveVertex",
-                        'id'   : self.moveVertex }
-        self.MapWindow.mouse['box'] = 'point'
-
-    def OnAddVertex(self, event):
-        """!Add line vertex"""
-        Debug.msg(2, "Digittoolbar.OnAddVertex():")
-        self.action = { 'desc' : "addVertex",
-                        'id'   : self.addVertex }
-        self.MapWindow.mouse['box'] = 'point'
-        
-    def OnRemoveVertex(self, event):
-        """!Remove line vertex"""
-        Debug.msg(2, "Digittoolbar.OnRemoveVertex():")
-        self.action = { 'desc' : "removeVertex",
-                        'id'   : self.removeVertex }
-        self.MapWindow.mouse['box'] = 'point'
-
-    def OnEditLine(self, event):
-        """!Edit line"""
-        Debug.msg(2, "Digittoolbar.OnEditLine():")
-        self.action = { 'desc' : "editLine",
-                        'id'   : self.editLine }
-        self.MapWindow.mouse['box'] = 'line'
-
-    def OnMoveLine(self, event):
-        """!Move line"""
-        Debug.msg(2, "Digittoolbar.OnMoveLine():")
-        self.action = { 'desc' : "moveLine",
-                        'id'   : self.moveLine }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnDeleteLine(self, event):
-        """!Delete line"""
-        Debug.msg(2, "Digittoolbar.OnDeleteLine():")
-        self.action = { 'desc' : "deleteLine",
-                        'id'   : self.deleteLine }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnDisplayCats(self, event):
-        """!Display/update categories"""
-        Debug.msg(2, "Digittoolbar.OnDisplayCats():")
-        self.action = { 'desc' : "displayCats",
-                        'id'   : self.displayCats }
-        self.MapWindow.mouse['box'] = 'point'
-
-    def OnDisplayAttr(self, event):
-        """!Display/update attributes"""
-        Debug.msg(2, "Digittoolbar.OnDisplayAttr():")
-        self.action = { 'desc' : "displayAttrs",
-                        'id'   : self.displayAttr }
-        self.MapWindow.mouse['box'] = 'point'
-        
-    def OnUndo(self, event):
-        """!Undo previous changes"""
-        self.digit.Undo()
-        
-        event.Skip()
-
-    def EnableUndo(self, enable = True):
-        """!Enable 'Undo' in toolbar
-        
-        @param enable False for disable
-        """
-        if enable:
-            if self.GetToolEnabled(self.undo) is False:
-                self.EnableTool(self.undo, True)
-        else:
-            if self.GetToolEnabled(self.undo) is True:
-                self.EnableTool(self.undo, False)
-        
-    def OnSettings(self, event):
-        """!Show settings dialog"""
-        if self.digit is None:
-            try:
-                self.digit = self.MapWindow.digit = VDigit(mapwindow = self.MapWindow)
-            except SystemExit:
-                self.digit = self.MapWindow.digit = None
-        
-        if not self.settingsDialog:
-            self.settingsDialog = VDigitSettingsDialog(parent = self.parent, title = _("Digitization settings"),
-                                                       style = wx.DEFAULT_DIALOG_STYLE)
-            self.settingsDialog.Show()
-
-    def OnAdditionalToolMenu(self, event):
-        """!Menu for additional tools"""
-        point = wx.GetMousePosition()
-        toolMenu = wx.Menu()
-        
-        for label, itype, handler, desc in (
-            (_('Break selected lines/boundaries at intersection'),
-             wx.ITEM_CHECK, self.OnBreak, "breakLine"),
-            (_('Connect selected lines/boundaries'),
-             wx.ITEM_CHECK, self.OnConnect, "connectLine"),
-            (_('Copy categories'),
-             wx.ITEM_CHECK, self.OnCopyCats, "copyCats"),
-            (_('Copy features from (background) vector map'),
-             wx.ITEM_CHECK, self.OnCopy, "copyLine"),
-            (_('Copy attributes'),
-             wx.ITEM_CHECK, self.OnCopyAttrb, "copyAttrs"),
-            (_('Feature type conversion'),
-             wx.ITEM_CHECK, self.OnTypeConversion, "typeConv"),
-            (_('Flip selected lines/boundaries'),
-             wx.ITEM_CHECK, self.OnFlip, "flipLine"),
-            (_('Merge selected lines/boundaries'),
-             wx.ITEM_CHECK, self.OnMerge, "mergeLine"),
-            (_('Snap selected lines/boundaries (only to nodes)'),
-             wx.ITEM_CHECK, self.OnSnap, "snapLine"),
-            (_('Split line/boundary'),
-             wx.ITEM_CHECK, self.OnSplitLine, "splitLine"),
-            (_('Query features'),
-             wx.ITEM_CHECK, self.OnQuery, "queryLine"),
-            (_('Z bulk-labeling of 3D lines'),
-             wx.ITEM_CHECK, self.OnZBulk, "zbulkLine")):
-            # Add items to the menu
-            item = wx.MenuItem(parentMenu = toolMenu, id = wx.ID_ANY,
-                               text = label,
-                               kind = itype)
-            toolMenu.AppendItem(item)
-            self.MapWindow.Bind(wx.EVT_MENU, handler, item)
-            if self.action['desc'] == desc:
-                item.Check(True)
-        
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.MapWindow.PopupMenu(toolMenu)
-        toolMenu.Destroy()
-        
-        if self.action['desc'] == 'addPoint':
-            self.ToggleTool(self.additionalTools, False)
-        
-    def OnCopy(self, event):
-        """!Copy selected features from (background) vector map"""
-        if self.action['desc'] == 'copyLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnCopy():")
-        self.action = { 'desc' : "copyLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnSplitLine(self, event):
-        """!Split line"""
-        if self.action['desc'] == 'splitLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnSplitLine():")
-        self.action = { 'desc' : "splitLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'point'
-
-
-    def OnCopyCats(self, event):
-        """!Copy categories"""
-        if self.action['desc'] == 'copyCats': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.copyCats, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnCopyCats():")
-        self.action = { 'desc' : "copyCats",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'point'
-
-    def OnCopyAttrb(self, event):
-        """!Copy attributes"""
-        if self.action['desc'] == 'copyAttrs': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.copyCats, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnCopyAttrb():")
-        self.action = { 'desc' : "copyAttrs",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'point'
-        
-
-    def OnFlip(self, event):
-        """!Flip selected lines/boundaries"""
-        if self.action['desc'] == 'flipLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnFlip():")
-        self.action = { 'desc' : "flipLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnMerge(self, event):
-        """!Merge selected lines/boundaries"""
-        if self.action['desc'] == 'mergeLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnMerge():")
-        self.action = { 'desc' : "mergeLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnBreak(self, event):
-        """!Break selected lines/boundaries"""
-        if self.action['desc'] == 'breakLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnBreak():")
-        self.action = { 'desc' : "breakLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnSnap(self, event):
-        """!Snap selected features"""
-        if self.action['desc'] == 'snapLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnSnap():")
-        self.action = { 'desc' : "snapLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnConnect(self, event):
-        """!Connect selected lines/boundaries"""
-        if self.action['desc'] == 'connectLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnConnect():")
-        self.action = { 'desc' : "connectLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnQuery(self, event):
-        """!Query selected lines/boundaries"""
-        if self.action['desc'] == 'queryLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnQuery(): %s" % \
-                      UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection'))
-        self.action = { 'desc' : "queryLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnZBulk(self, event):
-        """!Z bulk-labeling selected lines/boundaries"""
-        if not self.digit.IsVector3D():
-            GError(parent = self.parent,
-                   message = _("Vector map is not 3D. Operation canceled."))
-            return
-        
-        if self.action['desc'] == 'zbulkLine': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnZBulk():")
-        self.action = { 'desc' : "zbulkLine",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'line'
-
-    def OnTypeConversion(self, event):
-        """!Feature type conversion
-
-        Supported conversions:
-         - point <-> centroid
-         - line <-> boundary
-        """
-        if self.action['desc'] == 'typeConv': # select previous action
-            self.ToggleTool(self.addPoint, True)
-            self.ToggleTool(self.additionalTools, False)
-            self.OnAddPoint(event)
-            return
-        
-        Debug.msg(2, "Digittoolbar.OnTypeConversion():")
-        self.action = { 'desc' : "typeConv",
-                        'id'   : self.additionalTools }
-        self.MapWindow.mouse['box'] = 'box'
-
-    def OnSelectMap (self, event):
-        """!Select vector map layer for editing
-
-        If there is a vector map layer already edited, this action is
-        firstly terminated. The map layer is closed. After this the
-        selected map layer activated for editing.
-        """
-        if event.GetSelection() == 0: # create new vector map layer
-            if self.mapLayer:
-                openVectorMap = self.mapLayer.GetName(fullyQualified = False)['name']
-            else:
-                openVectorMap = None
-            dlg = CreateNewVector(self.parent,
-                                  exceptMap = openVectorMap, log = self.log,
-                                  cmd = (('v.edit',
-                                          { 'flags' : 'b', 'tool' : 'create' },
-                                          'map')),
-                                  disableAdd = True)
-            
-            if dlg and dlg.GetName():
-                # add layer to map layer tree
-                if self.layerTree:
-                    mapName = dlg.GetName() + '@' + grass.gisenv()['MAPSET']
-                    self.layerTree.AddLayer(ltype = 'vector',
-                                            lname = mapName,
-                                            lcmd = ['d.vect', 'map=%s' % mapName])
-                    
-                    vectLayers = self.UpdateListOfLayers(updateTool = True)
-                    selection = vectLayers.index(mapName)
-                
-                # create table ?
-                if dlg.IsChecked('table'):
-                    lmgr = self.parent.GetLayerManager()
-                    if lmgr:
-                        lmgr.OnShowAttributeTable(None, selection = 'table')
-                dlg.Destroy()
-            else:
-                self.combo.SetValue(_('Select vector map'))
-                if dlg:
-                    dlg.Destroy()
-                return
-        else:
-            selection = event.GetSelection() - 1 # first option is 'New vector map'
-        
-        # skip currently selected map
-        if self.layers[selection] == self.mapLayer:
-            return
-        
-        if self.mapLayer:
-            # deactive map layer for editing
-            self.StopEditing()
-        
-        # select the given map layer for editing
-        self.StartEditing(self.layers[selection])
-        
-        event.Skip()
-        
-    def StartEditing (self, mapLayer):
-        """!Start editing selected vector map layer.
-
-        @param mapLayer MapLayer to be edited
-        """
-        # deactive layer
-        self.Map.ChangeLayerActive(mapLayer, False)
-        
-        # clean map canvas
-        self.MapWindow.EraseMap()
-        
-        # unset background map if needed
-        if mapLayer:
-            if UserSettings.Get(group = 'vdigit', key = 'bgmap',
-                                subkey = 'value', internal = True) == mapLayer.GetName():
-                UserSettings.Set(group = 'vdigit', key = 'bgmap',
-                                 subkey = 'value', value = '', internal = True)
-            
-            self.parent.SetStatusText(_("Please wait, "
-                                        "opening vector map <%s> for editing...") % mapLayer.GetName(),
-                                        0)
-        
-        self.MapWindow.pdcVector = wx.PseudoDC()
-        self.digit = self.MapWindow.digit = VDigit(mapwindow = self.MapWindow)
-        
-        self.mapLayer = mapLayer
-        # open vector map
-        if self.digit.OpenMap(mapLayer.GetName()) is None:
-            self.mapLayer = None
-            self.StopEditing()
-            return False
-        
-        # check feature type (only for OGR layers)
-        fType = self.digit.GetFeatureType()
-        self.EnableAll()
-        self.EnableUndo(False)
-        
-        if fType == 'Point':
-            for tool in (self.addLine, self.addBoundary, self.addCentroid,
-                         self.addArea, self.moveVertex, self.addVertex,
-                         self.removeVertex, self.editLine):
-                self.EnableTool(tool, False)
-        elif fType == 'Line String':
-            for tool in (self.addPoint, self.addBoundary, self.addCentroid,
-                         self.addArea):
-                self.EnableTool(tool, False)
-        elif fType == 'Polygon':
-            for tool in (self.addPoint, self.addLine, self.addBoundary, self.addCentroid):
-                self.EnableTool(tool, False)
-        elif fType:
-            GError(parent = self,
-                   message = _("Unsupported feature type '%s'. Unable to edit "
-                               "OGR layer <%s>.") % (fType, mapLayer.GetName()))
-            self.digit.CloseMap()
-            self.mapLayer = None
-            self.StopEditing()
-            return False
-        
-        # update toolbar
-        if self.combo:
-            self.combo.SetValue(mapLayer.GetName())
-        if 'map' in self.parent.toolbars:
-            self.parent.toolbars['map'].combo.SetValue (_('Digitize'))
-        
-        if self.parent.GetName() != "IClassWindow":
-            lmgr = self.parent.GetLayerManager()
-            if lmgr:
-                lmgr.toolbars['tools'].Enable('vdigit', enable = False)
-        
-        Debug.msg (4, "VDigitToolbar.StartEditing(): layer=%s" % mapLayer.GetName())
-        
-        # change cursor
-        if self.MapWindow.mouse['use'] == 'pointer':
-            self.MapWindow.SetCursor(self.parent.cursors["cross"])
-        
-        if not self.MapWindow.resize:
-            self.MapWindow.UpdateMap(render = True)
-        
-        # respect opacity
-        opacity = mapLayer.GetOpacity(float = True)
-        
-        if opacity < 1.0:
-            alpha = int(opacity * 255)
-            self.digit.GetDisplay().UpdateSettings(alpha = alpha)
-        
-        return True
-
-    def StopEditing(self):
-        """!Stop editing of selected vector map layer.
-
-        @return True on success
-        @return False on failure
-        """
-        if self.combo:
-            self.combo.SetValue (_('Select vector map'))
-        
-        # save changes
-        if self.mapLayer:
-            Debug.msg (4, "VDigitToolbar.StopEditing(): layer=%s" % self.mapLayer.GetName())
-            if UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled') is False:
-                if self.digit.GetUndoLevel() > -1:
-                    dlg = wx.MessageDialog(parent = self.parent,
-                                           message = _("Do you want to save changes "
-                                                     "in vector map <%s>?") % self.mapLayer.GetName(),
-                                           caption = _("Save changes?"),
-                                           style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-                    if dlg.ShowModal() == wx.ID_NO:
-                        # revert changes
-                        self.digit.Undo(0)
-                    dlg.Destroy()
-            
-            self.parent.SetStatusText(_("Please wait, "
-                                        "closing and rebuilding topology of "
-                                        "vector map <%s>...") % self.mapLayer.GetName(),
-                                      0)
-            self.digit.CloseMap()
-            
-            lmgr = self.parent.GetLayerManager()
-            if lmgr:
-                lmgr.toolbars['tools'].Enable('vdigit', enable = True)
-                lmgr.GetLogWindow().GetProgressBar().SetValue(0)
-                lmgr.GetLogWindow().WriteCmdLog(_("Editing of vector map <%s> successfully finished") % \
-                                                    self.mapLayer.GetName(),
-                                                switchPage = False)
-            # re-active layer 
-            item = self.parent.tree.FindItemByData('maplayer', self.mapLayer)
-            if item and self.parent.tree.IsItemChecked(item):
-                self.Map.ChangeLayerActive(self.mapLayer, True)
-        
-        # change cursor
-        self.MapWindow.SetCursor(self.parent.cursors["default"])
-        self.MapWindow.pdcVector = None
-        
-        # close dialogs
-        for dialog in ('attributes', 'category'):
-            if self.parent.dialogs[dialog]:
-                self.parent.dialogs[dialog].Close()
-                self.parent.dialogs[dialog] = None
-        
-        del self.digit
-        del self.MapWindow.digit
-        
-        self.mapLayer = None
-        
-        self.MapWindow.redrawAll = True
-        
-        return True
-    
-    def UpdateListOfLayers (self, updateTool = False):
-        """!Update list of available vector map layers.
-        This list consists only editable layers (in the current mapset)
-
-        @param updateTool True to update also toolbar
-        """
-        Debug.msg (4, "VDigitToolbar.UpdateListOfLayers(): updateTool=%d" % \
-                   updateTool)
-        
-        layerNameSelected = None
-         # name of currently selected layer
-        if self.mapLayer:
-            layerNameSelected = self.mapLayer.GetName()
-        
-        # select vector map layer in the current mapset
-        layerNameList = []
-        self.layers = self.Map.GetListOfLayers(l_type = "vector",
-                                                      l_mapset = grass.gisenv()['MAPSET'])
-        
-        for layer in self.layers:
-            if not layer.name in layerNameList: # do not duplicate layer
-                layerNameList.append (layer.GetName())
-        
-        if updateTool: # update toolbar
-            if not self.mapLayer:
-                value = _('Select vector map')
-            else:
-                value = layerNameSelected
-            
-            if not self.comboid:
-                if not self.tools or 'selector' in self.tools:
-                    self.combo = wx.ComboBox(self, id = wx.ID_ANY, value = value,
-                                             choices = [_('New vector map'), ] + layerNameList, size = (80, -1),
-                                             style = wx.CB_READONLY)
-                    self.comboid = self.InsertControl(0, self.combo)
-                    self.parent.Bind(wx.EVT_COMBOBOX, self.OnSelectMap, self.comboid)
-            else:
-                self.combo.SetItems([_('New vector map'), ] + layerNameList)
-            
-            self.Realize()
-        
-        return layerNameList
-
-    def GetLayer(self):
-        """!Get selected layer for editing -- MapLayer instance"""
-        return self.mapLayer
-    
-class ProfileToolbar(AbstractToolbar):
-    """!Toolbar for profiling raster map
-    """ 
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['plot']
-        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
-                                      self.parent.OnSelectRaster),
-                                     ('transect', icons["transect"],
-                                      self.parent.OnDrawTransect),
-                                     (None, ),
-                                     ('draw', icons["draw"],
-                                      self.parent.OnCreateProfile),
-                                     ('erase', Icons['displayWindow']["erase"],
-                                      self.parent.OnErase),
-                                     ('drag', Icons['displayWindow']['pan'],
-                                      self.parent.OnDrag),
-                                     ('zoom', Icons['displayWindow']['zoomIn'],
-                                      self.parent.OnZoom),
-                                     ('unzoom', Icons['displayWindow']['zoomBack'],
-                                      self.parent.OnRedraw),
-                                     (None, ),
-                                     ('statistics', icons['statistics'],
-                                      self.parent.OnStats),
-                                     ('datasave', icons["save"],
-                                      self.parent.SaveProfileToFile),
-                                     ('image', Icons['displayWindow']["saveFile"],
-                                      self.parent.SaveToFile),
-                                     ('print', Icons['displayWindow']["print"],
-                                      self.parent.PrintMenu),
-                                     (None, ),
-                                     ('settings', icons["options"],
-                                      self.parent.PlotOptionsMenu),
-                                     ('quit', icons["quit"],
-                                      self.parent.OnQuit),
-                                     ))
-    
-class LMNvizToolbar(AbstractToolbar):
-    """!Nviz toolbar
-    """
-    def __init__(self, parent):
-        self.lmgr = parent
-        
-        AbstractToolbar.__init__(self, parent)
-        
-        # only one dialog can be open
-        self.settingsDialog   = None
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['nviz']
-        return self._getToolbarData((("nvizCmd", icons['nvizCmd'],
-                                      self.OnNvizCmd),
-                                     (None, ),
-                                     ("settings", icons["settings"],
-                                      self.OnSettings),
-                                     ("help", icons["help"],
-                                      self.OnHelp))
-                                    )
-        
-    def OnNvizCmd(self, event):
-        """!Show m.nviz.image command"""
-        self.lmgr.GetLayerTree().GetMapDisplay().GetWindow().OnNvizCmd()
-        
-    def OnHelp(self, event):
-        """!Show 3D view mode help"""
-        if not self.lmgr:
-            RunCommand('g.manual',
-                       entry = 'wxGUI.Nviz')
-        else:
-            log = self.lmgr.GetLogWindow()
-            log.RunCmd(['g.manual',
-                        'entry=wxGUI.Nviz'])
-        
-    def OnSettings(self, event):
-        """!Show nviz notebook page"""
-        if not self.settingsDialog:
-            self.settingsDialog = NvizPreferencesDialog(parent = self.parent)
-        self.settingsDialog.Show()
-        
-class ModelToolbar(AbstractToolbar):
-    """!Graphical modeler toolbar (see gmodeler.py)
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['modeler']
-        return self._getToolbarData((('new', icons['new'],
-                                      self.parent.OnModelNew),
-                                     ('open', icons['open'],
-                                      self.parent.OnModelOpen),
-                                     ('save', icons['save'],
-                                      self.parent.OnModelSave),
-                                     ('image', icons['toImage'],
-                                      self.parent.OnExportImage),
-                                     ('python', icons['toPython'],
-                                      self.parent.OnExportPython),
-                                     (None, ),
-                                     ('action', icons['actionAdd'],
-                                      self.parent.OnAddAction),
-                                     ('data', icons['dataAdd'],
-                                      self.parent.OnAddData),
-                                     ('relation', icons['relation'],
-                                      self.parent.OnDefineRelation),
-                                     ('loop', icons['loop'],
-                                      self.parent.OnDefineLoop),
-                                     (None, ),
-                                     ('redraw', icons['redraw'],
-                                      self.parent.OnCanvasRefresh),
-                                     ('validate', icons['validate'],
-                                      self.parent.OnValidateModel),
-                                     ('run', icons['run'],
-                                      self.parent.OnRunModel),
-                                     (None, ),
-                                     ("variables", icons['variables'],
-                                      self.parent.OnVariables),
-                                     ("settings", icons['settings'],
-                                      self.parent.OnPreferences),
-                                     ("help", Icons['misc']['help'],
-                                      self.parent.OnHelp),
-                                     (None, ),
-                                     ('quit', icons['quit'],
-                                      self.parent.OnCloseWindow))
-                                    )
-    
-class HistogramToolbar(AbstractToolbar):
-    """!Histogram toolbar (see histogram.py)
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['displayWindow']
-        return self._getToolbarData((('histogram', icons["histogram"],
-                                      self.parent.OnOptions),
-                                     ('rendermao', icons["display"],
-                                      self.parent.OnRender),
-                                     ('erase', icons["erase"],
-                                      self.parent.OnErase),
-                                     ('font', Icons['misc']["font"],
-                                      self.parent.SetHistFont),
-                                     (None, ),
-                                     ('save', icons["saveFile"],
-                                      self.parent.SaveToFile),
-                                     ('hprint', icons["print"],
-                                      self.parent.PrintMenu),
-                                     (None, ),
-                                     ('quit', Icons['misc']["quit"],
-                                      self.parent.OnQuit))
-                                    )
-
-class Histogram2Toolbar(AbstractToolbar):
-    """!Toolbar for histogramming raster map
-    """ 
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['plot']
-        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
-                                      self.parent.OnSelectRaster),
-                                     (None, ),
-                                     ('draw', icons["draw"],
-                                      self.parent.OnCreateHist),
-                                     ('erase', Icons['displayWindow']["erase"],
-                                      self.parent.OnErase),
-                                     ('drag', Icons['displayWindow']['pan'],
-                                      self.parent.OnDrag),
-                                     ('zoom', Icons['displayWindow']['zoomIn'],
-                                      self.parent.OnZoom),
-                                     ('unzoom', Icons['displayWindow']['zoomBack'],
-                                      self.parent.OnRedraw),
-                                     (None, ),
-                                     ('statistics', icons['statistics'],
-                                      self.parent.OnStats),
-                                     ('image', Icons['displayWindow']["saveFile"],
-                                      self.parent.SaveToFile),
-                                     ('print', Icons['displayWindow']["print"],
-                                      self.parent.PrintMenu),
-                                     (None, ),
-                                     ('settings', icons["options"],
-                                      self.parent.PlotOptionsMenu),
-                                     ('quit', icons["quit"],
-                                      self.parent.OnQuit),
-                                     ))
-
-class ScatterplotToolbar(AbstractToolbar):
-    """!Toolbar for bivariate scatterplots of raster map pairs
-    """ 
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-        
-    def _toolbarData(self):
-        """!Toolbar data"""
-        icons = Icons['plot']
-#        icons2 = Icons['modeler']
-        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
-                                      self.parent.OnSelectRaster),
-                                     (None, ),
-                                     ('draw', icons["draw"],
-                                      self.parent.OnCreateScatter),
-                                     ('erase', Icons['displayWindow']["erase"],
-                                      self.parent.OnErase),
-                                     ('drag', Icons['displayWindow']['pan'],
-                                      self.parent.OnDrag),
-                                     ('zoom', Icons['displayWindow']['zoomIn'],
-                                      self.parent.OnZoom),
-                                     ('unzoom', Icons['displayWindow']['zoomBack'],
-                                      self.parent.OnRedraw),
-                                     (None, ),
-                                     ('statistics', icons['statistics'],
-                                      self.parent.OnRegression),
-                                     ('image', Icons['displayWindow']["saveFile"],
-                                      self.parent.SaveToFile),
-                                     ('print', Icons['displayWindow']["print"],
-                                      self.parent.PrintMenu),
-                                     (None, ),
-                                     ('settings', icons["options"],
-                                      self.parent.PlotOptionsMenu),
-                                     ('quit', icons["quit"],
-                                      self.parent.OnQuit),
-                                     ))
-
-class LMWorkspaceToolbar(AbstractToolbar):
-    """!Layer Manager `workspace` toolbar
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['layerManager']
-        return self._getToolbarData((('newdisplay', icons["newdisplay"],
-                                      self.parent.OnNewDisplay),
-                                     (None, ),
-                                     ('workspaceNew', icons["workspaceNew"],
-                                      self.parent.OnWorkspaceNew),
-                                     ('workspaceOpen', icons["workspaceOpen"],
-                                      self.parent.OnWorkspaceOpen),
-                                     ('workspaceSave', icons["workspaceSave"],
-                                      self.parent.OnWorkspaceSave),
-                                     ))
-
-class LMDataToolbar(AbstractToolbar):
-    """!Layer Manager `data` toolbar
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['layerManager']
-        return self._getToolbarData((('addMulti', icons["addMulti"],
-                                      self.parent.OnAddMaps),
-                                     ('addrast', icons["addRast"],
-                                      self.parent.OnAddRaster),
-                                     ('rastmisc', icons["rastMisc"],
-                                      self.parent.OnAddRasterMisc),
-                                     ('addvect', icons["addVect"],
-                                      self.parent.OnAddVector),
-                                     ('vectmisc', icons["vectMisc"],
-                                      self.parent.OnAddVectorMisc),
-                                     ('addgrp',  icons["addGroup"],
-                                      self.parent.OnAddGroup),
-                                     ('addovl',  icons["addOverlay"],
-                                      self.parent.OnAddOverlay),
-                                     ('delcmd',  icons["delCmd"],
-                                      self.parent.OnDeleteLayer),
-                                     ))
-
-class LMToolsToolbar(AbstractToolbar):
-    """!Layer Manager `tools` toolbar
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['layerManager']
-        return self._getToolbarData((('importMap', icons["import"],
-                                      self.parent.OnImportMenu),
-                                     (None, ),
-                                     ('mapCalc', icons["mapcalc"],
-                                      self.parent.OnMapCalculator),
-                                     ('georect', Icons["georectify"]["georectify"],
-                                      self.parent.OnGCPManager),
-                                     ('modeler', icons["modeler"],
-                                      self.parent.OnGModeler),
-                                     ('mapOutput', icons['mapOutput'],
-                                      self.parent.OnPsMap)
-                                     ))
-
-class LMMiscToolbar(AbstractToolbar):
-    """!Layer Manager `misc` toolbar
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['layerManager']
-        return self._getToolbarData((('settings', icons["settings"],
-                                      self.parent.OnPreferences),
-                                     ('help', Icons["misc"]["help"],
-                                      self.parent.OnHelp),
-                                     ))
-
-class LMVectorToolbar(AbstractToolbar):
-    """!Layer Manager `vector` toolbar
-    """
-    def __init__(self, parent):
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        # realize the toolbar
-        self.Realize()
-
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['layerManager']
-        return self._getToolbarData((('vdigit', icons["vdigit"],
-                                      self.parent.OnVDigit),
-                                     ('attribute', icons["attrTable"],
-                                      self.parent.OnShowAttributeTable),
-                                     ))
-    
-class PsMapToolbar(AbstractToolbar):
-    def __init__(self, parent):
-        """!Toolbar Cartographic Composer (psmap.py)
-        
-        @param parent parent window
-        """
-        AbstractToolbar.__init__(self, parent)
-        
-        self.InitToolbar(self._toolbarData())
-        
-        self.Realize()
-        
-        self.action = { 'id' : self.pointer }
-        self.defaultAction = { 'id' : self.pointer,
-                               'bind' : self.parent.OnPointer }
-        self.OnTool(None)
-        
-        from psmap import havePILImage
-        if not havePILImage:
-            self.EnableTool(self.preview, False)
-        
-    def _toolbarData(self):
-        """!Toolbar data
-        """
-        icons = Icons['psMap']
-        return self._getToolbarData((('loadFile', icons['scriptLoad'],
-                                      self.parent.OnLoadFile),                                    
-                                     ('instructionFile', icons['scriptSave'],
-                                      self.parent.OnInstructionFile),
-                                     (None, ),
-                                     ('pagesetup', icons['pageSetup'],
-                                      self.parent.OnPageSetup),
-                                     (None, ),
-                                     ("pointer", Icons["displayWindow"]["pointer"],
-                                      self.parent.OnPointer, wx.ITEM_CHECK),
-                                     ('pan', Icons["displayWindow"]['pan'],
-                                      self.parent.OnPan, wx.ITEM_CHECK),
-                                     ("zoomin", Icons["displayWindow"]["zoomIn"],
-                                      self.parent.OnZoomIn, wx.ITEM_CHECK),
-                                     ("zoomout", Icons["displayWindow"]["zoomOut"],
-                                      self.parent.OnZoomOut, wx.ITEM_CHECK),
-                                     ('zoomAll', icons['fullExtent'],
-                                      self.parent.OnZoomAll),
-                                     (None, ),
-                                     ('addMap', icons['addMap'],
-                                      self.parent.OnAddMap, wx.ITEM_CHECK),
-                                     ('addRaster', icons['addRast'],
-                                      self.parent.OnAddRaster),
-                                     ('addVector', icons['addVect'],
-                                      self.parent.OnAddVect),
-                                     ("dec", Icons["displayWindow"]["overlay"],
-                                      self.parent.OnDecoration),
-                                     ("delete", icons["deleteObj"],
-                                      self.parent.OnDelete),
-                                     (None, ),
-                                     ("preview", icons["preview"],
-                                      self.parent.OnPreview),
-                                     ('generatePS', icons['psExport'],
-                                      self.parent.OnPSFile),
-                                     ('generatePDF', icons['pdfExport'],
-                                      self.parent.OnPDFFile),
-                                     (None, ),
-                                     ("help", Icons['misc']['help'],
-                                      self.parent.OnHelp),
-                                     ('quit', icons['quit'],
-                                      self.parent.OnCloseWindow))
-                                    )

Deleted: grass/trunk/gui/wxpython/gui_modules/units.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/units.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/units.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,118 +0,0 @@
-"""!
- at package units
-
- at brief Units management
-
-Probably will be replaced by Python SWIG fns in the near future(?)
-
-Usage:
-
- at code
-from units import Units
- at endcode
-
-Classes:
- - BaseUnits
-
-(C) 2009 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-class BaseUnits:
-    def __init__(self):
-        self._units = dict()
-        self._units['length'] = { 0 : { 'key' : 'mu', 'label' : _('map units') },
-                             1 : { 'key' : 'me', 'label' : _('meters') },
-                             2 : { 'key' : 'km', 'label' : _('kilometers') },
-                             3 : { 'key' : 'mi', 'label' : _('miles') },
-                             4 : { 'key' : 'ft', 'label' : _('feet') } }
-        
-        self._units['area']   = { 0 : { 'key' : 'mu', 'label' : _('sq map units') },
-                             1 : { 'key' : 'me', 'label' : _('sq meters') },
-                             2 : { 'key' : 'km', 'label' : _('sq kilometers') },
-                             3 : { 'key' : 'ar', 'label' : _('acres') },
-                             4 : { 'key' : 'ht', 'label' : _('hectares') } }
-
-    def GetUnitsList(self, type):
-        """!Get list of units (their labels)
-        
-        @param type units type ('length' or 'area')
-        
-        @return list of units labels
-        """
-        result = list()
-        try:
-            keys = self._units[type].keys()
-            keys.sort()
-            for idx in keys:
-                result.append(self._units[type][idx]['label'])
-        except KeyError:
-            pass
-        
-        return result
-
-    def GetUnitsKey(self, type, index):
-        """!Get units key based on index
-        
-        @param type units type ('length' or 'area')
-        @param index units index
-        """
-        return self._units[type][index]['key']
-
-    def GetUnitsIndex(self, type, key):
-        """!Get units index based on key
-        
-        @param type units type ('length' or 'area')
-        @param key units key, e.g. 'me' for meters
-
-        @return index
-        """
-        for k, u in self._units[type].iteritems():
-            if u['key'] == key:
-                return k
-        return 0
-
-Units = BaseUnits()
-
-def ConvertValue(value, type, units):
-    """!Convert value from map units to given units
-
-    Inspired by vector/v.to.db/units.c
-
-    @param value value to be converted
-    @param type units type ('length', 'area')
-    @param unit  destination units
-    """
-    # get map units
-    # TODO
-    
-    f = 1
-    if type == 'length':
-        if units == 'me':
-            f = 1.0
-        elif units == 'km':
-            f = 1.0e-3
-        elif units == 'mi':
-            f = 6.21371192237334e-4
-        elif units == 'ft':
-            f = 3.28083989501312
-    else: # -> area
-        if units == 'me':
-            f = 1.0
-        elif units == 'km':
-            f = 1.0e-6
-        elif units == 'mi':
-            f = 3.86102158542446e-7
-        elif units == 'ft':
-            f = 10.7639104167097
-        elif units == 'ar':
-            f = 2.47105381467165e-4
-        elif units == 'ht':
-            f = 1.0e-4
-
-    return f * value

Deleted: grass/trunk/gui/wxpython/gui_modules/utils.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/utils.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/utils.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,780 +0,0 @@
-"""!
- at package utils.py
-
- at brief Misc utilities for wxGUI
-
-(C) 2007-2009, 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
- at author Jachym Cepicky
-"""
-
-import os
-import sys
-import platform
-import string
-import glob
-import locale
-import shlex
-import re
-
-import globalvar
-sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
-
-from grass.script import core as grass
-from grass.script import task as gtask
-
-import gcmd
-from debug import Debug
-
-def normalize_whitespace(text):
-    """!Remove redundant whitespace from a string"""
-    return string.join(string.split(text), ' ')
-
-def split(s):
-    """!Platform spefic shlex.split"""
-    if sys.version_info >= (2, 6):
-        return shlex.split(s, posix = (sys.platform != "win32"))
-    elif sys.platform == "win32":
-        return shlex.split(s.replace('\\', r'\\'))
-    else:
-        return shlex.split(s)
-
-def GetTempfile(pref=None):
-    """!Creates GRASS temporary file using defined prefix.
-
-    @todo Fix path on MS Windows/MSYS
-
-    @param pref prefer the given path
-
-    @return Path to file name (string) or None
-    """
-    import gcmd
-    
-    ret = gcmd.RunCommand('g.tempfile',
-                          read = True,
-                          pid = os.getpid())
-
-    tempfile = ret.splitlines()[0].strip()
-
-    # FIXME
-    # ugly hack for MSYS (MS Windows)
-    if platform.system() == 'Windows':
-	tempfile = tempfile.replace("/", "\\")
-    try:
-        path, file = os.path.split(tempfile)
-        if pref:
-            return os.path.join(pref, file)
-	else:
-	    return tempfile
-    except:
-        return None
-
-def GetLayerNameFromCmd(dcmd, fullyQualified = False, param = None,
-                        layerType = None):
-    """!Get map name from GRASS command
-    
-    Parameter dcmd can be modified when first parameter is not
-    defined.
-    
-    @param dcmd GRASS command (given as list)
-    @param fullyQualified change map name to be fully qualified
-    @param param params directory
-    @param layerType check also layer type ('raster', 'vector', '3d-raster', ...)
-    
-    @return tuple (name, found)
-    """
-    mapname = ''
-    found   = True
-    
-    if len(dcmd) < 1:
-        return mapname, False
-    
-    if 'd.grid' == dcmd[0]:
-        mapname = 'grid'
-    elif 'd.geodesic' in dcmd[0]:
-        mapname = 'geodesic'
-    elif 'd.rhumbline' in dcmd[0]:
-        mapname = 'rhumb'
-    else:
-        params = list()
-        for idx in range(len(dcmd)):
-            try:
-                p, v = dcmd[idx].split('=', 1)
-            except ValueError:
-                continue
-            
-            if p == param:
-                params = [(idx, p, v)]
-                break
-            
-            if p in ('map', 'input', 'layer',
-                     'red', 'blue', 'green',
-                     'h_map', 's_map', 'i_map',
-                     'reliefmap', 'labels'):
-                params.append((idx, p, v))
-        
-        if len(params) < 1:
-            if len(dcmd) > 1 and '=' not in dcmd[1]:
-                task = gtask.parse_interface(dcmd[0])
-                p = task.get_options()['params'][0].get('name', '')
-                params.append((1, p, dcmd[1]))
-            else:
-                return mapname, False
-        
-        mapname = params[0][2]
-        mapset = ''
-        if fullyQualified and '@' not in mapname:
-            if layerType in ('raster', 'vector', '3d-raster', 'rgb', 'his'):
-                try:
-                    if layerType in ('raster', 'rgb', 'his'):
-                        findType = 'cell'
-                    else:
-                        findType = layerType
-                    mapset = grass.find_file(mapname, element = findType)['mapset']
-                except AttributeError, e: # not found
-                    return '', False
-                if not mapset:
-                    found = False
-            else:
-                mapset = grass.gisenv()['MAPSET']
-            
-            # update dcmd
-            for i, p, v in params:
-                if p == 'layer':
-                    continue
-                dcmd[i] = p + '=' + v
-                if mapset:
-                    dcmd[i] += '@' + mapset
-        
-        maps = list()
-        ogr = False
-        for i, p, v in params:
-            if v.lower().rfind('@ogr') > -1:
-                ogr = True
-            if p == 'layer' and not ogr:
-                continue
-            maps.append(dcmd[i].split('=', 1)[1])
-        
-        mapname = '\n'.join(maps)
-    
-    return mapname, found
-
-def GetValidLayerName(name):
-    """!Make layer name SQL compliant, based on G_str_to_sql()
-    
-    @todo: Better use directly GRASS Python SWIG...
-    """
-    retName = str(name).strip()
-    
-    # check if name is fully qualified
-    if '@' in retName:
-        retName, mapset = retName.split('@')
-    else:
-        mapset = None
-    
-    cIdx = 0
-    retNameList = list(retName)
-    for c in retNameList:
-        if not (c >= 'A' and c <= 'Z') and \
-               not (c >= 'a' and c <= 'z') and \
-               not (c >= '0' and c <= '9'):
-            retNameList[cIdx] = '_'
-        cIdx += 1
-    retName = ''.join(retNameList)
-    
-    if not (retName[0] >= 'A' and retName[0] <= 'Z') and \
-           not (retName[0] >= 'a' and retName[0] <= 'z'):
-        retName = 'x' + retName[1:]
-
-    if mapset:
-        retName = retName + '@' + mapset
-        
-    return retName
-
-def ListOfCatsToRange(cats):
-    """!Convert list of category number to range(s)
-
-    Used for example for d.vect cats=[range]
-
-    @param cats category list
-
-    @return category range string
-    @return '' on error
-    """
-
-    catstr = ''
-
-    try:
-        cats = map(int, cats)
-    except:
-        return catstr
-
-    i = 0
-    while i < len(cats):
-        next = 0
-        j = i + 1
-        while j < len(cats):
-            if cats[i + next] == cats[j] - 1:
-                next += 1
-            else:
-                break
-            j += 1
-
-        if next > 1:
-            catstr += '%d-%d,' % (cats[i], cats[i + next])
-            i += next + 1
-        else:
-            catstr += '%d,' % (cats[i])
-            i += 1
-        
-    return catstr.strip(',')
-
-def ListOfMapsets(get = 'ordered'):
-    """!Get list of available/accessible mapsets
-
-    @param get method ('all', 'accessible', 'ordered')
-    
-    @return list of mapsets
-    @return None on error
-    """
-    mapsets = []
-    
-    if get == 'all' or get == 'ordered':
-        ret = gcmd.RunCommand('g.mapsets',
-                              read = True,
-                              quiet = True,
-                              flags = 'l',
-                              fs = 'newline')
-        
-        if ret:
-            mapsets = ret.splitlines()
-            ListSortLower(mapsets)
-        else:
-            return None
-        
-    if get == 'accessible' or get == 'ordered':
-        ret = gcmd.RunCommand('g.mapsets',
-                              read = True,
-                              quiet = True,
-                              flags = 'p',
-                              fs = 'newline')
-        if ret:
-            if get == 'accessible':
-                mapsets = ret.splitlines()
-            else:
-                mapsets_accessible = ret.splitlines()
-                for mapset in mapsets_accessible:
-                    mapsets.remove(mapset)
-                mapsets = mapsets_accessible + mapsets
-        else:
-            return None
-    
-    return mapsets
-
-def ListSortLower(list):
-    """!Sort list items (not case-sensitive)"""
-    list.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
-
-def GetVectorNumberOfLayers(parent, vector):
-    """!Get list of vector layers"""
-    layers = list()
-    if not vector:
-        return layers
-    
-    fullname = grass.find_file(name = vector, element = 'vector')['fullname']
-    if not fullname:
-        Debug.msg(5, "utils.GetVectorNumberOfLayers(): vector map '%s' not found" % vector)
-        return layers
-    
-    ret, out, msg = gcmd.RunCommand('v.db.connect',
-                                    getErrorMsg = True,
-                                    read = True,
-                                    flags = 'g',
-                                    map = fullname,
-                                    fs = ';')
-    if ret != 0:
-        sys.stderr.write(_("Vector map <%(map)s>: %(msg)s\n") % { 'map' : fullname, 'msg' : msg })
-        return layers
-    else:
-        Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret)
-    
-    for line in ret.splitlines():
-        try:
-            layer = line.split(';')[0]
-            if '/' in layer:
-                layer = layer.split('/')[0]
-            layers.append(layer)
-        except IndexError:
-            pass
-    
-    Debug.msg(3, "utils.GetVectorNumberOfLayers(): vector=%s -> %s" % \
-                  (fullname, ','.join(layers)))
-    
-    return layers
-
-def Deg2DMS(lon, lat, string = True, hemisphere = True, precision = 3):
-    """!Convert deg value to dms string
-
-    @param lon longitude (x)
-    @param lat latitude (y)
-    @param string True to return string otherwise tuple
-    @param hemisphere print hemisphere
-    @param precision seconds precision
-    
-    @return DMS string or tuple of values
-    @return empty string on error
-    """
-    try:
-        flat = float(lat)
-        flon = float(lon)
-    except ValueError:
-        if string:
-            return ''
-        else:
-            return None
-
-    # fix longitude
-    while flon > 180.0:
-        flon -= 360.0
-    while flon < -180.0:
-        flon += 360.0
-
-    # hemisphere
-    if hemisphere:
-        if flat < 0.0:
-            flat = abs(flat)
-            hlat = 'S'
-        else:
-            hlat = 'N'
-
-        if flon < 0.0:
-            hlon = 'W'
-            flon = abs(flon)
-        else:
-            hlon = 'E'
-    else:
-        flat = abs(flat)
-        flon = abs(flon)
-        hlon = ''
-        hlat = ''
-    
-    slat = __ll_parts(flat, precision = precision)
-    slon = __ll_parts(flon, precision = precision)
-
-    if string:
-        return slon + hlon + '; ' + slat + hlat
-    
-    return (slon + hlon, slat + hlat)
-
-def DMS2Deg(lon, lat):
-    """!Convert dms value to deg
-
-    @param lon longitude (x)
-    @param lat latitude (y)
-    
-    @return tuple of converted values
-    @return ValueError on error
-    """
-    x = __ll_parts(lon, reverse = True)
-    y = __ll_parts(lat, reverse = True)
-    
-    return (x, y)
-
-def __ll_parts(value, reverse = False, precision = 3):
-    """!Converts deg to d:m:s string
-
-    @param value value to be converted
-    @param reverse True to convert from d:m:s to deg
-    @param precision seconds precision (ignored if reverse is True)
-    
-    @return converted value (string/float)
-    @return ValueError on error (reverse == True)
-    """
-    if not reverse:
-        if value == 0.0:
-            return '%s%.*f' % ('00:00:0', precision, 0.0)
-    
-        d = int(int(value))
-        m = int((value - d) * 60)
-        s = ((value - d) * 60 - m) * 60
-        if m < 0:
-            m = '00'
-        elif m < 10:
-            m = '0' + str(m)
-        else:
-            m = str(m)
-        if s < 0:
-            s = '00.0000'
-        elif s < 10.0:
-            s = '0%.*f' % (precision, s)
-        else:
-            s = '%.*f' % (precision, s)
-        
-        return str(d) + ':' + m + ':' + s
-    else: # -> reverse
-        try:
-            d, m, s = value.split(':')
-            hs = s[-1]
-            s = s[:-1]
-        except ValueError:
-            try:
-                d, m = value.split(':')
-                hs = m[-1]
-                m = m[:-1]
-                s = '0.0'
-            except ValueError:
-                try:
-                    d = value
-                    hs = d[-1]
-                    d = d[:-1]
-                    m = '0'
-                    s = '0.0'
-                except ValueError:
-                    raise ValueError
-        
-        if hs not in ('N', 'S', 'E', 'W'):
-            raise ValueError
-        
-        coef = 1.0
-        if hs in ('S', 'W'):
-            coef = -1.0
-        
-        fm = int(m) / 60.0
-        fs = float(s) / (60 * 60)
-        
-        return coef * (float(d) + fm + fs)
-    
-def GetCmdString(cmd):
-    """
-    Get GRASS command as string.
-    
-    @param cmd GRASS command given as dictionary
-    
-    @return command string
-    """
-    scmd = ''
-    if not cmd:
-        return scmd
-    
-    scmd = cmd[0]
-    
-    if 'flags' in cmd[1]:
-        for flag in cmd[1]['flags']:
-            scmd += ' -' + flag
-    for flag in ('verbose', 'quiet', 'overwrite'):
-        if flag in cmd[1] and cmd[1][flag] is True:
-            scmd += ' --' + flag
-    
-    for k, v in cmd[1].iteritems():
-        if k in ('flags', 'verbose', 'quiet', 'overwrite'):
-            continue
-        scmd += ' %s=%s' % (k, v)
-            
-    return scmd
-
-def CmdToTuple(cmd):
-    """!Convert command list to tuple for gcmd.RunCommand()"""
-    if len(cmd) < 1:
-        return None
-        
-    dcmd = {}
-    for item in cmd[1:]:
-        if '=' in item: # params
-            key, value = item.split('=', 1)
-            dcmd[str(key)] = str(value).replace('"', '')
-        elif item[:2] == '--': # long flags
-            flag = item[2:]
-            if flag in ('verbose', 'quiet', 'overwrite'):
-                dcmd[str(flag)] = True
-        else: # -> flags
-            if 'flags' not in dcmd:
-                dcmd['flags'] = ''
-            dcmd['flags'] += item.replace('-', '')
-                
-    return (cmd[0],
-            dcmd)
-
-def PathJoin(*args):
-    """!Check path created by os.path.join"""
-    path = os.path.join(*args)
-    if platform.system() == 'Windows' and \
-            '/' in path:
-        return path[1].upper() + ':\\' + path[3:].replace('/', '\\')
-    
-    return path
-
-def ReadEpsgCodes(path):
-    """!Read EPSG code from the file
-
-    @param path full path to the file with EPSG codes
-
-    @return dictionary of EPSG code
-    @return string on error
-    """
-    epsgCodeDict = dict()
-    try:
-        try:
-            f = open(path, "r")
-        except IOError:
-            return _("failed to open '%s'" % path)
-        
-        i = 0
-        code = None
-        for line in f.readlines():
-            line = line.strip()
-            if len(line) < 1:
-                continue
-                
-            if line[0] == '#':
-                descr = line[1:].strip()
-            elif line[0] == '<':
-                code, params = line.split(" ", 1)
-                try:
-                    code = int(code.replace('<', '').replace('>', ''))
-                except ValueError:
-                    return e
-            
-            if code is not None:
-                epsgCodeDict[code] = (descr, params)
-                code = None
-            i += 1
-        
-        f.close()
-    except StandardError, e:
-        return e
-    
-    return epsgCodeDict
-
-def ReprojectCoordinates(coord, projOut, projIn = None, flags = ''):
-    """!Reproject coordinates
-
-    @param coord coordinates given as tuple
-    @param projOut output projection
-    @param projIn input projection (use location projection settings)
-
-    @return reprojected coordinates (returned as tuple)
-    """
-    coors = gcmd.RunCommand('m.proj',
-                            flags = flags,
-                            input = '-',
-                            proj_input = projIn,
-                            proj_output = projOut,
-                            fs = ';',
-                            stdin = '%f;%f' % (coord[0], coord[1]),
-                            read = True)
-    if coors:
-        coors = coors.split(';')
-        e = coors[0]
-        n = coors[1]
-        try:
-            proj = projOut.split(' ')[0].split('=')[1]
-        except IndexError:
-            proj = ''
-        if proj in ('ll', 'latlong', 'longlat') and 'd' not in flags:
-            return (proj, (e, n))
-        else:
-            try:
-                return (proj, (float(e), float(n)))
-            except ValueError:
-                return (None, None)
-    
-    return (None, None)
-
-def GetListOfLocations(dbase):
-    """!Get list of GRASS locations in given dbase
-
-    @param dbase GRASS database path
-
-    @return list of locations (sorted)
-    """
-    listOfLocations = list()
-
-    try:
-        for location in glob.glob(os.path.join(dbase, "*")):
-            try:
-                if os.path.join(location, "PERMANENT") in glob.glob(os.path.join(location, "*")):
-                    listOfLocations.append(os.path.basename(location))
-            except:
-                pass
-    except UnicodeEncodeError, e:
-        raise e
-    
-    ListSortLower(listOfLocations)
-    
-    return listOfLocations
-
-def GetListOfMapsets(dbase, location, selectable = False):
-    """!Get list of mapsets in given GRASS location
-
-    @param dbase      GRASS database path
-    @param location   GRASS location
-    @param selectable True to get list of selectable mapsets, otherwise all
-
-    @return list of mapsets - sorted (PERMANENT first)
-    """
-    listOfMapsets = list()
-    
-    if selectable:
-        ret = gcmd.RunCommand('g.mapset',
-                              read = True,
-                              flags = 'l',
-                              location = location,
-                              gisdbase = dbase)
-        
-        if not ret:
-            return listOfMapsets
-        
-        for line in ret.rstrip().splitlines():
-            listOfMapsets += line.split(' ')
-    else:
-        for mapset in glob.glob(os.path.join(dbase, location, "*")):
-            if os.path.isdir(mapset) and \
-                    os.path.isfile(os.path.join(dbase, location, mapset, "WIND")):
-                listOfMapsets.append(os.path.basename(mapset))
-    
-    ListSortLower(listOfMapsets)
-    return listOfMapsets
-
-def GetColorTables():
-    """!Get list of color tables"""
-    ret = gcmd.RunCommand('r.colors',
-                          read = True,
-                          flags = 'l')
-    if not ret:
-        return list()
-    
-    return ret.splitlines()
-
-def DecodeString(string):
-    """!Decode string using system encoding
-    
-    @param string string to be decoded
-    
-    @return decoded string
-    """
-    if not string:
-        return string
-    
-    enc = locale.getdefaultlocale()[1]
-    if enc:
-        Debug.msg(5, "DecodeString(): enc=%s" % enc)
-        return string.decode(enc)
-    
-    return string
-
-def EncodeString(string):
-    """!Return encoded string using system locales
-    
-    @param string string to be encoded
-    
-    @return encoded string
-    """
-    if not string:
-        return string
-    enc = locale.getdefaultlocale()[1]
-    if enc:
-        Debug.msg(5, "EncodeString(): enc=%s" % enc)
-        return string.encode(enc)
-    
-    return string
-
-def _getGDALFormats():
-    """!Get dictionary of avaialble GDAL drivers"""
-    ret = grass.read_command('r.in.gdal',
-                             quiet = True,
-                             flags = 'f')
-    
-    return _parseFormats(ret), _parseFormats(ret, writableOnly = True)
-
-def _getOGRFormats():
-    """!Get dictionary of avaialble OGR drivers"""
-    ret = grass.read_command('v.in.ogr',
-                             quiet = True,
-                             flags = 'f')
-    
-    return _parseFormats(ret), _parseFormats(ret, writableOnly = True)
-
-def _parseFormats(output, writableOnly = False):
-    """!Parse r.in.gdal/v.in.ogr -f output"""
-    formats = { 'file'     : list(),
-                'database' : list(),
-                'protocol' : list()
-                }
-    
-    if not output:
-        return formats
-    
-    patt = None
-    if writableOnly:
-        patt = re.compile('\(rw\+?\)$', re.IGNORECASE)
-    
-    for line in output.splitlines():
-        key, name = map(lambda x: x.strip(), line.strip().rsplit(':', -1))
-        
-        if writableOnly and not patt.search(key):
-            continue
-        
-        if name in ('Memory', 'Virtual Raster', 'In Memory Raster'):
-            continue
-        if name in ('PostgreSQL', 'SQLite',
-                    'ODBC', 'ESRI Personal GeoDatabase',
-                    'Rasterlite',
-                    'PostGIS WKT Raster driver'):
-            formats['database'].append(name)
-        elif name in ('GeoJSON',
-                      'OGC Web Coverage Service',
-                      'OGC Web Map Service',
-                      'HTTP Fetching Wrapper'):
-            formats['protocol'].append(name)
-        else:
-            formats['file'].append(name)
-    
-    for items in formats.itervalues():
-        items.sort()
-    
-    return formats
-
-formats = None
-
-def GetFormats(writableOnly = False):
-    """!Get GDAL/OGR formats"""
-    global formats
-    if not formats:
-        gdalAll, gdalWritable = _getGDALFormats()
-        ogrAll,  ogrWritable  = _getOGRFormats()
-        formats = {
-            'all' : {
-                'gdal' : gdalAll,
-                'ogr'  : ogrAll,
-                },
-            'writable' : {
-                'gdal' : gdalWritable,
-                'ogr'  : ogrWritable,
-                },
-            }
-    
-    if writableOnly:
-        return formats['writable']
-    
-    return formats['all']
-
-def GetSettingsPath():
-    """!Get full path to the settings directory
-    """
-    try:
-        verFd = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
-        version = int(verFd.readlines()[0].split(' ')[0].split('.')[0])
-    except (IOError, ValueError, TypeError, IndexError), e:
-        sys.exit(_("ERROR: Unable to determine GRASS version. Details: %s") % e)
-    
-    verFd.close()
-
-    # keep location of settings files rc and wx in sync with lib/init/grass.py
-    if sys.platform == 'win32':
-        return os.path.join(os.getenv('APPDATA'), 'grass%d' % version)
-    
-    return os.path.join(os.getenv('HOME'), '.grass%d' % version)

Deleted: grass/trunk/gui/wxpython/gui_modules/vclean.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/vclean.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/vclean.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,545 +0,0 @@
-"""
- at package vclean.py
-
- at brief Dialog for interactive construction of vector cleaning
-operations
-
-Classes:
- - VectorCleaningFrame
-
-(C) 2010-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Markus Metz
-"""
-
-import os
-import sys
-import shutil
-
-import wx
-import wx.lib.scrolledpanel as scrolled
-
-from grass.script import core as grass
-
-import dbm
-import gcmd
-import globalvar
-import gselect
-import render
-import utils
-from debug import Debug as Debug
-from preferences import globalSettings as UserSettings
-
-class VectorCleaningFrame(wx.Frame):
-    def __init__(self, parent, id=wx.ID_ANY, title=_('set up vector cleaning tools'),
-                 pos=wx.DefaultPosition, size=(-1, -1),
-                 style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
-                 **kwargs):
-        """!
-        Dialog for interactively defining vector cleaning tools
-        """
-        wx.Frame.__init__(self, parent, id, title, pos, size, style)
-
-        self.parent = parent # GMFrame
-        if self.parent:
-            self.log = self.parent.GetLogWindow()
-        else:
-            self.log = None
-  
-        # grass command
-        self.cmd = 'v.clean'
-        
-        # statusbar
-        self.CreateStatusBar()
-
-	# icon
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-
-	# self.panel not set as in colorrules
-        # self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
-        
-        # input map to clean
-        self.inmap = ''
-        
-        # cleaned output map
-        self.outmap = ''
-
-	self.ftype = ''
-
-        # cleaning tools
-        self.toolslines = {}
-
-        self.tool_desc_list = [
-            _('break lines/boundaries'),
-            _('remove duplicates'),
-            _('remove dangles'),
-            _('change boundary dangles to lines'),
-            _('remove bridges'),
-	    _('change bridges to lines'),
-	    _('snap lines/boundaries'),
-	    _('remove duplicate area centroids'),
-	    _('break polygons'),
-	    _('prune lines/boundaries'),
-	    _('remove small areas'),
-	    _('remove lines/boundaries of zero length'),
-	    _('remove small angles at nodes')
-	    ]
-
-        self.tool_list = [
-            'break',
-            'rmdupl',
-            'rmdangle',
-            'chdangle',
-            'rmbridge',
-	    'chbridge',
-	    'snap',
-	    'rmdac',
-	    'bpol',
-	    'prune',
-	    'rmarea',
-	    'rmline',
-	    'rmsa'
-	    ]
-
-	self.ftype = [
-	    'point',
-	    'line',
-	    'boundary',
-	    'centroid',
-	    'area',
-	    'face']
-
-	self.n_ftypes = 6
-        
-	self.tools_string = ''
-	self.thresh_string = ''
-	self.ftype_string = ''
-
-	self.SetTitle(_('Set up vector cleaning tools'))
-	self.SetStatusText(_("Set up vector cleaning tools"))
-	self.elem = 'vector'
-	self.ctlabel = _('Choose cleaning tools and set thresholds')
-
-        # top controls
-        self.inmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                         label= _('Select input vector map:'))
-        self.selectionInput = gselect.Select(parent=self, id=wx.ID_ANY,
-                                             size=globalvar.DIALOG_GSELECT_SIZE,
-                                             type='vector')
-	self.ftype_check = {}
-        ftypeBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
-                                label=_(' Feature type: '))
-        self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL)
-
-        self.outmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                         label= _('Select output vector map:'))
-        self.selectionOutput = gselect.Select(parent=self, id=wx.ID_ANY,
-                                             size=globalvar.DIALOG_GSELECT_SIZE,
-                                             type='vector')
-        
-        self.overwrite = wx.CheckBox(parent=self, id=wx.ID_ANY,
-                                       label=_('Allow output files to overwrite existing files'))
-        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
-
-        # cleaning tools
-        self.ct_label = wx.StaticText(parent=self, id=wx.ID_ANY,
-                                      label=self.ctlabel)
-
-        self.ct_panel = self.__toolsPanel()
-
-	# buttons to manage cleaning tools
-        self.btn_add = wx.Button(parent=self, id=wx.ID_ADD)
-        self.btn_remove = wx.Button(parent=self, id=wx.ID_REMOVE)
-        self.btn_moveup = wx.Button(parent=self, id=wx.ID_UP)
-        self.btn_movedown = wx.Button(parent=self, id=wx.ID_DOWN)
-
-        # add one tool as default
-        self.AddTool()
-	self.selected = -1
-        
-        # Buttons
-        self.btn_close = wx.Button(parent = self, id = wx.ID_CLOSE)
-        self.btn_run = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Run"))
-        self.btn_run.SetDefault()
-	self.btn_clipboard = wx.Button(parent=self, id=wx.ID_COPY)
-	self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
-        self.btn_help = wx.Button(parent = self, id = wx.ID_HELP)
-        
-        # bindings
-        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-        self.btn_run.Bind(wx.EVT_BUTTON, self.OnCleaningRun)
-	self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
-        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
-
-        self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddTool)
-        self.btn_remove.Bind(wx.EVT_BUTTON, self.OnClearTool)
-        self.btn_moveup.Bind(wx.EVT_BUTTON, self.OnMoveToolUp)
-        self.btn_movedown.Bind(wx.EVT_BUTTON, self.OnMoveToolDown)
-
-        self.SetMinSize(self.GetBestSize())
-
-        # layout
-        self._layout()
-
-        self.CentreOnScreen()
-        self.Show()
-        
-    def _layout(self):
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        #
-        # input output
-        #
-	inSizer = wx.GridBagSizer(hgap=5, vgap=5)
-
-        inSizer.Add(item=self.inmaplabel, pos=(0, 0),
-                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
-        inSizer.Add(item=self.selectionInput, pos=(1, 0),
-                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
-
-	self.ftype_check = [
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('point')),
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('line')),
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('boundary')),
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('centroid')),
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('area')),
-	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('face'))
-	    ]
-
-	typeoptSizer = wx.BoxSizer(wx.HORIZONTAL)
-	for num in range(0, self.n_ftypes):
-	    type_box = self.ftype_check[num]
-	    typeoptSizer.Add(item=type_box, flag=wx.ALIGN_LEFT, border=1)
-
-	self.ftypeSizer.Add(item = typeoptSizer,
-	           flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2)
-
-	outSizer = wx.GridBagSizer(hgap=5, vgap=5)
-
-        outSizer.Add(item=self.outmaplabel, pos=(0, 0),
-                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
-        outSizer.Add(item=self.selectionOutput, pos=(1, 0),
-                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
-        replaceSizer = wx.BoxSizer(wx.HORIZONTAL)
-        replaceSizer.Add(item=self.overwrite, proportion=1,
-                         flag=wx.ALL | wx.EXPAND, border=1)
-
-        outSizer.Add(item=replaceSizer, pos=(2, 0),
-                       flag=wx.ALL | wx.EXPAND, border=1)
-
-        #
-        # tools selection
-        #
-        bodySizer = wx.GridBagSizer(hgap=5, vgap=5)
-
-        bodySizer.Add(item=self.ct_label, pos=(0, 0), span=(1, 2),
-                      flag=wx.ALL, border=5)
-
-        bodySizer.Add(item=self.ct_panel, pos=(1, 0), span=(1, 2))
-
-	manageBoxSizer = wx.GridBagSizer(hgap=10, vgap=1)
-	# start with row 1 for nicer layout
-        manageBoxSizer.Add(item=self.btn_add, pos=(1, 0), border=2, flag=wx.ALL | wx.EXPAND)
-        manageBoxSizer.Add(item=self.btn_remove, pos=(2, 0), border=2, flag=wx.ALL | wx.EXPAND)
-        manageBoxSizer.Add(item=self.btn_moveup, pos=(3, 0), border=2, flag=wx.ALL | wx.EXPAND)
-        manageBoxSizer.Add(item=self.btn_movedown, pos=(4, 0), border=2, flag=wx.ALL | wx.EXPAND)
-
-        bodySizer.Add(item=manageBoxSizer, pos=(1, 2),
-                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
-
-        bodySizer.AddGrowableCol(2)
-        
-        #
-        # standard buttons
-        #
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(self.btn_close,
-                     flag=wx.LEFT | wx.RIGHT, border=5)
-        btnSizer.Add(self.btn_run,
-                     flag=wx.LEFT | wx.RIGHT, border=5)
-        btnSizer.Add(self.btn_clipboard,
-                     flag=wx.LEFT | wx.RIGHT, border=5)
-        btnSizer.Add(self.btn_help,
-                     flag=wx.LEFT | wx.RIGHT, border=5)
-        
-        #
-        # put it all together
-        #
-        sizer.Add(item=inSizer, proportion=0,
-                  flag=wx.ALL | wx.EXPAND, border=5)
-        
-        sizer.Add(item=self.ftypeSizer, proportion=0,
-                  flag=wx.ALL | wx.EXPAND, border=5)
-
-        sizer.Add(item=outSizer, proportion=0,
-                  flag=wx.ALL | wx.EXPAND, border=5)
-
-        sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
-                  style=wx.LI_HORIZONTAL), proportion=0,
-                  flag=wx.EXPAND | wx.ALL, border=5) 
-        
-        sizer.Add(item=bodySizer, proportion=1,
-                  flag=wx.ALL | wx.EXPAND, border=5)
-
-        sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
-                  style=wx.LI_HORIZONTAL), proportion=0,
-                  flag=wx.EXPAND | wx.ALL, border=5) 
-        
-        sizer.Add(item=btnSizer, proportion=0,
-                  flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-        self.Layout()
-        
-    def __toolsPanel(self):
-        ct_panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY,
-	                                  size=(500, 240),
-                                          style=wx.SUNKEN_BORDER)
-
-        self.ct_sizer = wx.GridBagSizer(vgap=2, hgap=4)
-        
-        ct_panel.SetSizer(self.ct_sizer)
-        ct_panel.SetAutoLayout(True)
-        
-        return ct_panel        
-
-    def OnAddTool(self, event):
-        """!Add tool button pressed"""
-	self.AddTool()
-
-    def AddTool(self):
-        snum = len(self.toolslines.keys())
-	num = snum + 1
-	# tool number
-	tool_no = wx.StaticText(parent = self.ct_panel, id = 3000+num,
-                                         label= str(num)+'.')
-	# tool
-	tool_cbox = wx.ComboBox(parent = self.ct_panel, id=1000+num, 
-				size = (300, -1), choices = self.tool_desc_list,
-				style = wx.CB_DROPDOWN |
-				wx.CB_READONLY | wx.TE_PROCESS_ENTER)
-	self.Bind(wx.EVT_COMBOBOX, self.OnSetTool, tool_cbox)
-	# threshold
-	txt_ctrl = wx.TextCtrl(parent=self.ct_panel, id=2000+num, value='0.00',
-			       size=(100,-1),
-			       style=wx.TE_NOHIDESEL)
-	self.Bind(wx.EVT_TEXT, self.OnThreshValue, txt_ctrl)
-
-	# select
-	select = wx.CheckBox(parent=self.ct_panel, id=num)
-	select.SetValue(False)
-	self.Bind(wx.EVT_CHECKBOX, self.OnSelect, select)
-
-	# start with row 1 and col 1 for nicer layout
-	self.ct_sizer.Add(item=tool_no, pos=(num, 1),
-			  flag=wx.ALIGN_CENTER_VERTICAL, border=5)
-	self.ct_sizer.Add(item=tool_cbox, pos=(num, 2),
-			  flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
-	self.ct_sizer.Add(item=txt_ctrl, pos=(num, 3),
-			  flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
-	self.ct_sizer.Add(item=select, pos=(num, 4),
-			  flag=wx.ALIGN_CENTER | wx.RIGHT)
-
-	self.toolslines[num] = {
-	    'tool_desc' : '' ,
-	    'tool' : '' ,
-	    'thresh' : '0.00' }
-        
-        self.ct_panel.Layout()
-        self.ct_panel.SetupScrolling()
-        
-    def OnClearTool(self, event):
-        """!Remove tool button pressed"""
-        id = self.selected
-
-	if id > 0:
-	    self.FindWindowById(id+1000).SetValue('')
-	    self.toolslines[id]['tool_desc'] = ''
-	    self.toolslines[id]['tool'] = ''
-	    self.SetStatusText(_("%s. cleaning tool removed, will be ignored") % id)
-	else:
-	    self.SetStatusText(_("Please select a cleaning tool to remove"))
-
-    def OnMoveToolUp(self, event):
-        """!Move up tool button pressed"""
-        id = self.selected
-
-	if id > 1:
-	    id_up = id - 1
-	    this_toolline = self.toolslines[id]
-	    up_toolline = self.toolslines[id_up]
-	    
-	    self.FindWindowById(id_up).SetValue(True)
-	    self.FindWindowById(id_up+1000).SetValue(this_toolline['tool_desc'])
-	    self.FindWindowById(id_up+2000).SetValue(this_toolline['thresh'])
-	    self.toolslines[id_up] = this_toolline
-	    
-	    self.FindWindowById(id).SetValue(False)
-	    self.FindWindowById(id+1000).SetValue(up_toolline['tool_desc'])
-	    self.FindWindowById(id+2000).SetValue(up_toolline['thresh'])
-	    self.toolslines[id] = up_toolline
-	    self.selected = id_up
-	    self.SetStatusText(_("%s. cleaning tool moved up") % id)
-	elif id == 1:
-	    self.SetStatusText(_("1. cleaning tool can not be moved up "))
-	elif id == -1:
-	    self.SetStatusText(_("Please select a cleaning tool to move up"))
-
-
-    def OnMoveToolDown(self, event):
-        """!Move down tool button pressed"""
-        id = self.selected
-        snum = len(self.toolslines.keys())
-
-	if id > 0 and id < snum:
-	    id_down = id + 1
-	    this_toolline = self.toolslines[id]
-	    down_toolline = self.toolslines[id_down]
-	    
-	    self.FindWindowById(id_down).SetValue(True)
-	    self.FindWindowById(id_down+1000).SetValue(this_toolline['tool_desc'])
-	    self.FindWindowById(id_down+2000).SetValue(this_toolline['thresh'])
-	    self.toolslines[id_down] = this_toolline
-	    
-	    self.FindWindowById(id).SetValue(False)
-	    self.FindWindowById(id+1000).SetValue(down_toolline['tool_desc'])
-	    self.FindWindowById(id+2000).SetValue(down_toolline['thresh'])
-	    self.toolslines[id] = down_toolline
-	    self.selected = id_down
-	    self.SetStatusText(_("%s. cleaning tool moved down") % id)
-	elif id == snum:
-	    self.SetStatusText(_("Last cleaning tool can not be moved down "))
-	elif id == -1:
-	    self.SetStatusText(_("Please select a cleaning tool to move down"))
-
-    def OnSetTool(self, event):
-        """!Tool was defined"""
-        id = event.GetId()
-	tool_no = id-1000
-	num = self.FindWindowById(id).GetCurrentSelection()
-
-	self.toolslines[tool_no]['tool_desc'] = self.tool_desc_list[num]
-	self.toolslines[tool_no]['tool'] = self.tool_list[num]
-
-	self.SetStatusText( str(tool_no) + '. ' + _("cleaning tool: '%s'") % (self.tool_list[num]))
-
-    def OnThreshValue(self, event):
-        """!Threshold value was entered"""
-        id = event.GetId()
-	num = id-2000
-	self.toolslines[num]['thresh'] = self.FindWindowById(id).GetValue()
-
-	self.SetStatusText(_("Threshold for %(num)s. tool '%(tool)s': %(thresh)s") % \
-                               { 'num' : num,
-                                 'tool' : self.toolslines[num]['tool'],
-                                 'thresh' : self.toolslines[num]['thresh'] })
-
-    def OnSelect(self, event):
-        """!Tool was selected"""
-        id = event.GetId()
-
-	if self.selected > -1 and self.selected != id:
-	    win = self.FindWindowById(self.selected)
-	    win.SetValue(False)
-
-	if self.selected != id:
-	    self.selected = id
-	else:
-	    self.selected = -1
-
-    def OnCleaningRun(self, event):
-        """!Builds options and runs v.clean
-        """
-	self.SetStatusText(_("Executing selected cleaning operations..."))
-        snum = len(self.toolslines.keys())
-	self.GetCmdStrings()
-
-        if self.log:
-	    cmd = [ self.cmd,
-                    'input=%s' % self.inmap,
-                    'output=%s' % self.outmap,
-                    'tool=%s' % self.tools_string,
-                    'thres=%s' % self.thresh_string ]
-            if self.ftype_string:
-                cmd.append('type=%s' % self.ftype_string)
-	    if self.overwrite.IsChecked():
-		cmd.append('--overwrite')
-            
-            self.log.RunCmd(cmd)
-            self.parent.Raise()
-        else:
-	    if self.overwrite.IsChecked():
-		overwrite = True
-	    else:
-		overwrite = False
-            
-	    gcmd.RunCommand(self.cmd,
-			    input = self.inmap,
-			    output = self.outmap,
-			    type = self.ftype_string,
-			    tool = self.tools_string,
-			    thresh = self.thresh_string,
-			    overwrite = overwrite)
-
-    def OnClose(self, event):
-        self.Destroy()
-        
-    def OnHelp(self, event):
-        """!Show GRASS manual page"""
-        gcmd.RunCommand('g.manual',
-                        quiet = True,
-                        parent = self,
-                        entry = self.cmd)
-        
-    def OnCopy(self, event):
-        """!Copy the command"""
-        cmddata = wx.TextDataObject()
-	# get tool and thresh strings
-	self.GetCmdStrings()
-        cmdstring = '%s' % (self.cmd)
-        # list -> string
-        cmdstring += ' input=%s output=%s type=%s tool=%s thres=%s' % \
-	    (self.inmap, self.outmap, self.ftype_string, self.tools_string, self.thresh_string)
-	if self.overwrite.IsChecked():
-	    cmdstring += ' --overwrite'
- 
-        cmddata.SetText(cmdstring)
-        if wx.TheClipboard.Open():
-            wx.TheClipboard.SetData(cmddata)
-            wx.TheClipboard.Close()
-            self.SetStatusText(_("Vector cleaning command copied to clipboard"))
-
-    def GetCmdStrings(self):
-	self.tools_string = ''
-	self.thresh_string = ''
-	self.ftype_string = ''
-	# feature types
-	first = 1
-        for num in range(0, self.n_ftypes - 1):
-	    if self.ftype_check[num].IsChecked():
-		if first:
-		    self.ftype_string = '%s' % self.ftype[num]
-		    first = 0
-		else:
-		    self.ftype_string += ',%s' % self.ftype[num]
-		    
-	    
-	# cleaning tools
-	first = 1
-        snum = len(self.toolslines.keys())
-        for num in range(1, snum + 1):
-	    if self.toolslines[num]['tool']:
-		if first:
-		    self.tools_string = '%s' % self.toolslines[num]['tool']
-		    self.thresh_string = '%s' % self.toolslines[num]['thresh']
-		    first = 0
-		else:
-		    self.tools_string += ',%s' % self.toolslines[num]['tool']
-		    self.thresh_string += ',%s' % self.toolslines[num]['thresh']
-
-	self.inmap = self.selectionInput.GetValue()
-	self.outmap = self.selectionOutput.GetValue()

Deleted: grass/trunk/gui/wxpython/gui_modules/vdigit.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/vdigit.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/vdigit.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1541 +0,0 @@
-"""!
- at package vdigit
-
- at brief Dialogs for wxGUI vector digitizer
-
-Classes:
- - VDigit
- - VDigitSettingsDialog
- - VDigitCategoryDialog
- - CategoryListCtrl
- - VDigitZBulkDialog
- - VDigitDuplicatesDialog
- - CheckListFeature
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import string
-import copy
-import textwrap
-import traceback
-
-from threading import Thread
-
-import wx
-import wx.lib.colourselect as csel
-import wx.lib.mixins.listctrl as listmix
-
-import gcmd
-import dbm
-from debug import Debug as Debug
-import gselect
-import globalvar
-from units import Units
-from preferences import globalSettings as UserSettings
-try:
-    from wxvdigit  import IVDigit, GV_LINES
-    haveVDigit = True
-    errorMsg = ''
-except ImportError, err:
-    haveVDigit = False
-    errorMsg = err
-    GV_LINES = -1
-    class IVDigit:
-        def __init__(self):
-            pass
-
-class VDigit(IVDigit):
-    def __init__(self, mapwindow):
-        """!Base class of vector digitizer
-        
-        @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance
-        """
-        IVDigit.__init__(self, mapwindow)
-        
-class VDigitSettingsDialog(wx.Dialog):
-    def __init__(self, parent, title, style = wx.DEFAULT_DIALOG_STYLE):
-        """!Standard settings dialog for digitization purposes
-        """
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
-
-        self.parent = parent # mapdisplay.MapFrame class instance
-        self.digit = self.parent.MapWindow.digit
-        
-        # notebook
-        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-        self._createSymbologyPage(notebook)
-        self.digit.SetCategory()
-        self._createGeneralPage(notebook)
-        self._createAttributesPage(notebook)
-        self._createQueryPage(notebook)
-
-        # buttons
-        btnApply = wx.Button(self, wx.ID_APPLY)
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnSave = wx.Button(self, wx.ID_SAVE)
-        btnSave.SetDefault()
-
-        # bindigs
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnApply.SetToolTipString(_("Apply changes for this session"))
-        btnApply.SetDefault()
-        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        btnSave.SetToolTipString(_("Close dialog and save changes to user settings file"))
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-        
-        # sizers
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        btnSizer.AddButton(btnApply)
-        btnSizer.AddButton(btnSave)
-        btnSizer.Realize()
-        
-        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.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.Bind(wx.EVT_CLOSE, self.OnCancel)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-    def _createSymbologyPage(self, notebook):
-        """!Create notebook page concerning symbology settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Symbology"))
-
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        
-        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-
-        self.symbology = {}
-        for label, key in self._symbologyData():
-            textLabel = wx.StaticText(panel, wx.ID_ANY, label)
-            color = csel.ColourSelect(panel, id = wx.ID_ANY,
-                                      colour = UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                                              subkey = [key, 'color']), size = globalvar.DIALOG_COLOR_SIZE)
-            isEnabled = UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                         subkey = [key, 'enabled'])
-            if isEnabled is not None:
-                enabled = wx.CheckBox(panel, id = wx.ID_ANY, label = "")
-                enabled.SetValue(isEnabled)
-                self.symbology[key] = (enabled, color)
-            else:
-                enabled = (1, 1)
-                self.symbology[key] = (None, color)
-            
-            flexSizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-            flexSizer.Add(enabled, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-            flexSizer.Add(color, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-            color.SetName("GetColour")
-        
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 10)
-        
-        panel.SetSizer(sizer)
-        
-        return panel
-
-    def _createGeneralPage(self, notebook):
-        """!Create notebook page concerning general settings"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("General"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        #
-        # display section
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Display"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        # line width
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width"))
-        self.lineWidthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
-                                          initial = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'value'),
-                                          min = 1, max = 1e6)
-        units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
-                              label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
-                              style = wx.ALIGN_LEFT)
-        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.lineWidthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
-                      border = 10)
-
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        #
-        # snapping section
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Snapping"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer(cols = 3, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-
-        # snapping
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold"))
-        self.snappingValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
-                                         initial = UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'value'),
-                                         min = -1, max = 1e6)
-        self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue)
-        self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue)
-        self.snappingUnit = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
-                                      choices = [_("screen pixels"), _("map units")])
-        self.snappingUnit.SetStringSelection(UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'units'))
-        self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits)
-        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.snappingValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(self.snappingUnit, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-
-        vertexSizer = wx.BoxSizer(wx.VERTICAL)
-        self.snapVertex = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                      label = _("Snap also to vertex"))
-        self.snapVertex.SetValue(UserSettings.Get(group = 'vdigit', key = "snapToVertex", subkey = 'enabled'))
-        vertexSizer.Add(item = self.snapVertex, proportion = 0, flag = wx.EXPAND)
-        self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
-        self.snappingInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                          label = _("Snapping threshold is %(value).1f %(units)s") % \
-                                              {'value' : self.digit.GetDisplay().GetThreshold(),
-                                               'units' : self.mapUnits})
-        vertexSizer.Add(item = self.snappingInfo, proportion = 0,
-                        flag = wx.ALL | wx.EXPAND, border = 1)
-
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.EXPAND)
-        sizer.Add(item = vertexSizer, proportion = 1, flag = wx.EXPAND)
-        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-
-        #
-        # select box
-        #
-        box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Select vector features"))
-        # feature type
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        inSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.selectFeature = {}
-        for feature in ('point', 'line',
-                        'centroid', 'boundary'):
-            chkbox = wx.CheckBox(parent = panel, label = feature)
-            self.selectFeature[feature] = chkbox.GetId()
-            chkbox.SetValue(UserSettings.Get(group = 'vdigit', key = 'selectType',
-                                             subkey = [feature, 'enabled']))
-            inSizer.Add(item = chkbox, proportion = 0,
-                        flag = wx.EXPAND | wx.ALL, border = 5)
-        sizer.Add(item = inSizer, proportion = 0, flag = wx.EXPAND)
-        # threshold
-        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select threshold"))
-        self.selectThreshValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
-                                             initial = UserSettings.Get(group = 'vdigit', key = "selectThresh", subkey = 'value'),
-                                             min = 1, max = 1e6)
-        units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
-                              label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
-                              style = wx.ALIGN_LEFT)
-        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.selectThreshValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
-                      border = 10)
-
-        self.selectIn = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                    label = _("Select only features inside of selection bounding box"))
-        self.selectIn.SetValue(UserSettings.Get(group = 'vdigit', key = "selectInside", subkey = 'enabled'))
-        self.selectIn.SetToolTipString(_("By default are selected all features overlapping selection bounding box "))
-        
-        self.checkForDupl = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                        label = _("Check for duplicates"))
-        self.checkForDupl.SetValue(UserSettings.Get(group = 'vdigit', key = "checkForDupl", subkey = 'enabled'))
-
-
-        sizer.Add(item = flexSizer, proportion = 0, flag = wx.EXPAND)
-        sizer.Add(item = self.selectIn, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)
-        sizer.Add(item = self.checkForDupl, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)        
-        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-
-        #
-        # digitize lines box
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize line features"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        self.intersect = wx.CheckBox(parent = panel, label = _("Break lines at intersection"))
-        self.intersect.SetValue(UserSettings.Get(group = 'vdigit', key = 'breakLines', subkey = 'enabled'))
-        
-        sizer.Add(item = self.intersect, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-
-        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-
-        #
-        # save-on-exit box
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Save changes"))
-        # save changes on exit?
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        self.save = wx.CheckBox(parent = panel, label = _("Save changes on exit"))
-        self.save.SetValue(UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled'))
-        sizer.Add(item = self.save, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createQueryPage(self, notebook):
-        """!Create notebook page for query tool"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Query tool"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-
-        #
-        # query tool box
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Choose query tool"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
-
-        self.queryBox = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select by box"))
-        self.queryBox.SetValue(UserSettings.Get(group = 'vdigit', key = "query", subkey = 'box'))
-
-        sizer.Add(item = self.queryBox, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        sizer.Add((0, 5))
-
-        #
-        # length
-        #
-        self.queryLength = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("length"))
-        self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
-        sizer.Add(item = self.queryLength, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select lines"))
-        self.queryLengthSL = wx.Choice (parent = panel, id = wx.ID_ANY, 
-                                        choices  =  [_("shorter than"), _("longer than")])
-        self.queryLengthSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection'))
-        self.queryLengthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
-                                            initial = 1,
-                                            min = 0, max = 1e6)
-        self.queryLengthValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'thresh'))
-        units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
-        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.queryLengthSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(self.queryLengthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-
-        #
-        # dangle
-        #
-        self.queryDangle = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("dangle"))
-        self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
-        sizer.Add(item = self.queryDangle, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-        txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select dangles"))
-        self.queryDangleSL = wx.Choice (parent = panel, id = wx.ID_ANY, 
-                                        choices = [_("shorter than"), _("longer than")])
-        self.queryDangleSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection'))
-        self.queryDangleValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
-                                       initial = 1,
-                                       min = 0, max = 1e6)
-        self.queryDangleValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'thresh'))
-        units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
-        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.queryDangleSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(self.queryDangleValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-
-        if UserSettings.Get(group = 'vdigit', key = "query", subkey = 'selection') == 0:
-            self.queryLength.SetValue(True)
-        else:
-            self.queryDangle.SetValue(True)
-
-        # enable & disable items
-        self.OnChangeQuery(None)
-
-        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _createAttributesPage(self, notebook):
-        """!Create notebook page for attributes"""
-        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
-        notebook.AddPage(page = panel, text = _("Attributes"))
-
-        border = wx.BoxSizer(wx.VERTICAL)
-
-        #
-        # add new record
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize new feature"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
-        # checkbox
-        self.addRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                     label = _("Add new record into table"))
-        self.addRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'))
-        sizer.Add(item = self.addRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        # settings
-        flexSizer = wx.FlexGridSizer(cols = 2, hgap = 3, vgap = 3)
-        flexSizer.AddGrowableCol(0)
-        settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use")))
-        # layer
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Layer"))
-        self.layer = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
-                                 min = 1, max = 1e3)
-        self.layer.SetValue(int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')))
-        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = self.layer, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-        # category number
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category number"))
-        self.category = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
-                                    initial = UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'),
-                                    min = -1e9, max = 1e9) 
-        if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') != 1:
-            self.category.Enable(False)
-        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = self.category, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-        # category mode
-        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category mode"))
-        self.categoryMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
-                                      choices = [_("Next to use"), _("Manual entry"), _("No category")])
-        self.categoryMode.SetSelection(UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection'))
-        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = self.categoryMode, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0,
-                   flag = wx.ALL | wx.EXPAND, border = 5)
-
-        #
-        # delete existing record
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Delete existing feature(s)"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        # checkbox
-        self.deleteRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                        label = _("Delete record from table"))
-        self.deleteRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "delRecord", subkey = 'enabled'))
-        sizer.Add(item = self.deleteRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0,
-                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-
-        #
-        # geometry attributes (currently only length and area are supported)
-        #
-        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
-                              label = " %s " % _("Geometry attributes"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
-        gridSizer.AddGrowableCol(0)
-        self.geomAttrb = { 'length' : { 'label' : _('length') },
-                           'area' : { 'label' : _('area') },
-                           'perimeter' : { 'label' : _('perimeter') } }
-
-        digitToolbar = self.parent.toolbars['vdigit']
-        try:
-            vectorName = digitToolbar.GetLayer().GetName()
-        except AttributeError:
-            vectorName = None # no vector selected for editing
-        layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
-        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
-        tree = self.parent.tree
-        item = tree.FindItemByData('maplayer', mapLayer)
-        row = 0
-        for attrb in ['length', 'area', 'perimeter']:
-            # checkbox
-            check = wx.CheckBox(parent = panel, id = wx.ID_ANY,
-                                label = self.geomAttrb[attrb]['label'])
-            ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
-            check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb)
-            # column (only numeric)
-            column = gselect.ColumnSelect(parent = panel, size = (200, -1))
-            column.InsertColumns(vector = vectorName,
-                                 layer = layer, excludeKey = True,
-                                 type = ['integer', 'double precision'])
-            # units 
-            if attrb == 'area':
-                choices = Units.GetUnitsList('area')
-            else:
-                choices = Units.GetUnitsList('length')
-            win_units = wx.Choice(parent = panel, id = wx.ID_ANY,
-                                  choices = choices, size = (120, -1))
-            
-            # default values
-            check.SetValue(False)
-            if item and tree.GetPyData(item)[0]['vdigit'] and \
-                    'geomAttr' in tree.GetPyData(item)[0]['vdigit'] and \
-                    attrb in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
-                check.SetValue(True)
-                column.SetStringSelection(tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['column'])
-                if attrb == 'area':
-                    type = 'area'
-                else:
-                    type = 'length'
-                unitsIdx = Units.GetUnitsIndex(type, 
-                                                tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['units'])
-                win_units.SetSelection(unitsIdx)
-
-            if not vectorName:
-                check.Enable(False)
-                column.Enable(False)
-            
-            if not check.IsChecked():
-                column.Enable(False)
-            
-            self.geomAttrb[attrb]['check']  = check.GetId()
-            self.geomAttrb[attrb]['column'] = column.GetId()
-            self.geomAttrb[attrb]['units']  = win_units.GetId()
-
-            gridSizer.Add(item = check,
-                          flag = wx.ALIGN_CENTER_VERTICAL,
-                          pos = (row, 0))
-            gridSizer.Add(item = column,
-                          pos = (row, 1))
-            gridSizer.Add(item = win_units,
-                          pos = (row, 2))
-            row += 1
-        
-        note = '\n'.join(textwrap.wrap(_("Note: These settings are stored "
-                                         "in the workspace not in the vector digitizer "
-                                         "preferences."), 55))
-        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
-                                           label = note),
-                      pos = (3, 0), span = (1, 3))
-                      
-        sizer.Add(item = gridSizer, proportion = 1,
-                  flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 0,
-                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
-
-        # bindings
-        self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
-        self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
-        self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer)
-
-        panel.SetSizer(border)
-        
-        return panel
-
-    def _symbologyData(self):
-        """!Data for _createSymbologyPage()
-
-        label | checkbox | color
-        """
-
-        return (
-            #            ("Background", "symbolBackground"),
-            (_("Highlight"), "highlight"),
-            (_("Highlight (duplicates)"), "highlightDupl"),
-            (_("Point"), "point"),
-            (_("Line"), "line"),
-            (_("Boundary (no area)"), "boundaryNo"),
-            (_("Boundary (one area)"), "boundaryOne"),
-            (_("Boundary (two areas)"), "boundaryTwo"),
-            (_("Centroid (in area)"), "centroidIn"),
-            (_("Centroid (outside area)"), "centroidOut"),
-            (_("Centroid (duplicate in area)"), "centroidDup"),
-            (_("Node (one line)"), "nodeOne"),
-            (_("Node (two lines)"), "nodeTwo"),
-            (_("Vertex"), "vertex"),
-            (_("Area (closed boundary + centroid)"), "area"),
-            (_("Direction"), "direction"),)
-
-    def OnGeomAttrb(self, event):
-        """!Register geometry attributes (enable/disable)
-        """
-        checked = event.IsChecked()
-        id = event.GetId()
-        key = None
-        for attrb, val in self.geomAttrb.iteritems():
-            if val['check'] == id:
-                key = attrb
-                break
-        
-        column = self.FindWindowById(self.geomAttrb[key]['column'])
-        if checked:
-            column.Enable()
-        else:
-            column.Enable(False)
-        
-    def OnChangeCategoryMode(self, event):
-        """!Change category mode
-        """
-        mode = event.GetSelection()
-        UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = mode)
-        if mode == 1: # manual entry
-            self.category.Enable(True)
-        elif self.category.IsEnabled(): # disable
-            self.category.Enable(False)
-        
-        if mode == 2 and self.addRecord.IsChecked(): # no category
-            self.addRecord.SetValue(False)
-        
-        self.digit.SetCategory()
-        self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
-
-    def OnChangeLayer(self, event):
-        """!Layer changed
-        """
-        layer = event.GetInt()
-        if layer > 0:
-            UserSettings.Set(group = 'vdigit', key = 'layer', subkey = 'value', value = layer)
-            self.digit.SetCategory()
-            self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
-            
-        event.Skip()
-
-    def OnChangeAddRecord(self, event):
-        """!Checkbox 'Add new record' status changed
-        """
-        pass
-        # self.category.SetValue(self.digit.SetCategory())
-            
-    def OnChangeSnappingValue(self, event):
-        """!Change snapping value - update static text
-        """
-        value = self.snappingValue.GetValue()
-        
-        if value < 0:
-            region = self.parent.MapWindow.Map.GetRegion()
-            res = (region['nsres'] + region['ewres']) / 2.
-            threshold = self.digit.GetDisplay().GetThreshold(value = res)
-        else:
-            if self.snappingUnit.GetStringSelection() == "map units":
-                threshold = value
-            else:
-                threshold = self.digit.GetDisplay().GetThreshold(value = value)
-            
-        if value == 0:
-            self.snappingInfo.SetLabel(_("Snapping disabled"))
-        elif value < 0:
-            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s "
-                                         "(based on comp. resolution)") % 
-                                       {'value' : threshold,
-                                        'units' : self.mapUnits.lower()})
-        else:
-            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
-                                       {'value' : threshold,
-                                        'units' : self.mapUnits.lower()})
-        
-        event.Skip()
-
-    def OnChangeSnappingUnits(self, event):
-        """!Snapping units change -> update static text
-        """
-        value = self.snappingValue.GetValue()
-        units = self.snappingUnit.GetStringSelection()
-        threshold = self.digit.GetDisplay().GetThreshold(value = value, units = units)
-
-        if units == "map units":
-            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
-                                       {'value' : value,
-                                        'units' : self.mapUnits})
-        else:
-            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
-                                       {'value' : threshold,
-                                        'units' : self.mapUnits})
-            
-        event.Skip()
-
-    def OnChangeQuery(self, event):
-        """!Change query
-        """
-        if self.queryLength.GetValue():
-            # length
-            self.queryLengthSL.Enable(True)
-            self.queryLengthValue.Enable(True)
-            self.queryDangleSL.Enable(False)
-            self.queryDangleValue.Enable(False)
-        else:
-            # dangle
-            self.queryLengthSL.Enable(False)
-            self.queryLengthValue.Enable(False)
-            self.queryDangleSL.Enable(True)
-            self.queryDangleValue.Enable(True)
-
-    def OnSave(self, event):
-        """!Button 'Save' pressed
-        """
-        self.UpdateSettings()
-        self.parent.toolbars['vdigit'].settingsDialog = None
-
-        fileSettings = {}
-        UserSettings.ReadSettingsFile(settings = fileSettings)
-        fileSettings['vdigit'] = UserSettings.Get(group = 'vdigit')
-        
-        file = UserSettings.SaveToFile(fileSettings)
-        self.parent.GetLayerManager().goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file)
-        
-        self.Destroy()
-
-        event.Skip()
-        
-    def OnApply(self, event):
-        """!Button 'Apply' pressed
-        """
-        self.UpdateSettings()
-
-    def OnCancel(self, event):
-        """!Button 'Cancel' pressed
-        """
-        self.parent.toolbars['vdigit'].settingsDialog = None
-        self.Destroy()
-
-        if event:
-            event.Skip()
-        
-    def UpdateSettings(self):
-        """!Update digitizer settings
-        """
-        self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes
-        # symbology
-        for key, (enabled, color) in self.symbology.iteritems():
-            if enabled:
-                UserSettings.Set(group = 'vdigit', key = 'symbol',
-                                 subkey = [key, 'enabled'],
-                                 value = enabled.IsChecked())
-                UserSettings.Set(group = 'vdigit', key = 'symbol',
-                                 subkey = [key, 'color'],
-                                 value = tuple(color.GetColour()))
-            else:
-                UserSettings.Set(group = 'vdigit', key = 'symbol',
-                                 subkey = [key, 'color'],
-                                 value = tuple(color.GetColour()))
-        # display
-        UserSettings.Set(group = 'vdigit', key = "lineWidth", subkey = 'value',
-                         value = int(self.lineWidthValue.GetValue()))
-
-        # snapping
-        UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'value',
-                         value = int(self.snappingValue.GetValue()))
-        UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'units',
-                         value = self.snappingUnit.GetStringSelection())
-        UserSettings.Set(group = 'vdigit', key = "snapToVertex", subkey = 'enabled',
-                         value = self.snapVertex.IsChecked())
-        
-        # digitize new feature
-        UserSettings.Set(group = 'vdigit', key = "addRecord", subkey = 'enabled',
-                         value = self.addRecord.IsChecked())
-        UserSettings.Set(group = 'vdigit', key = "layer", subkey = 'value',
-                         value = int(self.layer.GetValue()))
-        UserSettings.Set(group = 'vdigit', key = "category", subkey = 'value',
-                         value = int(self.category.GetValue()))
-        UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection',
-                         value = self.categoryMode.GetSelection())
-
-        # delete existing feature
-        UserSettings.Set(group = 'vdigit', key = "delRecord", subkey = 'enabled',
-                         value = self.deleteRecord.IsChecked())
-
-        # geometry attributes (workspace)
-        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
-        tree = self.parent.tree
-        item = tree.FindItemByData('maplayer', mapLayer)
-        for key, val in self.geomAttrb.iteritems():
-            checked = self.FindWindowById(val['check']).IsChecked()
-            column  = self.FindWindowById(val['column']).GetValue()
-            unitsIdx = self.FindWindowById(val['units']).GetSelection()
-            if item and not tree.GetPyData(item)[0]['vdigit']: 
-                tree.GetPyData(item)[0]['vdigit'] = { 'geomAttr' : dict() }
-            
-            if checked: # enable
-                if key == 'area':
-                    type = key
-                else:
-                    type = 'length'
-                unitsKey = Units.GetUnitsKey(type, unitsIdx)
-                tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] = { 'column' : column,
-                                                                       'units' : unitsKey }
-            else:
-                if item and tree.GetPyData(item)[0]['vdigit'] and \
-                        key in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
-                    del tree.GetPyData(item)[0]['vdigit']['geomAttr'][key]
-        
-        # query tool
-        if self.queryLength.GetValue():
-            UserSettings.Set(group = 'vdigit', key = "query", subkey = 'selection',
-                             value = 0)
-        else:
-            UserSettings.Set(group = 'vdigit', key = "query", subkey = 'type',
-                             value = 1)
-        UserSettings.Set(group = 'vdigit', key = "query", subkey = 'box',
-                         value = self.queryBox.IsChecked())
-        UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'than-selection',
-                         value = self.queryLengthSL.GetSelection())
-        UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'thresh',
-                         value = int(self.queryLengthValue.GetValue()))
-        UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'than-selection',
-                         value = self.queryDangleSL.GetSelection())
-        UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'thresh',
-                         value = int(self.queryDangleValue.GetValue()))
-
-        # select features
-        for feature in ('point', 'line',
-                        'centroid', 'boundary'):
-            UserSettings.Set(group = 'vdigit', key = 'selectType',
-                             subkey = [feature, 'enabled'],
-                             value = self.FindWindowById(self.selectFeature[feature]).IsChecked())
-        UserSettings.Set(group = 'vdigit', key = "selectThresh", subkey = 'value',
-                         value = int(self.selectThreshValue.GetValue()))
-        UserSettings.Set(group = 'vdigit', key = "checkForDupl", subkey = 'enabled',
-                         value = self.checkForDupl.IsChecked())
-        UserSettings.Set(group = 'vdigit', key = "selectInside", subkey = 'enabled',
-                         value = self.selectIn.IsChecked())
-
-        # on-exit
-        UserSettings.Set(group = 'vdigit', key = "saveOnExit", subkey = 'enabled',
-                         value = self.save.IsChecked())
-
-        # break lines
-        UserSettings.Set(group = 'vdigit', key = "breakLines", subkey = 'enabled',
-                         value = self.intersect.IsChecked())
-        
-        self.digit.UpdateSettings()
-        
-        # redraw map if auto-rendering is enabled
-        if self.parent.IsAutoRendered(): 
-            self.parent.OnRender(None)
-
-class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin):
-    def __init__(self, parent, title,
-                 vectorName, query = None, cats = None,
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-        """!Dialog used to display/modify categories of vector objects
-        
-        @param parent
-        @param title dialog title
-        @param query {coordinates, qdist} - used by v.edit/v.what
-        @param cats  directory of lines (layer/categories) - used by vdigit
-        @param style dialog style
-        """
-        self.parent = parent       # mapdisplay.BufferedWindow class instance
-        self.digit = parent.digit
-        
-        # map name
-        self.vectorName = vectorName
-        
-        # line : {layer: [categories]}
-        self.cats = {}
-        
-        # do not display dialog if no line is found (-> self.cats)
-        if cats is None:
-            if self._getCategories(query[0], query[1]) == 0 or not self.line:
-                Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
-        else:
-            self.cats = cats
-            for line in cats.keys():
-                for layer in cats[line].keys():
-                    self.cats[line][layer] = list(cats[line][layer])
-            
-            layers = []
-            for layer in self.digit.GetLayers():
-                layers.append(str(layer))
-        
-        # make copy of cats (used for 'reload')
-        self.cats_orig = copy.deepcopy(self.cats)
-        
-        wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title,
-                           style = style, **kwargs)
-        
-        # list of categories
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("List of categories - right-click to delete"))
-        listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY,
-                                     style = wx.LC_REPORT |
-                                     wx.BORDER_NONE |
-                                     wx.LC_SORT_ASCENDING |
-                                     wx.LC_HRULES |
-                                     wx.LC_VRULES)
-        # sorter
-        self.fid = self.cats.keys()[0]
-        self.itemDataMap = self.list.Populate(self.cats[self.fid])
-        listmix.ColumnSorterMixin.__init__(self, 2)
-        self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
-                                  size = (150, -1))
-        self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
-        self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
-        if len(self.cats.keys()) == 1:
-            self.fidMulti.Show(False)
-            self.fidText.SetLabel(str(self.fid))
-        else:
-            self.fidText.Show(False)
-            choices = []
-            for fid in self.cats.keys():
-                choices.append(str(fid))
-            self.fidMulti.SetItems(choices)
-            self.fidMulti.SetSelection(0)
-        
-        listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND)
-
-        # add new category
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Add new category"))
-        addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(3)
-
-        layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                 label = "%s:" % _("Layer"))
-        self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1),
-                                  choices = layers)
-        if len(layers) > 0:
-            self.layerNew.SetSelection(0)
-        
-        catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
-                               label = "%s:" % _("Category"))
-
-        try:
-            newCat = max(self.cats[self.fid][1]) + 1
-        except KeyError:
-            newCat = 1
-        self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1),
-                                  initial = newCat, min = 0, max = 1e9)
-        btnAddCat = wx.Button(self, wx.ID_ADD)
-        flexSizer.Add(item = layerNewTxt, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = self.layerNew, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = catNewTxt, proportion = 0,
-                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
-                      border = 10)
-        flexSizer.Add(item = self.catNew, proportion = 0,
-                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(item = btnAddCat, proportion = 0,
-                      flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
-        addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        # buttons
-        btnApply = wx.Button(self, wx.ID_APPLY)
-        btnApply.SetToolTipString(_("Apply changes"))
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnCancel.SetToolTipString(_("Ignore changes and close dialog"))
-        btnOk = wx.Button(self, wx.ID_OK)
-        btnOk.SetToolTipString(_("Apply changes and close dialog"))
-        btnOk.SetDefault()
-
-        # sizers
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        #btnSizer.AddButton(btnReload)
-        #btnSizer.SetNegativeButton(btnReload)
-        btnSizer.AddButton(btnApply)
-        btnSizer.AddButton(btnOk)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = listSizer, proportion = 1,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        mainSizer.Add(item = addSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALIGN_CENTER |
-                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
-        fidSizer = wx.BoxSizer(wx.HORIZONTAL)
-        fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
-                                        label = _("Feature id:")),
-                     proportion = 0, border = 5,
-                     flag = wx.ALIGN_CENTER_VERTICAL)
-        fidSizer.Add(item = self.fidMulti, proportion = 0,
-                     flag = wx.EXPAND | wx.ALL,  border = 5)
-        fidSizer.Add(item = self.fidText, proportion = 0,
-                     flag = wx.EXPAND | wx.ALL,  border = 5)
-        mainSizer.Add(item = fidSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-        
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        self.SetAutoLayout(True)
-
-        # set min size for dialog
-        self.SetMinSize(self.GetBestSize())
-
-        # bindings
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
-        btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat)
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-                                     
-        # list
-        self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
-        self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
-        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
-        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
-        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
-
-    def GetListCtrl(self):
-        """!Used by ColumnSorterMixin
-        """
-        return self.list
-
-    def OnColClick(self, event):
-        """!Click on column header (order by)
-        """
-        event.Skip()
-        
-    def OnBeginEdit(self, event):
-        """!Editing of item started
-        """
-        event.Allow()
-
-    def OnEndEdit(self, event):
-        """!Finish editing of item
-        """
-        itemIndex = event.GetIndex()
-        layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
-        catOld = int (self.list.GetItem(itemIndex, 1).GetText())
-
-        if event.GetColumn() == 0:
-            layerNew = int(event.GetLabel())
-            catNew = catOld
-        else:
-            layerNew = layerOld
-            catNew = int(event.GetLabel())
-        
-        try:
-            if layerNew not in self.cats[self.fid].keys():
-                self.cats[self.fid][layerNew] = []
-            self.cats[self.fid][layerNew].append(catNew)
-            self.cats[self.fid][layerOld].remove(catOld)
-        except:
-            event.Veto()
-            self.list.SetStringItem(itemIndex, 0, str(layerNew))
-            self.list.SetStringItem(itemIndex, 1, str(catNew))
-            dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
-                                           "Layer and category number must be integer.\n"
-                                           "Layer number must be greater then zero.") %
-                                   { 'layer': self.layerNew.GetStringSelection(),
-                                     'category' : str(self.catNew.GetValue()) },
-                                   _("Error"), wx.OK | wx.ICON_ERROR)
-            dlg.ShowModal()
-            dlg.Destroy()
-            return False
-
-    def OnRightDown(self, event):
-        """!Mouse right button down
-        """
-        x = event.GetX()
-        y = event.GetY()
-        item, flags = self.list.HitTest((x, y))
-
-        if item !=  wx.NOT_FOUND and \
-                flags & wx.LIST_HITTEST_ONITEM:
-            self.list.Select(item)
-
-        event.Skip()
-
-    def OnRightUp(self, event):
-        """!Mouse right button up
-        """
-        if not hasattr(self, "popupID1"):
-            self.popupID1 = wx.NewId()
-            self.popupID2 = wx.NewId()
-            self.popupID3 = wx.NewId()
-            self.Bind(wx.EVT_MENU, self.OnItemDelete,    id = self.popupID1)
-            self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2)
-            self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
-
-        # generate popup-menu
-        menu = wx.Menu()
-        menu.Append(self.popupID1, _("Delete selected"))
-        if self.list.GetFirstSelected() == -1:
-            menu.Enable(self.popupID1, False)
-
-        menu.Append(self.popupID2, _("Delete all"))
-        menu.AppendSeparator()
-        menu.Append(self.popupID3, _("Reload"))
-
-        self.PopupMenu(menu)
-        menu.Destroy()
-
-    def OnItemSelected(self, event):
-        """!Item selected
-        """
-        event.Skip()
-
-    def OnItemDelete(self, event):
-        """!Delete selected item(s) from the list (layer/category pair)
-        """
-        item = self.list.GetFirstSelected()
-        while item != -1:
-            layer = int (self.list.GetItem(item, 0).GetText())
-            cat = int (self.list.GetItem(item, 1).GetText())
-            self.list.DeleteItem(item)
-            self.cats[self.fid][layer].remove(cat)
-
-            item = self.list.GetFirstSelected()
-            
-        event.Skip()
-        
-    def OnItemDeleteAll(self, event):
-        """!Delete all items from the list
-        """
-        self.list.DeleteAllItems()
-        self.cats[self.fid] = {}
-
-        event.Skip()
-
-    def OnFeature(self, event):
-        """!Feature id changed (on duplicates)
-        """
-        self.fid = int(event.GetString())
-        
-        self.itemDataMap = self.list.Populate(self.cats[self.fid],
-                                              update = True)
-
-        try:
-            newCat = max(self.cats[self.fid][1]) + 1
-        except KeyError:
-            newCat = 1
-            
-        self.catNew.SetValue(newCat)
-        
-        event.Skip()
-        
-    def _getCategories(self, coords, qdist):
-        """!Get layer/category pairs for all available
-        layers
-
-        Return True line found or False if not found
-        """
-        ret = gcmd.RunCommand('v.what',
-                              parent = self,
-                              quiet = True,
-                              map = self.vectorName,
-                              east_north = '%f,%f' % \
-                                  (float(coords[0]), float(coords[1])),
-                              distance = qdist)
-
-        if not ret:
-            return False
-
-        for item in ret.splitlines():
-            litem = item.lower()
-            if "id:" in litem: # get line id
-                self.line = int(item.split(':')[1].strip())
-            elif "layer:" in litem: # add layer
-                layer = int(item.split(':')[1].strip())
-                if layer not in self.cats.keys():
-                    self.cats[layer] = []
-            elif "category:" in litem: # add category
-                self.cats[layer].append(int(item.split(':')[1].strip()))
-
-        return True
-
-    def OnReload(self, event):
-        """!Reload button pressed
-        """
-        # restore original list
-        self.cats = copy.deepcopy(self.cats_orig)
-
-        # polulate list
-        self.itemDataMap = self.list.Populate(self.cats[self.fid],
-                                              update = True)
-
-        event.Skip()
-
-    def OnCancel(self, event):
-        """!Cancel button pressed
-        """
-        self.parent.parent.dialogs['category'] = None
-        if self.digit:
-            self.digit.GetDisplay().SetSelected([])
-            self.parent.UpdateMap(render = False)
-        else:
-            self.parent.parent.OnRender(None)
-            
-        self.Close()
-
-    def OnApply(self, event):
-        """!Apply button pressed
-        """
-        for fid in self.cats.keys():
-            newfid = self.ApplyChanges(fid)
-            if fid == self.fid and newfid > 0:
-                self.fid = newfid
-            
-    def ApplyChanges(self, fid):
-        """!Apply changes 
-
-        @param fid feature id
-        """
-        cats = self.cats[fid]
-        cats_orig = self.cats_orig[fid]
-
-        # action : (catsFrom, catsTo)
-        check = {'catadd': (cats,      cats_orig),
-                 'catdel': (cats_orig, cats)}
-
-        newfid = -1
-        
-        # add/delete new category
-        for action, catsCurr in check.iteritems():
-            for layer in catsCurr[0].keys():
-                catList = []
-                for cat in catsCurr[0][layer]:
-                    if layer not in catsCurr[1].keys() or \
-                            cat not in catsCurr[1][layer]:
-                        catList.append(cat)
-                if catList != []:
-                    if action == 'catadd':
-                        add = True
-                    else:
-                        add = False
-                        
-                    newfid = self.digit.SetLineCats(fid, layer,
-                                                    catList, add)
-                    if len(self.cats.keys()) == 1:
-                        self.fidText.SetLabel("%d" % newfid)
-                    else:
-                        choices = self.fidMulti.GetItems()
-                        choices[choices.index(str(fid))] = str(newfid)
-                        self.fidMulti.SetItems(choices)
-                        self.fidMulti.SetStringSelection(str(newfid))
-                    
-                    self.cats[newfid] = self.cats[fid]
-                    del self.cats[fid]
-                    
-                    fid = newfid
-                    if self.fid < 0:
-                        wx.MessageBox(parent = self, message = _("Unable to update vector map."),
-                                      caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
-        
-        self.cats_orig[fid] = copy.deepcopy(cats)
-        
-        return newfid
-
-    def OnOK(self, event):
-        """!OK button pressed
-        """
-        self.OnApply(event)
-        self.OnCancel(event)
-
-    def OnAddCat(self, event):
-        """!Button 'Add' new category pressed
-        """
-        try:
-            layer = int(self.layerNew.GetStringSelection())
-            cat   = int(self.catNew.GetValue())
-            if layer <= 0:
-                raise ValueError
-        except ValueError:
-            gcmd.GError(parent = self,
-                        message = _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
-                                    "Layer and category number must be integer.\n"
-                                    "Layer number must be greater then zero.") %
-                        {'layer' : str(self.layerNew.GetValue()),
-                         'category' : str(self.catNew.GetValue())})
-            return False
-        
-        if layer not in self.cats[self.fid].keys():
-            self.cats[self.fid][layer] = []
-        
-        self.cats[self.fid][layer].append(cat)
-        
-        # reload list
-        self.itemDataMap = self.list.Populate(self.cats[self.fid],
-                                              update = True)
-        
-        # update category number for add
-        self.catNew.SetValue(cat + 1)
-        
-        event.Skip()
-
-        return True
-
-    def GetLine(self):
-        """!Get id of selected line of 'None' if no line is selected
-        """
-        return self.cats.keys()
-
-    def UpdateDialog(self, query = None, cats = None):
-        """!Update dialog
-        
-        @param query {coordinates, distance} - v.what
-        @param cats  directory layer/cats    - vdigit
-        Return True if updated otherwise False
-        """
-        # line: {layer: [categories]}
-        self.cats = {}
-        # do not display dialog if no line is found (-> self.cats)
-        if cats is None:
-            ret = self._getCategories(query[0], query[1])
-        else:
-            self.cats = cats
-            for line in cats.keys():
-                for layer in cats[line].keys():
-                    self.cats[line][layer] = list(cats[line][layer])
-            ret = 1
-        if ret == 0 or len(self.cats.keys()) < 1:
-            Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
-            return False
-        
-        # make copy of cats (used for 'reload')
-        self.cats_orig = copy.deepcopy(self.cats)
-
-        # polulate list
-        self.fid = self.cats.keys()[0]
-        self.itemDataMap = self.list.Populate(self.cats[self.fid],
-                                              update = True)
-
-        try:
-            newCat = max(self.cats[self.fid][1]) + 1
-        except KeyError:
-            newCat = 1
-        self.catNew.SetValue(newCat)
-        
-        if len(self.cats.keys()) == 1:
-            self.fidText.Show(True)
-            self.fidMulti.Show(False)
-            self.fidText.SetLabel("%d" % self.fid)
-        else:
-            self.fidText.Show(False)
-            self.fidMulti.Show(True)
-            choices = []
-            for fid in self.cats.keys():
-                choices.append(str(fid))
-            self.fidMulti.SetItems(choices)
-            self.fidMulti.SetSelection(0)
-
-        self.Layout()
-        
-        return True
-
-class CategoryListCtrl(wx.ListCtrl,
-                       listmix.ListCtrlAutoWidthMixin,
-                       listmix.TextEditMixin):
-    def __init__(self, parent, id, pos = wx.DefaultPosition,
-                 size = wx.DefaultSize, style = 0):
-        """!List of layers/categories"""
-        self.parent = parent
-        
-        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
-
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        listmix.TextEditMixin.__init__(self)
-
-    def Populate(self, cats, update = False):
-        """!Populate the list
-        """
-        itemData = {} # requested by sorter
-
-        if not update:
-            self.InsertColumn(0, _("Layer"))
-            self.InsertColumn(1, _("Category"))
-        else:
-            self.DeleteAllItems()
-
-        i = 1
-        for layer in cats.keys():
-            catsList = cats[layer]
-            for cat in catsList:
-                index = self.InsertStringItem(sys.maxint, str(catsList[0]))
-                self.SetStringItem(index, 0, str(layer))
-                self.SetStringItem(index, 1, str(cat))
-                self.SetItemData(index, i)
-                itemData[i] = (str(layer), str(cat))
-                i = i + 1
-
-        if not update:
-            self.SetColumnWidth(0, 100)
-            self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
-
-        self.currentItem = 0
-
-        return itemData
-
-class VDigitZBulkDialog(wx.Dialog):
-    def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
-        """!Dialog used for Z bulk-labeling tool
-        """
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
-
-        self.parent = parent # mapdisplay.BufferedWindow class instance
-
-        # panel  = wx.Panel(parent=self, id=wx.ID_ANY)
-
-        border = wx.BoxSizer(wx.VERTICAL)
-        
-        txt = wx.StaticText(parent = self,
-                            label = _("%d lines selected for z bulk-labeling") % nselected);
-        border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
-
-        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value"))
-        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
-        flexSizer.AddGrowableCol(0)
-
-        # starting value
-        txt = wx.StaticText(parent = self,
-                            label = _("Starting value"));
-        self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
-                                 initial = 0,
-                                 min = -1e6, max = 1e6)
-        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-
-        # step
-        txt = wx.StaticText(parent = self,
-                            label = _("Step"))
-        self.step  = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
-                                 initial = 0,
-                                 min = 0, max = 1e6)
-        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
-        flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
-
-        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
-        border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
-
-        # buttons
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnOk = wx.Button(self, wx.ID_OK)
-        btnOk.SetDefault()
-
-        # sizers
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        btnSizer.AddButton(btnOk)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-
-class VDigitDuplicatesDialog(wx.Dialog):
-    def __init__(self, parent, data, title = _("List of duplicates"),
-                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
-                 pos = wx.DefaultPosition):
-        """!Show duplicated feature ids
-        """
-        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
-                           pos = pos)
-        
-        self.parent = parent # BufferedWindow
-        self.data = data
-        self.winList = []
-
-        # panel  = wx.Panel(parent=self, id=wx.ID_ANY)
-
-        # notebook
-        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
-
-        id = 1
-        for key in self.data.keys():
-            panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY)
-            self.notebook.AddPage(page = panel, text = " %d " % (id))
-            
-            # notebook body
-            border = wx.BoxSizer(wx.VERTICAL)
-
-            win = CheckListFeature(parent = panel, data = list(self.data[key]))
-            self.winList.append(win.GetId())
-
-            border.Add(item = win, proportion = 1,
-                       flag = wx.ALL | wx.EXPAND, border = 5)
-
-            panel.SetSizer(border)
-
-            id += 1
-
-        # buttons
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnOk = wx.Button(self, wx.ID_OK)
-        btnOk.SetDefault()
-
-        # sizers
-        btnSizer = wx.StdDialogButtonSizer()
-        btnSizer.AddButton(btnCancel)
-        btnSizer.AddButton(btnOk)
-        btnSizer.Realize()
-        
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
-        mainSizer.Add(item = btnSizer, proportion = 0,
-                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
-
-        self.SetSizer(mainSizer)
-        mainSizer.Fit(self)
-        self.SetAutoLayout(True)
-
-        # set min size for dialog
-        self.SetMinSize((250, 180))
-
-    def GetUnSelected(self):
-        """!Get unselected items (feature id)
-
-        @return list of ids
-        """
-        ids = []
-        for id in self.winList:
-            wlist = self.FindWindowById(id)
-
-            for item in range(wlist.GetItemCount()):
-                if not wlist.IsChecked(item):
-                    ids.append(int(wlist.GetItem(item, 0).GetText()))
-                    
-        return ids
-
-class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
-    def __init__(self, parent, data,
-                 pos = wx.DefaultPosition, log = None):
-        """!List of mapset/owner/group
-        """
-        self.parent = parent
-        self.data = data
-
-        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
-                             style = wx.LC_REPORT)
-
-        listmix.CheckListCtrlMixin.__init__(self)
-
-        self.log = log
-
-        # setup mixins
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-
-        self.LoadData(self.data)
-
-    def LoadData(self, data):
-        """!Load data into list
-        """
-        self.InsertColumn(0, _('Feature id'))
-        self.InsertColumn(1, _('Layer (Categories)'))
-
-        for item in data:
-            index = self.InsertStringItem(sys.maxint, str(item[0]))
-            self.SetStringItem(index, 1, str(item[1]))
-
-        # enable all items by default
-        for item in range(self.GetItemCount()):
-            self.CheckItem(item, True)
-
-        self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
-        self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
-                
-    def OnCheckItem(self, index, flag):
-        """!Mapset checked/unchecked
-        """
-        pass

Deleted: grass/trunk/gui/wxpython/gui_modules/workspace.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/workspace.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/workspace.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1637 +0,0 @@
-"""!
- at package workspace.py
-
- at brief Open/save workspace definition file
-
-Classes:
- - ProcessWorkspaceFile
- - Nviz
- - WriteWorkspaceFile
- - ProcessGrcFile
-
-(C) 2007-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
- at author Anna Kratochvilova <kratochanna gmail.com> (wxNviz / Google SoC 2011)
-"""
-
-import os
-import sys
-import copy
-import types
-
-import wx
-
-### for gxw (workspace file) parsering
-# xmlproc not available on Mac OS
-# from xml.parsers.xmlproc import xmlproc
-# from xml.parsers.xmlproc import xmlval
-# from xml.parsers.xmlproc import xmldtd
-try:
-    import xml.etree.ElementTree as etree
-except ImportError:
-    import elementtree.ElementTree as etree # Python <= 2.4
-
-import utils
-import globalvar
-from preferences import globalSettings as UserSettings
-
-try:
-    import wxnviz
-except ImportError:
-    wxnviz = None
-
-class ProcessWorkspaceFile:
-    def __init__(self, tree):
-        """!A ElementTree handler for the GXW XML file, as defined in
-        grass-gxw.dtd.
-        """
-        self.tree = tree
-        self.root = self.tree.getroot()
-        
-        #
-        # layer manager properties
-        #
-        self.layerManager = {}
-        self.layerManager['pos']  = None # window position
-        self.layerManager['size'] = None # window size
-        
-        #
-        # list of mapdisplays
-        #
-        self.displays = []
-        #
-        # list of map layers
-        #
-        self.layers = []
-        #
-        # nviz state
-        #
-        self.nviz_state = {}
-        
-        self.displayIndex = -1 # first display has index '0'
-        
-        self.__processFile()
-        
-        self.nvizDefault = Nviz()
-        
-    def __filterValue(self, value):
-        """!Filter value
-        
-        @param value
-        """
-        value = value.replace('&lt;', '<')
-        value = value.replace('&gt;', '>')
-        
-        return value
-
-    def __getNodeText(self, node, tag, default = ''):
-        """!Get node text"""
-        p = node.find(tag)
-        if p is not None:
-            return utils.normalize_whitespace(p.text)
-        
-        return default
-    
-    def __processFile(self):
-        """!Process workspace file"""
-        #
-        # layer manager
-        #
-        node_lm = self.root.find('layer_manager')
-        if node_lm is not None:
-            posAttr = node_lm.get('dim', '')
-            if posAttr:
-                posVal = map(int, posAttr.split(','))
-                try:
-                    self.layerManager['pos']  = (posVal[0], posVal[1])
-                    self.layerManager['size'] = (posVal[2], posVal[3])
-                except:
-                    pass
-        
-        #
-        # displays
-        #
-        for display in self.root.findall('display'):
-            self.displayIndex += 1
-            
-            # window position and size
-            posAttr = display.get('dim', '')
-            if posAttr:
-                posVal = map(int, posAttr.split(','))
-                try:
-                    pos  = (posVal[0], posVal[1])
-                    size = (posVal[2], posVal[3])
-                except:
-                    pos  = None
-                    size = None
-            else:
-                pos  = None
-                size = None
-            
-            extentAttr = display.get('extent', '')
-            if extentAttr:
-                # w, s, e, n
-                extent = map(float, extentAttr.split(','))
-            else:
-                extent = None
-            
-            # projection
-            node_projection = display.find('projection')
-            if node_projection is not None:
-                projection = { 'enabled' : True,
-                               'epsg' : node_projection.get('epsg', ''),
-                               'proj' : self.__getNodeText(node_projection, 'value') }
-            else:
-                projection = { 'enabled' : False }
-            
-            self.displays.append( {
-                    "render"         : bool(int(display.get('render', "0"))),
-                    "mode"           : int(display.get('mode', 0)),
-                    "showCompExtent" : bool(int(display.get('showCompExtent', "0"))),
-                    "pos"            : pos,
-                    "size"           : size,
-                    "extent"         : extent,
-                    "alignExtent"    : bool(int(display.get('alignExtent', "0"))),
-                    "constrainRes"   : bool(int(display.get('constrainRes', "0"))),
-                    "projection"     : projection,
-                    "viewMode"       : display.get('viewMode', '2d')} )
-            
-            # process all layers/groups in the display
-            self.__processLayers(display)
-            # process nviz_state
-            self.__processNvizState(display)
-
-    def __processLayers(self, node, inGroup = -1):
-        """!Process layers/groups of selected display
-        
-        @param node display tree node
-        @param inGroup in group -> index of group item otherwise -1
-        """
-        for item in node.getchildren():
-            if item.tag == 'group':
-                # -> group
-                self.layers.append( {
-                        "type"    : 'group',
-                        "name"    : item.get('name', ''),
-                        "checked" : bool(int(item.get('checked', "0"))),
-                        "opacity" : None,
-                        "cmd"     : None,
-                        "group"   : inGroup,
-                        "display" : self.displayIndex,
-                        "vdigit"  : None,
-                        "nviz"    : None})
-                
-                self.__processLayers(item, inGroup = len(self.layers) - 1) # process items in group
-                
-            elif item.tag == 'layer':
-                cmd, selected, vdigit, nviz = self.__processLayer(item)
-                
-                self.layers.append( {
-                        "type"     : item.get('type', None),
-                        "name"     : item.get('name', None),
-                        "checked"  : bool(int(item.get('checked', "0"))),
-                        "opacity"  : float(item.get('opacity', '1.0')),
-                        "cmd"      : cmd,
-                        "group"    : inGroup,
-                        "display"  : self.displayIndex,
-                        "selected" : selected,
-                        "vdigit"   : vdigit,
-                        "nviz"     : nviz } )
-            
-    def __processLayer(self, layer):
-        """!Process layer item
-
-        @param layer tree node
-        """
-        cmd = list()
-        
-        #
-        # layer attributes (task) - 2D settings
-        #
-        node_task = layer.find('task')
-        cmd.append(node_task.get('name', "unknown"))
-        
-        # flags
-        for p in node_task.findall('flag'):
-            flag = p.get('name', '')
-            if len(flag) > 1:
-                cmd.append('--' + flag)
-            else:
-                cmd.append('-' + flag)
-        
-        # parameters
-        for p in node_task.findall('parameter'):
-            cmd.append('%s=%s' % (p.get('name', ''),
-                                  self.__filterValue(self.__getNodeText(p, 'value'))))
-        
-        if layer.find('selected') is not None:
-            selected = True
-        else:
-            selected = False
-        
-        #
-        # Vector digitizer settings
-        #
-        node_vdigit = layer.find('vdigit')
-        if node_vdigit is not None:
-            vdigit = self.__processLayerVdigit(node_vdigit)
-        else:
-            vdigit = None
-        
-        #
-        # Nviz (3D settings)
-        #
-        node_nviz = layer.find('nviz')
-        if node_nviz is not None:
-            nviz = self.__processLayerNviz(node_nviz)
-        else:
-            nviz = None
-        
-        return (cmd, selected, vdigit, nviz)
-
-    def __processLayerVdigit(self, node_vdigit):
-        """!Process vector digitizer layer settings
-
-        @param node_vdigit vdigit node
-        """
-        # init nviz layer properties
-        vdigit = dict()
-        for node in node_vdigit.findall('geometryAttribute'):
-            if 'geomAttr' not in vdigit:
-                vdigit['geomAttr'] = dict()
-            type = node.get('type')
-            vdigit['geomAttr'][type] = dict()
-            vdigit['geomAttr'][type]['column'] = node.get('column') # required
-            # default map units
-            vdigit['geomAttr'][type]['units'] = node.get('units', 'mu')
-        
-        return vdigit
-    
-    def __processLayerNviz(self, node_nviz):
-        """!Process 3D layer settings
-
-        @param node_nviz nviz node
-        """
-        # init nviz layer properties
-        nviz = {}
-        if node_nviz.find('surface') is not None: # -> raster
-            nviz['surface'] = {}
-            for sec in ('attribute', 'draw', 'mask', 'position'):
-                nviz['surface'][sec] = {}
-        elif node_nviz.find('vlines') is not None or \
-                node_nviz.find('vpoints') is not None: # -> vector
-            nviz['vector'] = {}
-            for sec in ('lines', 'points'):
-                nviz['vector'][sec] = {}
-        
-        if 'surface' in nviz:
-            node_surface = node_nviz.find('surface')
-            # attributes
-            for attrb in node_surface.findall('attribute'):
-                tagName = str(attrb.tag)
-                attrbName = attrb.get('name', '')
-                dc = nviz['surface'][tagName][attrbName] = {}
-                if attrb.get('map', '0') == '0':
-                    dc['map'] = False
-                else:
-                    dc['map'] = True
-                value = self.__getNodeText(attrb, 'value')
-                try:
-                    dc['value'] = int(value)
-                except ValueError:
-                    try:
-                        dc['value'] = float(value)
-                    except ValueError:
-                        dc['value'] = str(value)
-            
-            # draw
-            node_draw = node_surface.find('draw')
-            if node_draw is not None:
-                tagName = str(node_draw.tag)
-                nviz['surface'][tagName]['all'] = False
-                nviz['surface'][tagName]['mode'] = {}
-                nviz['surface'][tagName]['mode']['value'] = -1 # to be calculated
-                nviz['surface'][tagName]['mode']['desc'] = {}
-                nviz['surface'][tagName]['mode']['desc']['shading'] = \
-                    str(node_draw.get('shading', ''))
-                nviz['surface'][tagName]['mode']['desc']['style'] = \
-                    str(node_draw.get('style', ''))
-                nviz['surface'][tagName]['mode']['desc']['mode'] = \
-                    str(node_draw.get('mode', ''))
-                
-                # resolution
-                for node_res in node_draw.findall('resolution'):
-                    resType = str(node_res.get('type', ''))
-                    if 'resolution' not in nviz['surface']['draw']:
-                        nviz['surface']['draw']['resolution'] = {}
-                    value = int(self.__getNodeText(node_res, 'value'))
-                    nviz['surface']['draw']['resolution'][resType] = value
-                
-                # wire-color
-                node_wire_color = node_draw.find('wire_color')
-                if node_wire_color is not None:
-                    nviz['surface']['draw']['wire-color'] = {}
-                    value = str(self.__getNodeText(node_wire_color, 'value'))
-                    nviz['surface']['draw']['wire-color']['value'] = value
-                
-            # position
-            node_pos = node_surface.find('position')
-            if node_pos is not None:
-                dc = nviz['surface']['position'] = {}
-                for coor in ['x', 'y', 'z']:
-                    node = node_pos.find(coor)
-                    if node is None:
-                        continue
-                    value = int(self.__getNodeText(node_pos, coor))
-                    dc[coor] = value
-            
-        elif 'vector' in nviz:
-            # vpoints
-            node_vpoints = node_nviz.find('vpoints')
-            if node_vpoints is not None:
-                marker = str(node_vpoints.get('marker', ''))
-                markerId = list(UserSettings.Get(group='nviz', key='vector',
-                                                 subkey=['points', 'marker'], internal=True)).index(marker)
-                nviz['vector']['points']['marker'] = { 'value' : markerId }
-                
-                node_mode = node_vpoints.find('mode')
-                if node_mode is not None:
-                    nviz['vector']['points']['mode'] = {}
-                    nviz['vector']['points']['mode']['type'] = str(node_mode.get('type', 'surface'))
-                    nviz['vector']['points']['mode']['surface'] = {}
-                    nviz['vector']['points']['mode']['surface']['value'] = []
-                    nviz['vector']['points']['mode']['surface']['show'] = []
-                    
-                    # map
-                    for node_map in node_mode.findall('map'):
-                        nviz['vector']['points']['mode']['surface']['value'].append(
-                            self.__processLayerNvizNode(node_map, 'name', str))
-                        nviz['vector']['points']['mode']['surface']['show'].append(bool(
-                            self.__processLayerNvizNode(node_map, 'checked', int)))
-                
-                # color
-                self.__processLayerNvizNode(node_vpoints, 'color', str,
-                                            nviz['vector']['points'])
-                
-                # width
-                self.__processLayerNvizNode(node_vpoints, 'width', int,
-                                            nviz['vector']['points'])
-                
-                # height
-                self.__processLayerNvizNode(node_vpoints, 'height', int,
-                                            nviz['vector']['points'])
-                
-                # height
-                self.__processLayerNvizNode(node_vpoints, 'size', int,
-                                            nviz['vector']['points'])
-                
-                # thematic
-                node_thematic = node_vpoints.find('thematic')
-                thematic = nviz['vector']['points']['thematic'] = {}
-                thematic['rgbcolumn'] = self.__processLayerNvizNode(node_thematic, 'rgbcolumn', str)
-                thematic['sizecolumn'] = self.__processLayerNvizNode(node_thematic, 'sizecolumn', str)
-                for col in ('rgbcolumn', 'sizecolumn'):
-                    if thematic[col] == 'None':
-                        thematic[col] = None
-                thematic['layer'] = self.__processLayerNvizNode(node_thematic, 'layer', int)
-                for use in ('usecolor', 'usesize', 'usewidth'):
-                    if node_thematic.get(use, ''):
-                        thematic[use] = int(node_thematic.get(use, '0'))
-                
-            # vlines
-            node_vlines = node_nviz.find('vlines')
-            if node_vlines is not None:
-                node_mode = node_vlines.find('mode')
-                if node_mode is not None:
-                    nviz['vector']['lines']['mode'] = {}
-                    nviz['vector']['lines']['mode']['type'] = str(node_mode.get('type', ''))
-                    nviz['vector']['lines']['mode']['surface'] = {}
-                    nviz['vector']['lines']['mode']['surface']['value'] = []
-                    nviz['vector']['lines']['mode']['surface']['show'] = []
-                    
-                    # map
-                    for node_map in node_mode.findall('map'):
-                        nviz['vector']['lines']['mode']['surface']['value'].append(
-                            self.__processLayerNvizNode(node_map, 'name', str))
-                        nviz['vector']['lines']['mode']['surface']['show'].append(bool(
-                            self.__processLayerNvizNode(node_map, 'checked', int)))
-                
-                # color
-                self.__processLayerNvizNode(node_vlines, 'color', str,
-                                            nviz['vector']['lines'])
-                
-                # width
-                self.__processLayerNvizNode(node_vlines, 'width', int,
-                                            nviz['vector']['lines'])
-                
-                # height
-                self.__processLayerNvizNode(node_vlines, 'height', int,
-                                            nviz['vector']['lines'])
-                
-                # thematic
-                node_thematic = node_vlines.find('thematic')
-                thematic = nviz['vector']['lines']['thematic'] = {}
-                thematic['rgbcolumn'] = self.__processLayerNvizNode(node_thematic, 'rgbcolumn', str)
-                thematic['sizecolumn'] = self.__processLayerNvizNode(node_thematic, 'sizecolumn', str)
-                for col in ('rgbcolumn', 'sizecolumn'):
-                    if thematic[col] == 'None':
-                        thematic[col] = None
-                thematic['layer'] = self.__processLayerNvizNode(node_thematic, 'layer', int)
-                for use in ('usecolor', 'usesize', 'usewidth'):
-                    if node_thematic.get(use, ''):
-                        thematic[use] = int(node_thematic.get(use, '0'))
-            
-        return nviz
-    
-    def __processLayerNvizNode(self, node, tag, cast, dc = None):
-        """!Process given tag nviz/vector"""
-        node_tag = node.find(tag)
-        if node_tag is not None:
-            if node_tag.find('value') is not None:
-                value = cast(self.__getNodeText(node_tag, 'value'))
-            else:
-                try:
-                    value = cast(node_tag.text)
-                except ValueError:
-                    if cast == str:
-                        value = ''
-                    else:
-                        value = None
-            if dc:
-                dc[tag] = dict()
-                dc[tag]['value'] = value
-            else:
-                return value
-    
-    def __processNvizState(self, node):
-        """!Process tag nviz_state"""
-        node_state = node.find('nviz_state')
-        if node_state is None:
-            return
-        self.nviz_state['display'] = self.displayIndex
-        #
-        # view
-        #
-        node_view = node_state.find('view')
-        view = {}
-        iview = {}
-        
-        node_position = node_view.find('v_position')
-        view['position'] = {}
-        view['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
-        view['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
-        node_persp = node_view.find('persp')
-        view['persp'] = {}
-        iview['persp'] = {}
-        view['persp']['value'] = self.__processLayerNvizNode(node_persp, 'value', int)
-        view['persp']['step'] = self.__processLayerNvizNode(node_persp, 'step', int)
-        iview['persp']['min'] = self.__processLayerNvizNode(node_persp, 'min', int)
-        iview['persp']['max'] = self.__processLayerNvizNode(node_persp, 'max', int)
-        node_height = node_view.find('v_height')
-        iview['height'] = {}
-        iview['height']['value'] = self.__processLayerNvizNode(node_height, 'value', int)
-        iview['height']['min'] = self.__processLayerNvizNode(node_height, 'min', int)
-        iview['height']['max'] = self.__processLayerNvizNode(node_height, 'max', int)
-        node_twist = node_view.find('twist')
-        view['twist'] = {}
-        iview['twist'] = {}
-        view['twist']['value'] = self.__processLayerNvizNode(node_twist, 'value', int)
-        iview['twist']['min'] = self.__processLayerNvizNode(node_twist, 'min', int)
-        iview['twist']['max'] = self.__processLayerNvizNode(node_twist, 'max', int)
-        node_zexag = node_view.find('z-exag')
-        view['z-exag'] = {}
-        iview['z-exag'] = {}
-        view['z-exag']['value'] = self.__processLayerNvizNode(node_zexag, 'value', int)
-        view['z-exag']['min'] = self.__processLayerNvizNode(node_zexag, 'min', int)
-        view['z-exag']['max'] = self.__processLayerNvizNode(node_zexag, 'max', int)
-        iview['z-exag']['original'] = self.__processLayerNvizNode(node_zexag, 'original', float)
-        node_focus = node_view.find('focus')
-        iview['focus'] = {}
-        iview['focus']['x'] = self.__processLayerNvizNode(node_focus, 'x', int)
-        iview['focus']['y'] = self.__processLayerNvizNode(node_focus, 'y', int)
-        iview['focus']['z'] = self.__processLayerNvizNode(node_focus, 'z', int)
-        node_dir = node_view.find('dir')
-        if node_dir:
-            iview['dir'] = {}
-            iview['dir']['x'] = self.__processLayerNvizNode(node_dir, 'x', int)
-            iview['dir']['y'] = self.__processLayerNvizNode(node_dir, 'y', int)
-            iview['dir']['z'] = self.__processLayerNvizNode(node_dir, 'z', int)
-            iview['dir']['use'] = True
-        else:
-            iview['dir'] = {}
-            iview['dir']['x'] = -1
-            iview['dir']['y'] = -1
-            iview['dir']['z'] = -1
-            iview['dir']['use'] = False
-        
-        view['background'] = {}
-        color = self.__processLayerNvizNode(node_view, 'background_color', str)
-        view['background']['color'] = tuple(map(int, color.split(':')))
-        
-        self.nviz_state['view'] = view
-        self.nviz_state['iview'] = iview
-        #
-        # light
-        #
-        node_light = node_state.find('light')
-        light = {}
-        
-        node_position = node_light.find('l_position')
-        light['position'] = {}
-        light['position']['x'] = self.__processLayerNvizNode(node_position, 'x', float)
-        light['position']['y'] = self.__processLayerNvizNode(node_position, 'y', float)
-        light['position']['z'] = self.__processLayerNvizNode(node_position, 'z', int)
-        
-        light['bright'] = self.__processLayerNvizNode(node_light, 'bright', int) 
-        light['ambient'] = self.__processLayerNvizNode(node_light, 'ambient', int)
-        color = self.__processLayerNvizNode(node_light, 'color', str)
-        light['color'] = tuple(map(int, color.split(':')))
-        
-        self.nviz_state['light'] = light
-        
-        node_constants = node_state.find('constant_planes')
-        constants = []
-        if node_constants:
-            for i, node_plane in enumerate(node_constants.findall('plane')):
-                plane = {}
-                plane['color'] = self.__processLayerNvizNode(node_plane, 'color', str)                
-                plane['resolution'] = self.__processLayerNvizNode(node_plane, 'fine_resolution', int)
-                plane['value'] = self.__processLayerNvizNode(node_plane, 'height', int)
-                plane['object'] = {}
-                constants.append({'constant': plane})
-        self.nviz_state['constants'] = constants    
-        
-class Nviz:
-    def __init__(self):
-        """Default 3D settings"""
-        UserSettings.Reset('nviz')
-        UserSettings.ReadSettingsFile()
-        
-    def SetConstantDefaultProp(self):
-        """Set default constant data properties"""
-        data = dict()
-        for key, value in UserSettings.Get(group='nviz', key='constant').iteritems():
-            data[key] = value
-        color = str(data['color'][0]) + ':' + str(data['color'][1]) + ':' + str(data['color'][2])
-        data['color'] = color
-
-        return data
-    
-    def SetSurfaceDefaultProp(self, data = None):
-        """Set default surface data properties"""
-        if not data:
-            data = dict()
-        for sec in ('attribute', 'draw', 'mask', 'position'):
-            data[sec] = {}
-        
-        #
-        # attributes
-        #
-        for attrb in ('shine', ):
-            data['attribute'][attrb] = {}
-            for key, value in UserSettings.Get(group='nviz', key='surface',
-                                               subkey=attrb).iteritems():
-                data['attribute'][attrb][key] = value
-            data['attribute'][attrb]['update'] = None
-        
-        #
-        # draw
-        #
-        data['draw']['all'] = False # apply only for current surface
-        for control, value in UserSettings.Get(group='nviz', key='surface', subkey='draw').iteritems():
-            if control[:3] == 'res':
-                if 'resolution' not in data['draw']:
-                    data['draw']['resolution'] = {}
-                if 'update' not in data['draw']['resolution']:
-                    data['draw']['resolution']['update'] = None
-                data['draw']['resolution'][control[4:]] = value
-                continue
-            
-            if control == 'wire-color':
-                value = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
-            elif control in ('mode', 'style', 'shading'):
-                if 'mode' not in data['draw']:
-                    data['draw']['mode'] = {}
-                continue
-
-            data['draw'][control] = { 'value' : value }
-            data['draw'][control]['update'] = None
-        
-        value, desc = self.GetDrawMode(UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'mode']),
-                                       UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'style']),
-                                       UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'shading']))
-    
-        data['draw']['mode'] = { 'value' : value,
-                                 'desc' : desc, 
-                                 'update': None }
-        # position
-        for coord in ('x', 'y', 'z'):
-            data['position'][coord] = UserSettings.Get(group='nviz', key='surface', subkey=['position', coord])
-        data['position']['update'] = None
-            
-        return data
-    
-    def SetVolumeDefaultProp(self):
-        """Set default volume data properties"""
-        data = dict()
-        for sec in ('attribute', 'draw', 'position'):
-            data[sec] = dict()
-            for sec in ('isosurface', 'slice'):
-                    data[sec] = list()
-        
-        #
-        # draw
-        #
-        for control, value in UserSettings.Get(group='nviz', key='volume', subkey='draw').iteritems():
-            if control == 'shading':
-                sel = UserSettings.Get(group='nviz', key='volume', subkey=['draw', 'shading'])
-                value, desc = self.GetDrawMode(shade=sel, string=False)
-                
-                data['draw']['shading'] = {}
-                data['draw']['shading']['isosurface'] = { 'value' : value,
-                                                          'desc' : desc['shading'] }
-                data['draw']['shading']['slice'] = { 'value' : value,
-                                                     'desc' : desc['shading'] }
-            elif control == 'mode':
-                sel = UserSettings.Get(group='nviz', key='volume', subkey=['draw', 'mode'])
-                if sel == 0:
-                    desc = 'isosurface'
-                else:
-                    desc = 'slice'
-                data['draw']['mode'] = { 'value' : sel,
-                                         'desc' : desc, }
-            else:
-                data['draw'][control] = {}
-                data['draw'][control]['isosurface'] = { 'value' : value }
-                data['draw'][control]['slice'] = { 'value' : value }
-
-            if 'update' not in data['draw'][control]:
-                data['draw'][control]['update'] = None
-        
-        #
-        # isosurface attributes
-        #
-        for attrb in ('shine', ):
-            data['attribute'][attrb] = {}
-            for key, value in UserSettings.Get(group='nviz', key='volume',
-                                               subkey=attrb).iteritems():
-                data['attribute'][attrb][key] = value
-        
-        return data
-    
-    def SetIsosurfaceDefaultProp(self):
-        """!Set default isosurface properties"""
-        data = dict()
-        for attr in ('shine', 'topo', 'transp', 'color'):
-            data[attr] = {}
-            for key, value in UserSettings.Get(group = 'nviz', key = 'volume',
-                                               subkey = attr).iteritems():
-                data[attr][key] = value
-            data[attr]['update'] = None
-        return data
-    
-    def SetSliceDefaultProp(self):
-        """!Set default slice properties"""
-        data = dict()
-        data['position'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'volume',
-                                               subkey = 'slice_position'))
-        data['position']['update'] = None
-        
-        data['transp'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'volume',
-                                               subkey = 'transp'))
-        return data
-    
-    def SetVectorDefaultProp(self, data = None):
-        """Set default vector data properties"""
-        if not data:
-            data = dict()
-        for sec in ('lines', 'points'):
-            data[sec] = {}
-        
-        self.SetVectorLinesDefaultProp(data['lines'])
-        self.SetVectorPointsDefaultProp(data['points'])
-
-        return data
-    
-    def SetVectorLinesDefaultProp(self, data):
-        """Set default vector properties -- lines"""
-        # width
-        data['width'] = {'value' : UserSettings.Get(group='nviz', key='vector',
-                                                    subkey=['lines', 'width']) }
-        
-        # color
-        value = UserSettings.Get(group='nviz', key='vector',
-                                 subkey=['lines', 'color'])
-        color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
-        data['color'] = { 'value' : color }
-
-        # mode
-        if UserSettings.Get(group='nviz', key='vector',
-                            subkey=['lines', 'flat']):
-            type = 'flat'
-            
-        else:
-            type = 'surface'
-            
-        data['mode'] = {}
-        data['mode']['type'] = type
-        data['mode']['update'] = None
-    
-        # height
-        data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['lines', 'height']) }
-        # thematic
-        data['thematic'] = {'rgbcolumn' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['lines', 'rgbcolumn']),
-                            'sizecolumn' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['lines', 'sizecolumn']),
-                            'layer': 1,
-                            'usecolor' : False,
-                            'usewidth' : False}
-        if 'object' in data:
-            for attrb in ('color', 'width', 'mode', 'height', 'thematic'):
-                data[attrb]['update'] = None
-        
-    def SetVectorPointsDefaultProp(self, data):
-        """Set default vector properties -- points"""
-        # size
-        data['size'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
-                                                    subkey=['points', 'size']) }
-
-        # width
-        data['width'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
-                                                     subkey=['points', 'width']) }
-
-        # marker
-        data['marker'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['points', 'marker']) }
-
-        # color
-        value = UserSettings.Get(group='nviz', key='vector',
-                                 subkey=['points', 'color'])
-        color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
-        data['color'] = { 'value' : color }
-
-        # mode
-        data['mode'] = { 'type' : 'surface'}
-##                         'surface' : '', }
-        
-        # height
-        data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['points', 'height']) }
-        
-        data['thematic'] = {'rgbcolumn' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['points', 'rgbcolumn']),
-                            'sizecolumn' : UserSettings.Get(group='nviz', key='vector',
-                                                      subkey=['points', 'sizecolumn']),
-                            'layer': 1,
-                            'usecolor' : False,
-                            'usesize' : False}
-        if 'object' in data:
-            for attrb in ('size', 'width', 'marker',
-                          'color', 'height', 'thematic'):
-                data[attrb]['update'] = None
-        
-    def GetDrawMode(self, mode=None, style=None, shade=None, string=False):
-        """Get surface draw mode (value) from description/selection
-
-        @param mode,style,shade modes
-        @param string if True input parameters are strings otherwise
-        selections
-        """
-        if not wxnviz:
-            return None
-        
-        value = 0
-        desc = {}
-
-        if string:
-            if mode is not None:
-                if mode == 'coarse':
-                    value |= wxnviz.DM_WIRE
-                elif mode == 'fine':
-                    value |= wxnviz.DM_POLY
-                else: # both
-                    value |= wxnviz.DM_WIRE_POLY
-
-            if style is not None:
-                if style == 'wire':
-                    value |= wxnviz.DM_GRID_WIRE
-                else: # surface
-                    value |= wxnviz.DM_GRID_SURF
-                    
-            if shade is not None:
-                if shade == 'flat':
-                    value |= wxnviz.DM_FLAT
-                else: # surface
-                    value |= wxnviz.DM_GOURAUD
-
-            return value
-
-        # -> string is False
-        if mode is not None:
-            if mode == 0: # coarse
-                value |= wxnviz.DM_WIRE
-                desc['mode'] = 'coarse'
-            elif mode == 1: # fine
-                value |= wxnviz.DM_POLY
-                desc['mode'] = 'fine'
-            else: # both
-                value |= wxnviz.DM_WIRE_POLY
-                desc['mode'] = 'both'
-
-        if style is not None:
-            if style == 0: # wire
-                value |= wxnviz.DM_GRID_WIRE
-                desc['style'] = 'wire'
-            else: # surface
-                value |= wxnviz.DM_GRID_SURF
-                desc['style'] = 'surface'
-
-        if shade is not None:
-            if shade == 0:
-                value |= wxnviz.DM_FLAT
-                desc['shading'] = 'flat'
-            else: # surface
-                value |= wxnviz.DM_GOURAUD
-                desc['shading'] = 'gouraud'
-        
-        return (value, desc)
-    
-    def SetDecorDefaultProp(self, type):
-        """!Set default arrow properties
-        """
-        data = {}
-        
-        # arrow
-        if type == 'arrow':
-            data['arrow'] = UserSettings.Get(group = 'nviz', key = 'arrow')
-            data['arrow']['color'] = "%d:%d:%d" % (
-                UserSettings.Get(group = 'nviz', key = 'arrow', subkey = 'color')[:3])
-            data['arrow'].update(UserSettings.Get(group = 'nviz', key = 'arrow', internal = True))
-            data['arrow']['show'] = False
-        
-        # arrow
-        if type == 'scalebar':
-            data['scalebar'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'scalebar'))
-            data['scalebar']['color'] = "%d:%d:%d" % (
-                UserSettings.Get(group = 'nviz', key = 'scalebar', subkey = 'color')[:3])
-            data['scalebar'].update(copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'scalebar', internal = True)))
-            data['scalebar']['id'] = 0
-        return data
-    
-class WriteWorkspaceFile(object):
-    """!Generic class for writing workspace file"""
-    def __init__(self, lmgr, file):
-        self.file =  file
-        self.lmgr = lmgr
-        self.indent = 0
-        
-        # write header
-        self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
-        self.file.write('<!DOCTYPE gxw SYSTEM "grass-gxw.dtd">\n')
-        self.file.write('%s<gxw>\n' % (' ' * self.indent))
-        
-        self.indent =+ 4
-        
-        # layer manager
-        windowPos = self.lmgr.GetPosition()
-        windowSize = self.lmgr.GetSize()
-        file.write('%s<layer_manager dim="%d,%d,%d,%d">\n' % (' ' * self.indent,
-                                                              windowPos[0],
-                                                              windowPos[1],
-                                                              windowSize[0],
-                                                              windowSize[1]
-                                                              ))
-        
-        file.write('%s</layer_manager>\n' % (' ' * self.indent))
-        
-        # list of displays
-        for page in range(0, self.lmgr.gm_cb.GetPageCount()):
-            mapTree = self.lmgr.gm_cb.GetPage(page).maptree
-            region = mapTree.Map.region
-            
-            displayPos = mapTree.mapdisplay.GetPosition()
-            displaySize = mapTree.mapdisplay.GetSize()
-            if mapTree.mapdisplay.toolbars['map'].combo.GetSelection() == 1:
-                viewmode = '3d'
-            else:
-                viewmode = '2d'
-            
-            file.write('%s<display render="%d" '
-                       'mode="%d" showCompExtent="%d" '
-                       'alignExtent="%d" '
-                       'constrainRes="%d" '
-                       'dim="%d,%d,%d,%d" '
-                       'extent="%f,%f,%f,%f" '
-                       'viewMode="%s" >\n' % (' ' * self.indent,
-                                              int(mapTree.mapdisplay.GetProperty('render')),
-                                              mapTree.mapdisplay.statusbarManager.GetMode(),
-                                              int(mapTree.mapdisplay.GetProperty('region')),
-                                              int(mapTree.mapdisplay.GetProperty('alignExtent')),
-                                              int(mapTree.mapdisplay.GetProperty('resolution')),
-                                              displayPos[0],
-                                              displayPos[1],
-                                              displaySize[0],
-                                              displaySize[1],
-                                              region['w'],
-                                              region['s'],
-                                              region['e'],
-                                              region['n'],
-                                              viewmode
-                                              ))
-            # projection statusbar info
-            if mapTree.mapdisplay.GetProperty('projection') and \
-                    UserSettings.Get(group='display', key='projection', subkey='proj4'):
-                self.indent += 4
-                file.write('%s<projection' % (' ' * self.indent))
-                epsg = UserSettings.Get(group='display', key='projection', subkey='epsg')
-                if epsg:
-                    file.write(' epsg="%s"' % epsg)
-                file.write('>\n')
-                proj = UserSettings.Get(group='display', key='projection', subkey='proj4')
-                self.indent += 4 
-                file.write('%s<value>%s</value>\n' % (' ' * self.indent, proj))
-                self.indent -= 4
-                file.write('%s</projection>\n' % (' ' * self.indent))
-                self.indent -= 4
-            
-            # list of layers
-            item = mapTree.GetFirstChild(mapTree.root)[0]
-            self.__writeLayer(mapTree, item)
-            
-            if mapTree.mapdisplay.MapWindow3D is not None:
-                nvizDisp = mapTree.mapdisplay.MapWindow3D
-                self.__writeNvizState(view = nvizDisp.view, iview =  nvizDisp.iview, 
-                                      light = nvizDisp.light, constants = nvizDisp.constants)
-            
-            file.write('%s</display>\n' % (' ' * self.indent))
-        
-        self.indent =- 4
-        file.write('%s</gxw>\n' % (' ' * self.indent))
-
-    def __filterValue(self, value):
-        """!Make value XML-valid"""
-        value = value.replace('<', '&lt;')
-        value = value.replace('>', '&gt;')
-        
-        return value
-    
-    def __writeLayer(self, mapTree, item):
-        """!Write bunch of layers to GRASS Workspace XML file"""
-        self.indent += 4
-        itemSelected = mapTree.GetSelections()
-        while item and item.IsOk():
-            type = mapTree.GetPyData(item)[0]['type']
-            if type != 'group':
-                maplayer = mapTree.GetPyData(item)[0]['maplayer']
-            else:
-                maplayer = None
-
-            checked = int(item.IsChecked())
-            if type == 'command':
-                cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string=True)
-                self.file.write('%s<layer type="%s" name="%s" checked="%d">\n' % \
-                               (' ' * self.indent, type, cmd, checked));
-                self.file.write('%s</layer>\n' % (' ' * self.indent));
-            elif type == 'group':
-                name = mapTree.GetItemText(item)
-                self.file.write('%s<group name="%s" checked="%d">\n' % \
-                               (' ' * self.indent, name.encode('utf8'), checked));
-                self.indent += 4
-                subItem = mapTree.GetFirstChild(item)[0]
-                self.__writeLayer(mapTree, subItem)
-                self.indent -= 4
-                self.file.write('%s</group>\n' % (' ' * self.indent));
-            else:
-                cmd = mapTree.GetPyData(item)[0]['maplayer'].GetCmd(string=False)
-                name = mapTree.GetItemText(item)
-                opacity = maplayer.GetOpacity(float = True)
-                # remove 'opacity' part
-                if opacity < 1:
-                    name = name.split('(', -1)[0].strip()
-                self.file.write('%s<layer type="%s" name="%s" checked="%d" opacity="%f">\n' % \
-                                    (' ' * self.indent, type, name.encode('utf8'), checked, opacity));
-                
-                self.indent += 4
-                # selected ?
-                if item in itemSelected:
-                    self.file.write('%s<selected />\n' % (' ' * self.indent))
-                # layer properties
-                self.file.write('%s<task name="%s">\n' % (' ' * self.indent, cmd[0]))
-                self.indent += 4
-                for key, val in cmd[1].iteritems():
-                    if key == 'flags':
-                        for f in val:
-                            self.file.write('%s<flag name="%s" />\n' %
-                                            (' ' * self.indent, f))
-                    elif val in (True, False):
-                        self.file.write('%s<flag name="%s" />\n' %
-                                        (' ' * self.indent, key))
-                    else: # parameter
-                        self.file.write('%s<parameter name="%s">\n' %
-                                        (' ' * self.indent, key))
-                        self.indent += 4
-                        self.file.write('%s<value>%s</value>\n' %
-                                        (' ' * self.indent, self.__filterValue(val)))
-                        self.indent -= 4
-                        self.file.write('%s</parameter>\n' % (' ' * self.indent));
-                self.indent -= 4
-                self.file.write('%s</task>\n' % (' ' * self.indent));
-                # vector digitizer
-                vdigit = mapTree.GetPyData(item)[0]['vdigit']
-                if vdigit:
-                    self.file.write('%s<vdigit>\n' % (' ' * self.indent))
-                    if 'geomAttr' in vdigit:
-                        self.indent += 4
-                        for type, val in vdigit['geomAttr'].iteritems():
-                            units = ''
-                            if val['units'] != 'mu':
-                                units = ' units="%s"' % val['units']
-                            self.file.write('%s<geometryAttribute type="%s" column="%s"%s />\n' % \
-                                                (' ' * self.indent, type, val['column'], units))
-                        self.indent -= 4
-                    self.file.write('%s</vdigit>\n' % (' ' * self.indent))
-                # nviz
-                nviz = mapTree.GetPyData(item)[0]['nviz']
-                if nviz:
-                    self.file.write('%s<nviz>\n' % (' ' * self.indent))
-                    if maplayer.type == 'raster':
-                        self.__writeNvizSurface(nviz['surface'])
-                    elif maplayer.type == 'vector':
-                        self.__writeNvizVector(nviz['vector'])
-                    self.file.write('%s</nviz>\n' % (' ' * self.indent))
-                self.indent -= 4
-                self.file.write('%s</layer>\n' % (' ' * self.indent))
-            item = mapTree.GetNextSibling(item)
-        self.indent -= 4
-        
-    def __writeNvizSurface(self, data):
-        """!Save Nviz raster layer properties to workspace
-
-        @param data Nviz layer properties
-        """
-        if 'object' not in data: # skip disabled
-            return
-        self.indent += 4
-        self.file.write('%s<surface>\n' % (' ' * self.indent))
-        self.indent += 4
-        for attrb in data.iterkeys():
-            if len(data[attrb]) < 1: # skip empty attributes
-                continue
-            if attrb == 'object':
-                continue
-            
-            for name in data[attrb].iterkeys():
-                # surface attribute
-                if attrb == 'attribute':
-                    self.file.write('%s<%s name="%s" map="%d">\n' % \
-                                   (' ' * self.indent, attrb, name, data[attrb][name]['map']))
-                    self.indent += 4
-                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
-                    self.indent -= 4
-                    # end tag
-                    self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
-
-            # draw mode
-            if attrb == 'draw':
-                self.file.write('%s<%s' %(' ' * self.indent, attrb))
-                if 'mode' in data[attrb]:
-                    for tag, value in data[attrb]['mode']['desc'].iteritems():
-                        self.file.write(' %s="%s"' % (tag, value))
-                self.file.write('>\n') # <draw ...>
-
-                if 'resolution' in data[attrb]:
-                    self.indent += 4
-                    for type in ('coarse', 'fine'):
-                        self.file.write('%s<resolution type="%s">\n' % (' ' * self.indent, type))
-                        self.indent += 4
-                        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent,
-                                                                   data[attrb]['resolution'][type]))
-                        self.indent -= 4
-                        self.file.write('%s</resolution>\n' % (' ' * self.indent))
-
-                if 'wire-color' in data[attrb]:
-                    self.file.write('%s<wire_color>\n' % (' ' * self.indent))
-                    self.indent += 4
-                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent,
-                                                               data[attrb]['wire-color']['value']))
-                    self.indent -= 4
-                    self.file.write('%s</wire_color>\n' % (' ' * self.indent))
-                self.indent -= 4
-            
-            # position
-            elif attrb == 'position':
-                self.file.write('%s<%s>\n' %(' ' * self.indent, attrb))
-                i = 0
-                for tag in ('x', 'y', 'z'):
-                    self.indent += 4
-                    self.file.write('%s<%s>%d</%s>\n' % (' ' * self.indent, tag,
-                                                        data[attrb][tag], tag))
-                    i += 1
-                    self.indent -= 4
-
-            if attrb != 'attribute':
-                # end tag
-                self.file.write('%s</%s>\n' % (' ' * self.indent, attrb))
-
-        self.indent -= 4
-        self.file.write('%s</surface>\n' % (' ' * self.indent))
-        self.indent -= 4
-
-    def __writeNvizVector(self, data):
-        """!Save Nviz vector layer properties (lines/points) to workspace
-
-        @param data Nviz layer properties
-        """
-        self.indent += 4
-        for attrb in data.iterkeys():
-            if len(data[attrb]) < 1: # skip empty attributes
-                continue
-
-            if 'object' not in data[attrb]: # skip disabled
-                continue
-            if attrb == 'lines':
-                self.file.write('%s<v%s>\n' % (' ' * self.indent, attrb))
-            elif attrb == 'points':
-                markerId = data[attrb]['marker']['value']
-                marker = UserSettings.Get(group = 'nviz', key = 'vector',
-                                          subkey = ['points', 'marker'], internal = True)[markerId]
-                self.file.write('%s<v%s marker="%s">\n' % (' ' * self.indent,
-                                                           attrb,
-                                                           marker))
-            self.indent += 4
-            for name in data[attrb].iterkeys():
-                if name in ('object', 'marker'):
-                    continue
-                if name == 'mode':
-                    self.file.write('%s<%s type="%s">\n' % (' ' * self.indent, name,
-                                                          data[attrb][name]['type']))
-                    if data[attrb][name]['type'] == 'surface':
-                        self.indent += 4
-                        for idx, surface in enumerate(data[attrb][name]['surface']['value']):
-                            checked = data[attrb][name]['surface']['show'][idx]
-                            self.file.write('%s<map>\n' % (' ' * self.indent))
-                            self.indent += 4
-                            self.file.write('%s<name>%s</name>\n' % (' ' * self.indent, surface))
-                            self.file.write('%s<checked>%s</checked>\n' % (' ' * self.indent, int(checked)))
-                            self.indent -= 4
-                            self.file.write('%s</map>\n' % (' ' * self.indent))
-                        self.indent -= 4
-                    self.file.write('%s</%s>\n' % ((' ' * self.indent, name)))
-                elif name == 'thematic':
-                    self.file.write('%s<%s ' % (' ' * self.indent, name))
-                    for key in data[attrb][name].iterkeys():
-                        if key.startswith('use'):
-                            self.file.write('%s="%s" ' % (key, int(data[attrb][name][key])))
-                    self.file.write('>\n')
-                    self.indent += 4
-                    for key, value in data[attrb][name].iteritems():
-                        if key.startswith('use'):
-                            continue
-                        if value is None:
-                            value = ''
-                        self.file.write('%s<%s>%s</%s>\n' % (' ' * self.indent, key, value, key))
-                    self.indent -= 4
-                    self.file.write('%s</%s>\n' % (' ' * self.indent, name))
-                else:
-                    self.file.write('%s<%s>\n' % (' ' * self.indent, name))
-                    self.indent += 4
-                    self.file.write('%s<value>%s</value>\n' % (' ' * self.indent, data[attrb][name]['value']))
-                    self.indent -= 4
-                    self.file.write('%s</%s>\n' % (' ' * self.indent, name))
-            self.indent -= 4
-            self.file.write('%s</v%s>\n' % (' ' * self.indent, attrb))
-
-        self.indent -= 4
-
-    def __writeNvizState(self, view, iview, light, constants):
-        """"!Save Nviz properties (view, light) to workspace
-
-        @param view Nviz view properties
-        @param iview Nviz internal view properties
-        @param light Nviz light properties
-        """
-        self.indent += 4
-        self.file.write('%s<nviz_state>\n' % (' ' * self.indent))
-        #
-        # view
-        #
-        self.indent += 4
-        self.file.write('%s<view>\n' % (' ' * self.indent))
-        self.indent += 4
-        # position
-        self.file.write('%s<v_position>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, view['position']['x']))
-        self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, view['position']['y']))
-        self.indent -= 4
-        self.file.write('%s</v_position>\n' % (' ' * self.indent))
-        # perspective
-        self.file.write('%s<persp>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['persp']['value']))
-        self.file.write('%s<step>%d</step>\n' % (' ' * self.indent, view['persp']['step']))
-        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['persp']['min']))
-        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['persp']['max']))
-        self.indent -= 4
-        self.file.write('%s</persp>\n' % (' ' * self.indent))
-        # height
-        self.file.write('%s<v_height>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, iview['height']['value']))
-        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['height']['min']))
-        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['height']['max']))
-        self.indent -= 4
-        self.file.write('%s</v_height>\n' % (' ' * self.indent))
-        # twist
-        self.file.write('%s<twist>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['twist']['value']))
-        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, iview['twist']['min']))
-        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, iview['twist']['max']))
-        self.indent -= 4
-        self.file.write('%s</twist>\n' % (' ' * self.indent))
-        # z-exag
-        self.file.write('%s<z-exag>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<value>%d</value>\n' % (' ' * self.indent, view['z-exag']['value']))
-        self.file.write('%s<min>%d</min>\n' % (' ' * self.indent, view['z-exag']['min']))
-        self.file.write('%s<max>%d</max>\n' % (' ' * self.indent, view['z-exag']['max']))
-        self.file.write('%s<original>%d</original>\n' % (' ' * self.indent, iview['z-exag']['original']))
-        self.indent -= 4
-        self.file.write('%s</z-exag>\n' % (' ' * self.indent))
-        # focus (look here)
-        self.file.write('%s<focus>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<x>%d</x>\n' % (' ' * self.indent, iview['focus']['x']))
-        self.file.write('%s<y>%d</y>\n' % (' ' * self.indent, iview['focus']['y']))
-        self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, iview['focus']['z']))
-        self.indent -= 4
-        self.file.write('%s</focus>\n' % (' ' * self.indent))
-        # background
-        self.__writeTagWithValue('background_color', view['background']['color'][:3], format = 'd:%d:%d')
-        
-        self.indent -= 4
-        self.file.write('%s</view>\n' % (' ' * self.indent))
-        #
-        # light
-        #
-        self.file.write('%s<light>\n' % (' ' * self.indent))
-        self.indent += 4
-        # position
-        self.file.write('%s<l_position>\n' % (' ' * self.indent))
-        self.indent += 4
-        self.file.write('%s<x>%.2f</x>\n' % (' ' * self.indent, light['position']['x']))
-        self.file.write('%s<y>%.2f</y>\n' % (' ' * self.indent, light['position']['y']))
-        self.file.write('%s<z>%d</z>\n' % (' ' * self.indent, light['position']['z']))
-        self.indent -= 4
-        self.file.write('%s</l_position>\n' % (' ' * self.indent))
-        # bright
-        self.__writeTagWithValue('bright', light['bright'])
-        # ambient
-        self.__writeTagWithValue('ambient', light['ambient'])
-        # color
-        self.__writeTagWithValue('color', light['color'][:3], format = 'd:%d:%d')
-        
-        self.indent -= 4
-        self.file.write('%s</light>\n' % (' ' * self.indent))
-        #
-        # constant planes
-        #
-        if constants:
-            self.file.write('%s<constant_planes>\n' % (' ' * self.indent))
-            self.indent += 4
-            for idx, plane in enumerate(constants):
-                self.file.write('%s<plane>\n' % (' ' * self.indent))
-                self.indent += 4
-                self.__writeTagWithValue('height', constants[idx]['constant']['value'])
-                self.__writeTagWithValue('fine_resolution', constants[idx]['constant']['resolution'])
-                self.__writeTagWithValue('color', constants[idx]['constant']['color'], format = 's')
-                self.indent -= 4
-                self.file.write('%s</plane>\n' % (' ' * self.indent))
-            self.indent -= 4
-            self.file.write('%s</constant_planes>\n' % (' ' * self.indent))
-        self.indent -= 4
-        
-        self.file.write('%s</nviz_state>\n' % (' ' * self.indent))
-        self.indent -= 4
-    
-    def __writeTagWithValue(self, tag, data, format = 'd'):
-        """!Helper function for writing pair tag
-        
-        @param tag written tag
-        @param data written data
-        @param format conversion type
-        """
-        self.file.write('%s<%s>\n' % (' ' * self.indent, tag))
-        self.indent += 4
-        self.file.write('%s' % (' ' * self.indent))
-        self.file.write(('<value>%' + format + '</value>\n') % data)
-        self.indent -= 4
-        self.file.write('%s</%s>\n' % (' ' * self.indent, tag))
-        
-class ProcessGrcFile(object):
-    def __init__(self, filename):
-        """!Process GRC file"""
-        self.filename = filename
-
-        # elements
-        self.inGroup = False
-        self.inRaster = False
-        self.inVector = False
-
-        # list of layers
-        self.layers = []
-
-        # error message
-        self.error = ''
-        self.num_error = 0
-
-    def read(self, parent):
-        """!Read GRC file
-
-        @param parent parent window
-
-        @return list of map layers
-        """
-        try:
-            file = open(self.filename, "r")
-        except IOError:
-            wx.MessageBox(parent=parent,
-                          message=_("Unable to open file <%s> for reading.") % self.filename,
-                          caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
-            return []
-
-        line_id = 1
-        for line in file.readlines():
-            self.process_line(line.rstrip('\n'), line_id)
-            line_id +=1
-
-        file.close()
-
-        if self.num_error > 0:
-            wx.MessageBox(parent=parent,
-                          message=_("Some lines were skipped when reading settings "
-                                    "from file <%(file)s>.\nSee 'Command output' window for details.\n\n"
-                                    "Number of skipped lines: %(line)d") % \
-                                        { 'file' : self.filename, 'line' : self.num_error },
-                          caption=_("Warning"), style=wx.OK | wx.ICON_EXCLAMATION)
-            parent.goutput.WriteLog('Map layers loaded from GRC file <%s>' % self.filename)
-            parent.goutput.WriteLog('Skipped lines:\n%s' % self.error)
-
-        return self.layers
-
-    def process_line(self, line, line_id):
-        """!Process line definition"""
-        element = self._get_element(line)
-        if element == 'Group':
-            self.groupName = self._get_value(line)
-            self.layers.append({
-                    "type"    : 'group',
-                    "name"    : self.groupName,
-                    "checked" : None,
-                    "opacity" : None,
-                    "cmd"     : None,
-                    "group"   : self.inGroup,
-                    "display" : 0 })
-            self.inGroup = True
-
-        elif element == '_check':
-            if int(self._get_value(line)) ==  1:
-                self.layers[-1]['checked'] = True
-            else:
-                self.layers[-1]['checked'] = False
-            
-        elif element == 'End':
-            if self.inRaster:
-                self.inRaster = False
-            elif self.inVector:
-                self.inVector = False
-            elif self.inGroup:
-                self.inGroup = False
-            elif self.inGridline:
-                self.inGridline = False
-        
-        elif element == 'opacity':
-            self.layers[-1]['opacity'] = float(self._get_value(line))
-
-        # raster
-        elif element == 'Raster':
-            self.inRaster = True
-            self.layers.append({
-                    "type"    : 'raster',
-                    "name"    : self._get_value(line),
-                    "checked" : None,
-                    "opacity" : None,
-                    "cmd"     : ['d.rast'],
-                    "group"   : self.inGroup,
-                    "display" : 0})
-
-        elif element == 'map' and self.inRaster:
-            self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
-            
-        elif element == 'overlay' and self.inRaster:
-            if int(self._get_value(line)) == 1:
-                self.layers[-1]['cmd'].append('-o')
-            
-        elif element == 'rastquery' and self.inRaster:
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('catlist=%s' % value)
-            
-        elif element == 'bkcolor' and self.inRaster:
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('bg=%s' % value)
-
-        # vector
-        elif element == 'Vector':
-            self.inVector = True
-            self.layers.append({
-                    "type"    : 'vector',
-                    "name"    : self._get_value(line),
-                    "checked" : None,
-                    "opacity" : None,
-                    "cmd"     : ['d.vect'],
-                    "group"   : self.inGroup,
-                    "display" : 0})
-
-        elif element == 'vect' and self.inVector:
-            self.layers[-1]['cmd'].append('map=%s' % self._get_value(line))
-                
-        elif element in ('display_shape',
-                         'display_cat',
-                         'display_topo',
-                         'display_dir',
-                         'display_attr',
-                         'type_point',
-                         'type_line',
-                         'type_boundary',
-                         'type_centroid',
-                         'type_area',
-                         'type_face') and self.inVector:
-            
-            if int(self._get_value(line)) == 1:
-                name = element.split('_')[0]
-                type = element.split('_')[1]
-                paramId = self._get_cmd_param_index(self.layers[-1]['cmd'], name)
-                if paramId == -1:
-                    self.layers[-1]['cmd'].append('%s=%s' % (name, type))
-                else:
-                    self.layers[-1]['cmd'][paramId] += ',%s' % type
-
-        elif element in ('color',
-                         'fcolor',
-                         'lcolor') and self.inVector:
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('%s=%s' % (element,
-                                                         self._color_name_to_rgb(value)))
-
-        elif element == 'rdmcolor' and self.inVector:
-            if int(self._get_value(line)) == 1:
-                self.layers[-1]['cmd'].append('-c')
-
-        elif element == 'sqlcolor' and self.inVector:
-            if int(self._get_value(line)) == 1:
-                self.layers[-1]['cmd'].append('-a')
-
-        elif element in ('icon',
-                         'size',
-                         'layer',
-                         'xref',
-                         'yref',
-                         'lsize',
-                         'where',
-                         'minreg',
-                         'maxreg') and self.inVector:
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('%s=%s' % (element,
-                                                         value))
-        
-        elif element == 'lwidth':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('width=%s' % value)
-
-        elif element == 'lfield':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('llayer=%s' % value)
-                                        
-        elif element == 'attribute':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('attrcol=%s' % value)
-
-        elif element == 'cat':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('cats=%s' % value)
-
-        # gridline
-        elif element == 'gridline':
-            self.inGridline = True
-            self.layers.append({
-                    "type"    : 'grid',
-                    "name"    : self._get_value(line),
-                    "checked" : None,
-                    "opacity" : None,
-                    "cmd"     : ['d.grid'],
-                    "group"   : self.inGroup,
-                    "display" : 0})
-
-        elif element == 'gridcolor':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('color=%s' % self._color_name_to_rgb(value))
-
-        elif element == 'gridborder':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('bordercolor=%s' % self._color_name_to_rgb(value))
-
-        elif element == 'textcolor':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('textcolor=%s' % self._color_name_to_rgb(value))
-
-        elif element in ('gridsize',
-                         'gridorigin'):
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('%s=%s' % (element[4:], value))
-
-        elif element in 'fontsize':
-            value = self._get_value(line)
-            if value != '':
-                self.layers[-1]['cmd'].append('%s=%s' % (element, value))
-        
-        elif element == 'griddraw':
-            value = self._get_value(line)
-            if value == '0':
-                self.layers[-1]['cmd'].append('-n')
-                
-        elif element == 'gridgeo':
-            value = self._get_value(line)
-            if value == '1':
-                self.layers[-1]['cmd'].append('-g')
-        
-        elif element == 'borderdraw':
-            value = self._get_value(line)
-            if value == '0':
-                self.layers[-1]['cmd'].append('-b')
-
-        elif element == 'textdraw':
-            value = self._get_value(line)
-            if value == '0':
-                self.layers[-1]['cmd'].append('-t')
-        
-        else:
-            self.error += _(' row %d:') % line_id + line + os.linesep
-            self.num_error += 1
-
-    def _get_value(self, line):
-        """!Get value of element"""
-        try:
-            return line.strip(' ').split(' ')[1].strip(' ')
-        except:
-            return ''
-
-    def _get_element(self, line):
-        """!Get element tag"""
-        return line.strip(' ').split(' ')[0].strip(' ')
-
-    def _get_cmd_param_index(self, cmd, name):
-        """!Get index of parameter in cmd list
-
-        @param cmd cmd list
-        @param name parameter name
-
-        @return index
-        @return -1 if not found
-        """
-        i = 0
-        for param in cmd:
-            if '=' not in param:
-                i += 1
-                continue
-            if param.split('=')[0] == name:
-                return i
-
-            i += 1
-
-        return -1
-
-    def _color_name_to_rgb(self, value):
-        """!Convert color name (#) to rgb values"""
-        col = wx.NamedColour(value)
-        return str(col.Red()) + ':' + \
-            str(col.Green()) + ':' + \
-            str(col.Blue())

Deleted: grass/trunk/gui/wxpython/gui_modules/wxnviz.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxnviz.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/wxnviz.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,2092 +0,0 @@
-"""!
- at package wxnviz.py
-
- at brief wxGUI 3D view mode
-
-This module implements 3D visualization mode for map display (ctypes
-required).
-
-List of classes:
- - Nviz
- - Texture
-
-(C) 2008-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
- at author Pythonized by Glynn Clements
- at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
-"""
-
-import wx
-import sys
-import locale
-import struct
-from threading import Thread
-from math import sqrt
-from numpy import matrix
-
-from ctypes import *
-try:
-    from grass.lib.gis      import *
-    from grass.lib.raster3d import *
-    from grass.lib.vector   import *
-    from grass.lib.ogsf     import *
-    from grass.lib.nviz     import *
-    from grass.lib.raster   import *
-except ImportError, e:
-    sys.stderr.write(_("3D view mode: %s\n") % e)
-    
-from debug import Debug
-import grass.script as grass
-
-log      = None
-progress = None
-
-def print_error(msg, type):
-    """!Redirect stderr"""
-    global log
-    if log:
-        log.write(msg)
-    else:
-        print msg
-    
-    return 0
-
-def print_progress(value):
-    """!Redirect progress info"""
-    global progress
-    if progress:
-        progress.SetValue(value)
-    else:
-        print value
-    
-    return 0
-
-errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
-errfunc = errtype(print_error)
-pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
-perfunc = pertype(print_progress)
-
-class Nviz(object):
-    def __init__(self, glog, gprogress):
-        """!Initialize Nviz class instance
-        
-        @param log logging area
-        @param gprogress progressbar
-        """
-        global errfunc, perfunc, log, progress
-        log = glog
-        progress = gprogress
-        
-        G_gisinit("wxnviz")
-        # gislib is already initialized (where?)
-        G_set_error_routine(errfunc) 
-        G_set_percent_routine(perfunc)
-        
-        self.Init()
-        
-        self.data_obj = nv_data()
-        self.data = pointer(self.data_obj)
-        self.color_obj = Colors()
-        self.color = pointer(self.color_obj)
-        
-        self.width = self.height = -1
-        self.showLight = False
-        
-        Debug.msg(1, "Nviz::Nviz()")
-        
-    def __del__(self):
-        """!Destroy Nviz class instance"""
-        G_unset_error_routine()
-        G_unset_percent_routine()
-        del self.data
-        del self.data_obj
-        self.log = None
-
-    def Init(self):
-        """!Initialize window"""
-        locale.setlocale(locale.LC_NUMERIC, 'C')
-        G_unset_window()
-        Rast_unset_window()
-        Rast__init_window()
-        GS_libinit()
-        GVL_libinit()
-    
-    def ResizeWindow(self, width, height):
-        """!GL canvas resized
-        
-        @param width window width
-        @param height window height
-        
-        @return 1 on success
-        @return 0 on failure (window resized by default to 20x20 px)
-        """
-        self.width  = width
-        self.height = height
-        Debug.msg(3, "Nviz::ResizeWindow(): width=%d height=%d",
-                  width, height)
-        return Nviz_resize_window(width, height)
-    
-    def GetLongDim(self):
-        """!Get longest dimension, used for initial size of north arrow"""
-        return Nviz_get_longdim(self.data)
-    
-    def SetViewDefault(self):
-        """!Set default view (based on loaded data)
-        
-        @return z-exag value, default, min and max height
-        """
-        # determine z-exag
-        z_exag = Nviz_get_exag()
-        Nviz_change_exag(self.data, z_exag)
-        
-        # determine height
-        hdef = c_double()
-        hmin = c_double()
-        hmax = c_double()
-        Nviz_get_exag_height(byref(hdef), byref(hmin), byref(hmax))
-        
-        Debug.msg(1, "Nviz::SetViewDefault(): hdef=%f, hmin=%f, hmax=%f",
-                  hdef.value, hmin.value, hmax.value)
-        
-        return (z_exag, hdef.value, hmin.value, hmax.value)
-    
-    def SetView(self, x, y, height, persp, twist):
-        """!Change view settings
-        @param x,y position
-        @param height
-        @param persp perpective
-        @param twist
-        """
-        Nviz_set_viewpoint_height(height)
-        Nviz_set_viewpoint_position(x, y)
-        Nviz_set_viewpoint_twist(twist)
-        Nviz_set_viewpoint_persp(persp)
-        
-        Debug.msg(3, "Nviz::SetView(): x=%f, y=%f, height=%f, persp=%f, twist=%f",
-                  x, y, height, persp, twist)
-                
-    def GetViewpointPosition(self):
-        x = c_double()
-        y = c_double()
-        h = c_double()
-        Nviz_get_viewpoint_height(byref(h))
-        Nviz_get_viewpoint_position(byref(x), byref(y))
-        
-        return (x.value, y.value, h.value)
-        
-    def LookHere(self, x, y):
-        """!Look here feature 
-        @param x,y screen coordinates
-        """
-        
-        Nviz_look_here(x, y)
-        Debug.msg(3, "Nviz::LookHere(): x=%f, y=%f", x, y)
-    
-    def LookAtCenter(self):
-        """!Center view at center of displayed surface"""
-        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
-        Debug.msg(3, "Nviz::LookAtCenter()")
-    
-    def GetFocus(self):
-        """!Get focus"""
-        Debug.msg(3, "Nviz::GetFocus()")
-        if Nviz_has_focus(self.data):
-            x = c_float()
-            y = c_float()
-            z = c_float()
-            Nviz_get_focus(self.data, byref(x), byref(y), byref(z))
-            return x.value, y.value, z.value
-        else:
-            return -1, -1, -1
-        
-    def SetFocus(self, x, y, z):
-        """!Set focus"""
-        Debug.msg(3, "Nviz::SetFocus()")
-        Nviz_set_focus(self.data, x, y, z)
-        
-    def GetViewdir(self):
-        """!Get viewdir"""
-        Debug.msg(3, "Nviz::GetViewdir()")
-        dir = (c_float * 3)()
-        GS_get_viewdir(byref(dir))
-        
-        return dir[0], dir[1], dir[2]
-        
-    def SetViewdir(self, x, y, z):
-        """!Set viewdir"""
-        Debug.msg(3, "Nviz::SetViewdir(): x=%f, y=%f, z=%f" % (x, y, z))
-        dir = (c_float * 3)()
-        for i, coord in enumerate((x, y, z)):
-            dir[i] = coord
-        GS_set_viewdir(byref(dir))
-                
-    def SetZExag(self, z_exag):
-        """!Set z-exag value
-        
-        @param z_exag value
-        
-        @return 1
-        """
-        Debug.msg(3, "Nviz::SetZExag(): z_exag=%f", z_exag)
-        return Nviz_change_exag(self.data, z_exag)
-    
-    def Draw(self, quick, quick_mode):
-        """!Draw canvas
-        
-        Draw quick mode:
-         - DRAW_QUICK_SURFACE
-         - DRAW_QUICK_VLINES
-         - DRAW_QUICK_VPOINTS
-         - DRAW_QUICK_VOLUME
-        
-        @param quick if true draw in wiremode
-        @param quick_mode quick mode
-        """
-        Debug.msg(3, "Nviz::Draw(): quick=%d", quick)
-        
-        Nviz_draw_cplane(self.data, -1, -1) # ?
-        
-        if quick:
-            Nviz_draw_quick(self.data, quick_mode)
-        else:
-            Nviz_draw_all(self.data)
-        
-    def EraseMap(self):
-        """!Erase map display (with background color)
-        """
-        Debug.msg(1, "Nviz::EraseMap()")
-        GS_clear(Nviz_get_bgcolor(self.data))
-        
-    def InitView(self):
-        """!Initialize view"""
-        # initialize nviz data
-        Nviz_init_data(self.data)
-        
-        # define default attributes for map objects
-        Nviz_set_surface_attr_default()
-        # set background color
-        Nviz_set_bgcolor(self.data, Nviz_color_from_str("white"))
-        
-        GS_clear(Nviz_get_bgcolor(self.data))        
-        # initialize view, lights
-        Nviz_init_view(self.data)
-        
-        Debug.msg(1, "Nviz::InitView()")
-        
-    def SetBgColor(self, color_str):
-        """!Set background color
-        
-        @param color_str color string
-        """
-        Nviz_set_bgcolor(self.data, Nviz_color_from_str(color_str))
-        
-    def SetLight(self, x, y, z, color, bright, ambient, w = 0, lid = 1):
-        """!Change lighting settings
-        @param x,y,z position
-        @param color light color (as string)
-        @param bright light brightness
-        @param ambient light ambient
-        @param w local coordinate (default to 0)
-        """
-        Nviz_set_light_position(self.data, lid, x, y, z, w)
-        Nviz_set_light_bright(self.data, lid, bright)
-        Nviz_set_light_color(self.data, lid, int(color[0]), int(color[1]), int(color[2]))
-        Nviz_set_light_ambient(self.data, lid, ambient)
-                             
-    def LoadSurface(self, name, color_name, color_value):
-        """!Load raster map (surface)
-        
-        @param name raster map name
-        @param color_name raster map for color (None for color_value)
-        @param color_value color string (named color or RGB triptet)
-        
-        @return object id
-        @return -1 on failure
-        """
-        mapset = G_find_raster2(name, "")
-        if mapset is None:
-            G_warning(_("Raster map <%s> not found"), name)
-            return -1
-        
-        # topography
-        id = Nviz_new_map_obj(MAP_OBJ_SURF,
-                              G_fully_qualified_name(name, mapset), 0.0,
-                              self.data)
-        
-        if color_name:      # check for color map
-            mapset = G_find_raster2(color_name, "")
-            if mapset is None:
-                G_warning(_("Raster map <%s> not found"), color_name)
-                GS_delete_surface(id)
-                return -1
-            
-            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
-                          G_fully_qualified_name(color_name, mapset), -1.0,
-                          self.data)
-        
-        elif color_value:   # check for color value
-            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, CONST_ATT,
-                          None, Nviz_color_from_str(color_value),
-                          self.data)
-        
-        else:               # use by default elevation map for coloring
-            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
-                          G_fully_qualified_name(name, mapset), -1.0,
-                          self.data)
-        
-        # if (i > 1)
-        #     set_default_wirecolors(self.data, i)
-        
-        # focus on loaded self.data
-        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
-        
-        Debug.msg(1, "Nviz::LoadRaster(): name=%s -> id=%d", name, id)
-        
-        return id
-    
-    def AddConstant(self, value, color):
-        """!Add new constant surface"""
-        id = Nviz_new_map_obj(MAP_OBJ_SURF, None, value, self.data)
-        
-        Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, CONST_ATT,
-                        None, Nviz_color_from_str(color),
-                        self.data)
-        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
-        
-        Debug.msg(1, "Nviz::AddConstant(): id=%d", id)
-        return id
-        
-    def UnloadSurface(self, id):
-        """!Unload surface
-        
-        @param id surface id
-        
-        @return 1 on success
-        @return 0 on failure
-        """
-        if not GS_surf_exists(id):
-            return 0
-        
-        Debug.msg(1, "Nviz::UnloadSurface(): id=%d", id)
-        
-        if GS_delete_surface(id) < 0:
-            return 0
-        
-        return 1
-    
-    def LoadVector(self, name, points):
-        """!Load vector map overlay
-        
-        @param name vector map name
-        @param points if true load 2d points rather then 2d lines
-        
-        @return object id, id of base surface (or -1 if it is not loaded)
-        @return -1 on failure
-        """
-        baseId = -1
-        if GS_num_surfs() == 0:     # load base surface if no loaded
-            baseId = Nviz_new_map_obj(MAP_OBJ_SURF, None, 0.0, self.data)
-            
-            nsurf = c_int()
-            surf_list = GS_get_surf_list(byref(nsurf))
-            GS_set_att_const(surf_list[0], ATT_TRANSP, 255)
-            
-        mapset = G_find_vector2 (name, "")
-        if mapset is None:
-            G_warning(_("Vector map <%s> not found"),
-                      name)
-        
-        if points:
-            id = Nviz_new_map_obj(MAP_OBJ_SITE,
-                                  G_fully_qualified_name(name, mapset), 0.0,
-                                  self.data)
-        else:
-            id = Nviz_new_map_obj(MAP_OBJ_VECT,
-                                  G_fully_qualified_name(name, mapset), 0.0,
-                                  self.data)
-        
-        Debug.msg(1, "Nviz::LoadVector(): name=%s -> id=%d", name, id)
-        
-        return id, baseId
-    
-    def UnloadVector(self, id, points):
-        """!Unload vector set
-        
-        @param id vector set id
-        @param points vector points or lines set
-        
-        @return 1 on success
-        @return 0 on failure
-        """
-        Debug.msg(1, "Nviz::UnloadVector(): id=%d", id)
-        
-        if points:
-            if not GP_site_exists(id):
-                return 0
-            if GP_delete_site(id) < 0:
-                return 0
-        else:
-            if not GV_vect_exists(id):
-                return 0
-            if GV_delete_vector(id) < 0:
-                return 0
-        
-        return 1
-
-    def VectorSurfaceSelected(self, vid, sid):
-        """!Check if surface is selected (currently unused)
-        
-        @param vid vector id
-        @param sid surface id
-        
-        @return True if selected
-        @return False if not selected
-        """
-        selected = GV_surf_is_selected(vid, sid)
-        Debug.msg(1, "Nviz::VectorSurfaceSelected(): vid=%s, sid=%d -> selected=%d", vid, sid, selected)
-        return selected
-    
-    def LoadVolume(self, name, color_name, color_value):
-        """!Load 3d raster map (volume)
-        
-        @param name 3d raster map name
-        @param color_name 3d raster map for color (None for color_value)
-        @param color_value color string (named color or RGB triptet)
-        
-        @return object id
-        @return -1 on failure
-        """
-        mapset = G_find_raster3d(name, "")
-        if mapset is None:
-            G_warning(_("3d raster map <%s> not found"),
-                      name)
-            return -1
-        
-        # topography
-        id = Nviz_new_map_obj(MAP_OBJ_VOL,
-                              G_fully_qualified_name(name, mapset), 0.0,
-                              self.data)
-        
-        if color_name:      # check for color map
-            mapset = G_find_raster3d(color_name, "")
-            if mapset is None:
-                G_warning(_("3d raster map <%s> not found"),
-                          color_name)
-                GVL_delete_vol(id)
-                return -1
-            
-            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, MAP_ATT,
-                          G_fully_qualified_name(color_name, mapset), -1.0,
-                          self.data)
-        elif color_value:   # check for color value
-            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, CONST_ATT,
-                          None, Nviz_color_from_str(color_value),
-                          self.data)
-        else:               # use by default elevation map for coloring
-            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, MAP_ATT,
-                          G_fully_qualified_name(name, mapset), -1.0,
-                          self.data)
-        
-        Debug.msg(1, "Nviz::LoadVolume(): name=%s -> id=%d", name, id)
-        
-        return id
-
-    def UnloadVolume(self, id):
-        """!Unload volume
-        
-        @param id volume id
-        
-        @return 1 on success
-        @return 0 on failure
-        """
-        if not GVL_vol_exists(id):
-            return 0
-        
-        Debug.msg(1, "Nviz::UnloadVolume(): id=%d", id)
-        
-        if GVL_delete_vol(id) < 0:
-          return 0
-        
-        return 1
-    
-    def SetSurfaceTopo(self, id, map, value):
-        """!Set surface topography
-        
-        @param id surface id
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_TOPO, map, value)
-    
-    def SetSurfaceColor(self, id, map, value):
-        """!Set surface color
-        
-        @param id surface id
-        @param map if true use map otherwise constant
-        @param value map name or value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_COLOR, map, value)
-    
-    def SetSurfaceMask(self, id, invert, value):
-        """!Set surface mask
-        
-        @todo invert
-        
-        @param id surface id
-        @param invert if true invert mask 
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_MASK, True, value)
-    
-    def SetSurfaceTransp(self, id, map, value):
-        """!Set surface mask
-        
-        @todo invert
-        
-        @param id surface id
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_TRANSP, map, value)
-    
-    def SetSurfaceShine(self, id, map, value):
-        """!Set surface shininess
-        
-        @param id surface id
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_SHINE, map, value)
-    
-    def SetSurfaceEmit(self, id, map, value):
-        """!Set surface emission (currently unused)
-        
-        @param id surface id
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.SetSurfaceAttr(id, ATT_EMIT, map, value)
-    
-    def SetSurfaceAttr(self, id, attr, map, value):
-        """!Set surface attribute
-        
-        @param id surface id
-        @param attr attribute desc
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        if not GS_surf_exists(id):
-            return -1
-        
-        if map:
-            ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, MAP_ATT,
-                                value, -1.0, self.data)
-        else:
-            if attr == ATT_COLOR:
-                val = Nviz_color_from_str(value)
-            else:
-                val = float(value)
-            
-            ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, CONST_ATT,
-                                None, val, self.data)
-        
-        Debug.msg(3, "Nviz::SetSurfaceAttr(): id=%d, attr=%d, map=%d, value=%s",
-                  id, attr, map, value)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def UnsetSurfaceMask(self, id):
-        """!Unset surface mask
-        
-        @param id surface id
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        @return -1 on failure
-        """
-        return self.UnsetSurfaceAttr(id, ATT_MASK)
-    
-    def UnsetSurfaceTransp(self, id):
-        """!Unset surface transparency
-        
-        @param id surface id
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.UnsetSurfaceAttr(id, ATT_TRANSP)
-    
-    def UnsetSurfaceEmit(self, id):
-        """!Unset surface emission (currently unused)
-        
-        @param id surface id
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        return self.UnsetSurfaceAttr(id, ATT_EMIT)
-    
-    def UnsetSurfaceAttr(self, id, attr):
-        """!Unset surface attribute
-        
-        @param id surface id
-        @param attr attribute descriptor
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        if not GS_surf_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::UnsetSurfaceAttr(): id=%d, attr=%d",
-                  id, attr)
-        
-        ret = Nviz_unset_attr(id, MAP_OBJ_SURF, attr)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-
-    def SetSurfaceRes(self, id, fine, coarse):
-        """!Set surface resolution
-        
-        @param id surface id
-        @param fine x/y fine resolution
-        @param coarse x/y coarse resolution
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        Debug.msg(3, "Nviz::SetSurfaceRes(): id=%d, fine=%d, coarse=%d",
-                  id, fine, coarse)
-        
-        if id > 0:
-            if not GS_surf_exists(id):
-                return -1
-            
-            if GS_set_drawres(id, fine, fine, coarse, coarse) < 0:
-                return -2
-        else:
-            GS_setall_drawres(fine, fine, coarse, coarse)
-        
-        return 1
-
-    def SetSurfaceStyle(self, id, style):
-        """!Set draw style
-        
-        Draw styles:
-         - DM_GOURAUD
-         - DM_FLAT
-         - DM_FRINGE
-         - DM_WIRE
-         - DM_COL_WIRE
-         - DM_POLY
-         - DM_WIRE_POLY
-         - DM_GRID_WIRE
-         - DM_GRID_SURF
-         
-        @param id surface id (<= 0 for all)
-        @param style draw style
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        """
-        Debug.msg(3, "Nviz::SetSurfaceStyle(): id=%d, style=%d",
-                  id, style)
-        
-        if id > 0:
-            if not GS_surf_exists(id):
-                return -1
-            
-            if GS_set_drawmode(id, style) < 0:
-                return -2
-            
-            return 1
-        
-        if GS_setall_drawmode(style) < 0:
-            return -2
-        
-        return 1
-    
-    def SetWireColor(self, id, color_str):
-        """!Set color of wire
-        
-        @todo all
-         
-        @param surface id (< 0 for all)
-        @param color color string (R:G:B)
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting attributes failed
-        @return 1 on success
-        @return 0 on failure
-        """
-        Debug.msg(3, "Nviz::SetWireColor(): id=%d, color=%s",
-                  id, color_str)
-        
-        color = Nviz_color_from_str(color_str)
-        
-        if id > 0:
-            if not GS_surf_exists(id):
-                return -1
-            
-            GS_set_wire_color(id, color)
-        else:
-            nsurfs = c_int()
-            surf_list = GS_get_surf_list(byref(nsurfs))
-            for i in xrange(nsurfs.value):
-                id = surf_list[i]
-                GS_set_wire_color(id, color)
-            
-            G_free(surf_list)
-            surf_list = None
-        
-        return 1
-    
-    def GetSurfacePosition(self, id):
-        """!Get surface position
-        
-        @param id surface id
-        
-        @return x,y,z
-        @return zero-length vector on error
-        """
-        if not GS_surf_exists(id):
-            return []
-        
-        x, y, z = c_float(), c_float(), c_float()
-        GS_get_trans(id, byref(x), byref(y), byref(z))
-        
-        Debug.msg(3, "Nviz::GetSurfacePosition(): id=%d, x=%f, y=%f, z=%f",
-                  id, x.value, y.value, z.value)
-        
-        return [x.value, y.value, z.value]
-
-    def SetSurfacePosition(self, id, x, y, z):
-        """!Set surface position
-        
-        @param id surface id
-        @param x,y,z translation values
-        
-        @return 1 on success
-        @return -1 surface not found
-        @return -2 setting position failed
-        """
-        if not GS_surf_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetSurfacePosition(): id=%d, x=%f, y=%f, z=%f",
-                  id, x, y, z)
-        
-        GS_set_trans(id, x, y, z)
-        
-        return 1
-
-    def SetVectorLineMode(self, id, color_str, width, flat):
-        """!Set mode of vector line overlay
-        
-        @param id vector id
-        @param color_str color string
-        @param width line width
-        @param flat display flat or on surface
-        
-        @return -1 vector set not found
-        @return -2 on failure
-        @return 1 on success
-        """
-        if not GV_vect_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetVectorMode(): id=%d, color=%s, width=%d, flat=%d",
-                  id, color_str, width, flat)
-        
-        color = Nviz_color_from_str(color_str)
-        
-        # use memory by default
-        if GV_set_style(id, 1, color, width, flat) < 0:
-            return -2
-        
-        return 1
-
-    def SetVectorLineHeight(self, id, height):
-        """!Set vector height above surface (lines)
-        
-        @param id vector set id
-        @param height
-        
-        @return -1 vector set not found
-        @return 1 on success
-        """
-        if not GV_vect_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetVectorLineHeight(): id=%d, height=%f",
-                  id, height)
-        
-        GV_set_trans(id, 0.0, 0.0, height)
-        
-        return 1
-
-    def SetVectorLineSurface(self, id, surf_id):
-        """!Set reference surface of vector set (lines)
-        
-        @param id vector set id
-        @param surf_id surface id
-        
-        @return 1 on success
-        @return -1 vector set not found
-        @return -2 surface not found
-        @return -3 on failure
-        """
-        if not GV_vect_exists(id):
-            return -1
-        
-        if not GS_surf_exists(surf_id):
-            return -2
-        
-        if GV_select_surf(id, surf_id) < 0:
-            return -3
-        
-        return 1
-
-    def UnsetVectorLineSurface(self, id, surf_id):
-        """!Unset reference surface of vector set (lines)
-        
-        @param id vector set id
-        @param surf_id surface id
-        
-        @return 1 on success
-        @return -1 vector set not found
-        @return -2 surface not found
-        @return -3 on failure
-        """
-        if not GV_vect_exists(id):
-            return -1
-        
-        if not GS_surf_exists(surf_id):
-            return -2
-        
-        if GV_unselect_surf(id, surf_id) < 0:
-            return -3
-        
-        return 1
-        
-    def SetVectorPointMode(self, id, color_str, width, size, marker):
-        """!Set mode of vector point overlay
-        
-        @param id vector id
-        @param color_str color string
-        @param width line width
-        @param flat
-        
-        @return -1 vector set not found
-        """
-        if not GP_site_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetVectorPointMode(): id=%d, color=%s, "
-                  "width=%d, size=%f, marker=%d",
-                  id, color_str, width, size, marker)
-        
-        color = Nviz_color_from_str(color_str)
-        
-        if GP_set_style(id, color, width, size, marker) < 0:
-            return -2
-        
-        return 1
-
-    def SetVectorPointHeight(self, id, height):
-        """!Set vector height above surface (points)
-        
-        @param id vector set id
-        @param height
-        
-        @return -1 vector set not found
-        @return 1 on success
-        """
-        if not GP_site_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetVectorPointHeight(): id=%d, height=%f",
-                  id, height)
-        
-        GP_set_trans(id, 0.0, 0.0, height)
-        
-        return 1
-
-    def SetVectorPointSurface(self, id, surf_id):
-        """!Set reference surface of vector set (points)
-        
-        @param id vector set id
-        @param surf_id surface id
-        
-        @return 1 on success
-        @return -1 vector set not found
-        @return -2 surface not found
-        @return -3 on failure
-        """
-        if not GP_site_exists(id):
-            return -1
-        
-        if not GS_surf_exists(surf_id):
-            return -2
-        
-        if GP_select_surf(id, surf_id) < 0:
-            return -3
-        
-        return 1
-
-    def ReadVectorColors(self, name, mapset):
-        """!Read vector colors
-        
-        @param name vector map name
-        @mapset mapset name ("" for search path)
-        
-        @return -1 on error 
-        @return 0 if color table missing 
-        @return 1 on success (color table found) 
-        """
-        return Vect_read_colors(name, mapset, self.color)
-        
-    def CheckColorTable(self, id, type):
-        """!Check if color table exists.
-        
-        @param id vector set id
-        @param type vector set type (lines/points)
-        
-        @return 1 color table exists
-        @return 0 no color table found
-        @return -1 on error
-        @return -2 vector set not found
-        """
-        file = c_char_p()
-        
-        if type == 'points':
-            ret = GP_get_sitename(id, byref(file))
-        elif type == 'lines':
-            ret = GV_get_vectname(id, byref(file))
-            
-        if ret < 0:
-            return -2
-        
-        return self.ReadVectorColors(file, "")
-        
-    def SetPointsStyleThematic(self, id, layer, color = None, colorTable = False, 
-                               width = None, size = None, symbol = None):
-        """!Set thematic style for vector points
-        
-        @param id vector set id
-        @param layer layer number for thematic mapping
-        @param colorTable use color table 
-        @param color color column name 
-        @param width width column name 
-        @param size size column name 
-        @param symbol symbol column name 
-        """
-        file = c_char_p()
-        ret = GP_get_sitename(id, byref(file))
-        if ret < 0:
-            return -1
-        
-        ret = self.ReadVectorColors(file, "")
-        if ret < 0:
-            return -1
-        
-        if colorTable:
-            GP_set_style_thematic(id, layer, color, width, size, symbol, self.color)
-        else:
-            GP_set_style_thematic(id, layer, color, width, size, symbol, None)
-
-    def SetLinesStyleThematic(self, id, layer, color = None, colorTable = False, width = None):
-        """!Set thematic style for vector lines
-        
-        @param id vector set id
-        @param layer layer number for thematic mapping
-        @param color color column name 
-        @param colorTable use color table 
-        @param width width column name 
-        """
-        file = c_char_p()
-        ret = GV_get_vectname(id, byref(file))
-        if ret < 0:
-            return -1
-        
-        ret = self.ReadVectorColors(file, "")
-        if ret < 0:
-            return -1
-        
-        if colorTable:
-            GV_set_style_thematic(id, layer, color, width, self.color)
-        else:
-            GV_set_style_thematic(id, layer, color, width, None)
-        
-    def UnsetLinesStyleThematic(self, id):
-        """!Unset thematic style for vector points"""
-        GV_unset_style_thematic(id)      
-         
-    def UnsetPointsStyleThematic(self, id):
-        """!Unset thematic style for vector lines"""
-        GP_unset_style_thematic(id)
-        
-    def UnsetVectorPointSurface(self, id, surf_id):
-        """!Unset reference surface of vector set (points)
-        
-        @param id vector set id
-        @param surf_id surface id
-        
-        @return 1 on success
-        @return -1 vector set not found
-        @return -2 surface not found
-        @return -3 on failure
-        """
-        if not GP_site_exists(id):
-            return -1
-        
-        if not GS_surf_exists(surf_id):
-            return -2
-        
-        if GP_unselect_surf(id, surf_id) < 0:
-            return -3
-        
-        return 1
-        
-    def AddIsosurface(self, id, level, isosurf_id = None):
-        """!Add new isosurface
-        
-        @param id volume id
-        @param level isosurface level (topography)
-        
-        @return -1 on failure
-        @return 1 on success
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id is not None:
-            num = GVL_isosurf_num_isosurfs(id)
-            if num < 0 or isosurf_id != num:
-                return -1
-                
-        if GVL_isosurf_add(id) < 0:
-            return -1
-        
-        # set topography level
-        nisosurfs = GVL_isosurf_num_isosurfs(id)
-        
-        return GVL_isosurf_set_att_const(id, nisosurfs - 1, ATT_TOPO, level)
-    
-    def AddSlice(self, id, slice_id = None):
-        """!Add new slice
-        
-        @param id volume id
-        
-        @return -1 on failure
-        @return number of slices
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if slice_id is not None:
-            num = GVL_slice_num_slices(id)
-            if num < 0 or slice_id != num:
-                return -1
-                
-        if GVL_slice_add(id) < 0:
-            return -1
-        
-        return GVL_slice_num_slices(id)
-    
-    def DeleteIsosurface(self, id, isosurf_id):
-        """!Delete isosurface
-        
-        @param id volume id
-        @param isosurf_id isosurface id
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id > GVL_isosurf_num_isosurfs(id):
-            return -2
-        
-        ret = GVL_isosurf_del(id, isosurf_id)
-        
-        if ret < 0:
-            return -3
-
-        return 1
-    
-    def DeleteSlice(self, id, slice_id):
-        """!Delete slice
-        
-        @param id volume id
-        @param slice_id slice id
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 slice not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if slice_id > GVL_slice_num_slices(id):
-            return -2
-        
-        ret = GVL_slice_del(id, slice_id)
-        
-        if ret < 0:
-            return -3
-
-        return 1
-    
-    def MoveIsosurface(self, id, isosurf_id, up):
-        """!Move isosurface up/down in the list
-        
-        @param id volume id
-        @param isosurf_id isosurface id
-        @param up if true move up otherwise down
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id > GVL_isosurf_num_isosurfs(id):
-            return -2
-        
-        if up:
-            ret = GVL_isosurf_move_up(id, isosurf_id)
-        else:
-            ret = GVL_isosurf_move_down(id, isosurf_id)
-        
-        if ret < 0:
-            return -3
-
-        return 1
-
-    def MoveSlice(self, id, slice_id, up):
-        """!Move slice up/down in the list
-        
-        @param id volume id
-        @param slice_id slice id
-        @param up if true move up otherwise down
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 slice not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if slice_id > GVL_slice_num_slices(id):
-            return -2
-        
-        if up:
-            ret = GVL_slice_move_up(id, slice_id)
-        else:
-            ret = GVL_slice_move_down(id, slice_id)
-        
-        if ret < 0:
-            return -3
-
-        return 1
-    
-    def SetIsosurfaceTopo(self, id, isosurf_id, map, value):
-        """!Set isosurface level
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_TOPO, map, value)
-    
-    def SetIsosurfaceColor(self, id, isosurf_id, map, value):
-        """!Set isosurface color
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_COLOR, map, value)
-    
-    def SetIsosurfaceMask(self, id, isosurf_id, invert, value):
-        """!Set isosurface mask
-        
-        @todo invert
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param invert true for invert mask
-        @param value map name to be used for mask
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_MASK, True, value)
-    
-    def SetIsosurfaceTransp(self, id, isosurf_id, map, value):
-        """!Set isosurface transparency
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_TRANSP, map, value)
-    
-    def SetIsosurfaceShine(self, id, isosurf_id, map, value):
-        """!Set isosurface shininess
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_SHINE, map, value)
-    
-    def SetIsosurfaceEmit(self, id, isosurf_id, map, value):
-        """!Set isosurface emission (currently unused)
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_EMIT, map, value)
-    
-    def SetIsosurfaceAttr(self, id, isosurf_id, attr, map, value):
-        """!Set isosurface attribute
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param attr attribute desc
-        @param map if true use map otherwise constant
-        @param value map name of value
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 setting attributes failed
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
-            return -2
-        
-        if map:
-            ret = GVL_isosurf_set_att_map(id, isosurf_id, attr, value)
-        else:
-            if attr == ATT_COLOR:
-                val = Nviz_color_from_str(value)
-            else:
-                val = float(value)
-            
-            ret = GVL_isosurf_set_att_const(id, isosurf_id, attr, val)
-        
-        Debug.msg(3, "Nviz::SetIsosurfaceAttr(): id=%d, isosurf=%d, "
-                  "attr=%d, map=%s, value=%s",
-                  id, isosurf_id, attr, map, value)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def UnsetIsosurfaceMask(self, id, isosurf_id):
-        """!Unset isosurface mask
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 setting attributes failed
-        """
-        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_MASK)
-    
-    def UnsetIsosurfaceTransp(self, id, isosurf_id):
-        """!Unset isosurface transparency
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 setting attributes failed
-        """
-        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_TRANSP)
-    
-    def UnsetIsosurfaceEmit(self, id, isosurf_id):
-        """!Unset isosurface emission (currently unused)
-        
-        @param id volume id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -3 setting attributes failed
-        """
-        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_EMIT)
-    
-    def UnsetIsosurfaceAttr(self, id, isosurf_id, attr):
-        """!Unset surface attribute
-        
-        @param id surface id
-        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
-        @param attr attribute descriptor
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 isosurface not found
-        @return -2 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
-            return -2
-        
-        Debug.msg(3, "Nviz::UnsetSurfaceAttr(): id=%d, isosurf_id=%d, attr=%d",
-                  id, isosurf_id, attr)
-        
-        ret = GVL_isosurf_unset_att(id, isosurf_id, attr)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-
-    def SetIsosurfaceMode(self, id, mode):
-        """!Set draw mode for isosurfaces
-        
-        @param mode
-        
-        @return 1 on success
-        @return -1 volume set not found
-        @return -2 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        ret = GVL_isosurf_set_drawmode(id, mode)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetSliceMode(self, id, mode):
-        """!Set draw mode for slices
-        
-        @param mode
-        
-        @return 1 on success
-        @return -1 volume set not found
-        @return -2 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        ret = GVL_slice_set_drawmode(id, mode)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetIsosurfaceRes(self, id, res):
-        """!Set draw resolution for isosurfaces
-        
-        @param res resolution value
-        
-        @return 1 on success
-        @return -1 volume set not found
-        @return -2 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        ret = GVL_isosurf_set_drawres(id, res, res, res)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetSliceRes(self, id, res):
-        """!Set draw resolution for slices
-        
-        @param res resolution value
-        
-        @return 1 on success
-        @return -1 volume set not found
-        @return -2 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        ret = GVL_slice_set_drawres(id, res, res, res)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetSlicePosition(self, id, slice_id, x1, x2, y1, y2, z1, z2, dir):
-        """!Set slice position
-        
-        @param id volume id
-        @param slice_id slice id
-        @param x1,x2,y1,y2,z1,z2 slice coordinates
-        @param dir axis
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 slice not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if slice_id > GVL_slice_num_slices(id):
-            return -2
-        
-        ret = GVL_slice_set_pos(id, slice_id, x1, x2, y1, y2, z1, z2, dir)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetSliceTransp(self, id, slice_id, value):
-        """!Set slice transparency
-        
-        @param id volume id
-        @param slice_id slice id
-        @param x1,x2,y1,y2,z1,z2 slice coordinates
-        @param value transparency value (0 - 255)
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 slice not found
-        @return -3 on failure
-        """
-        
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if slice_id > GVL_slice_num_slices(id):
-            return -2
-        
-        ret = GVL_slice_set_transp(id, slice_id, value)
-        
-        if ret < 0:
-            return -2
-        
-        return 1
-    
-    def SetIsosurfaceInOut(self, id, isosurf_id, inout):
-        """!Set inout mode
-        
-        @param inout mode true/false
-        
-        @return 1 on success
-        @return -1 volume set not found
-        @return -2 isosurface not found
-        @return -3 on failure
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
-            return -2
-        
-        ret = GVL_isosurf_set_flags(id, isosurf_id, inout)
-        
-        if ret < 0:
-            return -3
-        
-        return 1
-    
-    def GetVolumePosition(self, id):
-        """!Get volume position
-        
-        @param id volume id
-        
-        @return x,y,z
-        @return zero-length vector on error
-        """
-        if not GVL_vol_exists(id):
-            return []
-        
-        x, y, z = c_float(), c_float(), c_float()
-        GVL_get_trans(id, byref(x), byref(y), byref(z))
-        
-        Debug.msg(3, "Nviz::GetVolumePosition(): id=%d, x=%f, y=%f, z=%f",
-                  id, x.value, y.value, z.value)
-        
-        return [x.value, y.value, z.value]
-    
-    def SetVolumePosition(self, id, x, y, z):
-        """!Set volume position
-        
-        @param id volume id
-        @param x,y,z translation values
-        
-        @return 1 on success
-        @return -1 volume not found
-        @return -2 setting position failed
-        """
-        if not GVL_vol_exists(id):
-            return -1
-        
-        Debug.msg(3, "Nviz::SetVolumePosition(): id=%d, x=%f, y=%f, z=%f",
-                  id, x, y, z)
-        
-        GVL_set_trans(id, x, y, z)
-        
-        return 1
-    
-    def GetCPlaneCurrent(self):
-        return Nviz_get_current_cplane(self.data)
-    
-    def GetCPlanesCount(self):
-        """!Returns number of cutting planes"""
-        return Nviz_num_cplanes(self.data) 
-    
-    def GetCPlaneRotation(self):
-        """!Returns rotation parameters of current cutting plane"""
-        x, y, z = c_float(), c_float(), c_float()
-        
-        current = Nviz_get_current_cplane(self.data)
-        Nviz_get_cplane_rotation(self.data, current, byref(x), byref(y), byref(z))
-        
-        return x.value, y.value, z.value
-    
-    def GetCPlaneTranslation(self):
-        """!Returns translation parameters of current cutting plane"""
-        x, y, z = c_float(), c_float(), c_float()
-        
-        current = Nviz_get_current_cplane(self.data)
-        Nviz_get_cplane_translation(self.data, current, byref(x), byref(y), byref(z))
-        
-        return x.value, y.value, z.value
-    
-    def SetCPlaneRotation(self, x, y, z):
-        """!Set current clip plane rotation
-        
-        @param x,y,z rotation parameters
-        """
-        current = Nviz_get_current_cplane(self.data)
-        Nviz_set_cplane_rotation(self.data, current, x, y, z)
-        Nviz_draw_cplane(self.data, -1, -1)
-    
-    def SetCPlaneTranslation(self, x, y, z):
-        """!Set current clip plane translation
-        
-        @param x,y,z translation parameters
-        """
-        current = Nviz_get_current_cplane(self.data)
-        Nviz_set_cplane_translation(self.data, current, x, y, z)
-        Nviz_draw_cplane(self.data, -1, -1) 
-        Debug.msg(3, "Nviz::SetCPlaneTranslation(): id=%d, x=%f, y=%f, z=%f",
-                  current, x, y, z)
-                
-    def SetCPlaneInteractively(self, x, y):
-        current = Nviz_get_current_cplane(self.data)
-        ret = Nviz_set_cplane_here(self.data, current, x, y)
-        if ret:
-            Nviz_draw_cplane(self.data, -1, -1)
-            x, y, z = self.GetCPlaneTranslation()
-            return x, y, z
-        else:
-            return None, None, None
-        
-        
-    def SelectCPlane(self, index):
-        """!Select cutting plane
-        
-        @param index index of cutting plane
-        """
-        Nviz_on_cplane(self.data, index)
-    
-    def UnselectCPlane(self, index):
-        """!Unselect cutting plane
-        
-        @param index index of cutting plane
-        """
-        Nviz_off_cplane(self.data, index)
-        
-    def SetFenceColor(self, index):
-        """!Select current cutting plane
-        
-        @param index type of fence - from 0 (off) to 4
-        """    
-        Nviz_set_fence_color(self.data, index)
-            
-    def GetXYRange(self):
-        """!Get xy range"""
-        return Nviz_get_xyrange(self.data)
-    
-    def GetZRange(self):
-        """!Get z range"""
-        min, max = c_float(), c_float()
-        Nviz_get_zrange(self.data, byref(min), byref(max))
-        return min.value, max.value
-    
-    def SaveToFile(self, filename, width = 20, height = 20, itype = 'ppm'):
-        """!Save current GL screen to ppm/tif file
-
-        @param filename file name
-        @param width image width
-        @param height image height
-        @param itype image type ('ppm' or 'tif')
-        """
-        widthOrig  = self.width
-        heightOrig = self.height
-        
-        self.ResizeWindow(width, height)
-        GS_clear(Nviz_get_bgcolor(self.data))
-        self.Draw(False, -1)
-        if itype == 'ppm':
-            GS_write_ppm(filename)
-        else:
-            GS_write_tif(filename)
-        
-        self.ResizeWindow(widthOrig, heightOrig)
-
-    def DrawLightingModel(self):
-        """!Draw lighting model"""
-        if self.showLight:
-            Nviz_draw_model(self.data)
-
-    def DrawFringe(self):
-        """!Draw fringe"""
-        Nviz_draw_fringe(self.data)
-        
-    def SetFringe(self, sid, color, elev, nw = False, ne = False, sw = False, se = False):
-        """!Set fringe
-
-        @param sid surface id
-        @param color color
-        @param elev elevation (height)
-        @param nw,ne,sw,se fringe edges (turn on/off)
-        """
-        scolor = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
-        Nviz_set_fringe(self.data,
-                        sid, Nviz_color_from_str(scolor),
-                        elev, int(nw), int(ne), int(sw), int(se))
-    
-    def DrawArrow(self):
-        """!Draw north arrow
-        """
-        return Nviz_draw_arrow(self.data)
-        
-    def SetArrow(self, sx, sy, size, color):
-        """!Set north arrow from canvas coordinates
-        
-        @param sx,sy canvas coordinates
-        @param size arrow length
-        @param color arrow color
-        """
-        return Nviz_set_arrow(self.data, sx, sy, size, Nviz_color_from_str(color))       
-        
-    def DeleteArrow(self):
-        """!Delete north arrow
-        """
-        Nviz_delete_arrow(self.data)
-    
-    def SetScalebar(self, id, sx, sy, size, color):
-        """!Set scale bar from canvas coordinates
-        
-        @param sx,sy canvas coordinates
-        @param id scale bar id
-        @param size scale bar length
-        @param color scale bar color
-        """
-        return Nviz_set_scalebar(self.data, id, sx, sy, size, Nviz_color_from_str(color))
-    
-    def DrawScalebar(self):
-        """!Draw scale bar
-        """
-        return Nviz_draw_scalebar(self.data)
-    
-    def DeleteScalebar(self, id):
-        """!Delete scalebar
-        """
-        Nviz_delete_scalebar(self.data, id)
-        
-    def GetPointOnSurface(self, sx, sy):
-        """!Get point on surface
-
-        @param sx,sy canvas coordinates (LL)
-        """
-        sid = c_int()
-        x   = c_float()
-        y   = c_float()
-        z   = c_float()
-        Debug.msg(5, "Nviz::GetPointOnSurface(): sx=%d sy=%d" % (sx, sy))
-        num = GS_get_selected_point_on_surface(sx, sy, byref(sid), byref(x), byref(y), byref(z))
-        if num == 0:
-            return (None, None, None, None)
-        
-        return (sid.value, x.value, y.value, z.value)
-
-    def QueryMap(self, sx, sy):
-        """!Query surface map
-
-        @param sx,sy canvas coordinates (LL)
-        """
-        sid, x, y, z = self.GetPointOnSurface(sx, sy)
-        if not sid:
-            return None
-        
-        catstr = create_string_buffer(256)
-        valstr = create_string_buffer(256)
-        GS_get_cat_at_xy(sid, ATT_TOPO, catstr, x, y)
-        GS_get_val_at_xy(sid, ATT_COLOR, valstr, x, y)
-        
-        return { 'id' : sid,
-                 'x'  : x,
-                 'y'  : y,
-                 'z'  : z,
-                 'elevation' : catstr.value.replace('(', '').replace(')', ''),
-                 'color'     : valstr.value }
-    
-    def GetDistanceAlongSurface(self, sid, p1, p2, useExag = True):
-        """!Get distance measured along surface"""
-        d = c_float()
-        
-        GS_get_distance_alongsurf(sid, p1[0], p1[1], p2[0], p2[1],
-                                  byref(d), int(useExag))
-        
-        return d.value
-
-    def GetRotationParameters(self, dx, dy):
-        """!Get rotation parameters (angle, x, y, z axes)
-        
-        @param dx,dy difference from previous mouse drag event
-        """
-        modelview = (c_double * 16)()
-        Nviz_get_modelview(byref(modelview))
-        
-        angle = sqrt(dx*dx+dy*dy)/float(self.width+1)*180.0
-        m = []
-        row = []
-        for i, item in enumerate(modelview):
-            row.append(item)
-            if (i+1) % 4 == 0:
-                m.append(row)
-                row = []
-        inv = matrix(m).I
-        ax, ay, az = dy, dx, 0.
-        x = inv[0,0]*ax + inv[1,0]*ay + inv[2,0]*az
-        y = inv[0,1]*ax + inv[1,1]*ay + inv[2,1]*az
-        z = inv[0,2]*ax + inv[1,2]*ay + inv[2,2]*az
-        
-        return angle, x, y, z 
-       
-    def Rotate(self, angle, x, y, z):
-        """!Set rotation parameters
-        Rotate scene (difference from current state).
-
-        @param angle angle
-        @param x,y,z axis coordinate
-        """
-        Nviz_set_rotation(angle, x, y, z)
-        
-    def UnsetRotation(self):
-        """!Stop rotating the scene"""
-        Nviz_unset_rotation()
-        
-    def ResetRotation(self):
-        """!Reset scene rotation"""
-        Nviz_init_rotation()
-        
-    def GetRotationMatrix(self):
-        """!Get rotation matrix"""
-        matrix = (c_double * 16)()
-        GS_get_rotation_matrix(byref(matrix))
-        returnMatrix = []
-        for item in matrix:
-            returnMatrix.append(item)
-        return returnMatrix
-        
-    def SetRotationMatrix(self, matrix):
-        """!Set rotation matrix"""
-        mtrx = (c_double * 16)()
-        for i in range(len(matrix)):
-            mtrx[i] = matrix[i]
-        GS_set_rotation_matrix(byref(mtrx))
-    
-    def Start2D(self):
-        Nviz_set_2D(self.width, self.height)
-        
-    def FlyThrough(self, flyInfo, mode, exagInfo):
-        """!Fly through the scene
-        
-        @param flyInfo fly parameters
-        @param mode 0 or 1 for different fly behaviour
-        @param exagInfo parameters changing fly speed
-        """
-        fly = (c_float * 3)()
-        for i, item in enumerate(flyInfo):
-            fly[i] = item
-        exag = (c_int * 2)()
-        exag[0] = int(exagInfo['move'])
-        exag[1] = int(exagInfo['turn'])
-        Nviz_flythrough(self.data, fly, exag, mode)
-        
-class Texture(object):
-    """!Class representing OpenGL texture"""
-    def __init__(self, filepath, overlayId, coords):
-        """!Load image to texture
-
-        @param filepath path to image file
-        @param overlayId id of overlay (1 for legend, 101 and more for text)
-        @param coords image coordinates
-        """
-        self.path = filepath
-        self.image = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
-        self.width = self.image.GetWidth()
-        self.height = self.image.GetHeight()
-        self.id = overlayId
-        self.coords = list(coords)
-        self.bounds = wx.Rect()
-        self.active = True
-        
-        # alpha needs to be initialized
-        if not self.image.HasAlpha():
-            self.image.InitAlpha()
-    
-        # resize image to match 2^n
-        self.Resize()
-        
-        # check max texture size
-        maxSize = c_int()
-        Nviz_get_max_texture(byref(maxSize))
-        self.maxSize = maxSize.value
-        if self.maxSize < self.width or self.maxSize < self.height:
-            # TODO: split up image 
-            self.textureId = None
-        else:
-            self.textureId = self.Load()
-            
-    def __del__(self):
-        """!Delete texture"""
-        if self.textureId:
-            Nviz_del_texture(self.textureId)
-        grass.try_remove(self.path)
-            
-    def Resize(self):    
-        """!Resize image to match 2^n"""
-        n = m = 1
-        while self.width > pow(2,n):
-            n += 1
-        while self.height > pow(2,m):
-            m += 1
-        self.image.Resize(size = (pow(2,n), pow(2,m)), pos = (0, 0))
-        self.width = self.image.GetWidth()
-        self.height = self.image.GetHeight()
-        
-    def Load(self):
-        """!Load image to texture"""  
-        if self.image.HasAlpha():
-            bytesPerPixel = 4
-        else:
-            bytesPerPixel = 3
-        bytes = bytesPerPixel * self.width * self.height
-        rev_val = self.height - 1
-        im = (c_ubyte * bytes)()
-        bytes3 = 3 * self.width * self.height
-        bytes1 = self.width * self.height
-        imageData = struct.unpack(str(bytes3) + 'B', self.image.GetData())
-        if self.image.HasAlpha():
-            alphaData = struct.unpack(str(bytes1) + 'B', self.image.GetAlphaData())
-        
-        # this takes too much time
-        wx.BeginBusyCursor()
-        for i in range(self.height):
-            for j in range(self.width):
-                im[(j + i * self.width) * bytesPerPixel + 0] = imageData[( j + (rev_val - i) * self.width) * 3 + 0]
-                im[(j + i * self.width) * bytesPerPixel + 1] = imageData[( j + (rev_val - i) * self.width) * 3 + 1]
-                im[(j + i * self.width) * bytesPerPixel + 2] = imageData[( j + (rev_val - i) * self.width) * 3 + 2]
-                if self.image.HasAlpha():
-                    im[(j + i * self.width) * bytesPerPixel + 3] = alphaData[( j + (rev_val - i) * self.width)]
-        wx.EndBusyCursor()
-        
-        id = Nviz_load_image(im, self.width, self.height, self.image.HasAlpha())
-        
-        return id
-        
-    def Draw(self):
-        """!Draw texture as an image"""
-        Nviz_draw_image(self.coords[0], self.coords[1], self.width, self.height, self.textureId)
-    
-        
-    def SetBounds(self, rect):
-        """!Set Bounding Rectangle"""
-        self.bounds = rect
-        
-    def HitTest(self, x, y, radius):
-        copy = wx.Rect(*self.bounds)
-        copy.Inflate(radius, radius)
-        return copy.ContainsXY(x, y)
-    
-    def MoveTexture(self, dx, dy):
-        """!Move texture on the screen"""
-        self.coords[0] += dx
-        self.coords[1] += dy
-        self.bounds.OffsetXY(dx, dy)
-    
-    def SetCoords(self, coords):
-        """!Set coordinates"""
-        dx = coords[0] - self.coords[0]
-        dy = coords[1] - self.coords[1]
-        self.MoveTexture(dx, dy)
-        
-    def GetId(self):
-        """!Returns image id."""
-        return self.id
-    
-    def SetActive(self, active = True):
-        self.active = active
-        
-    def IsActive(self):
-        return self.active
-        
-class ImageTexture(Texture):
-    """!Class representing OpenGL texture as an overlay image"""
-    def __init__(self, filepath, overlayId, coords, cmd):
-        """!Load image to texture
-
-        @param filepath path to image file
-        @param overlayId id of overlay (1 for legend)
-        @param coords image coordinates
-        @param cmd d.legend command      
-        """
-        Texture.__init__(self, filepath = filepath, overlayId = overlayId, coords = coords)
-        
-        self.cmd = cmd
-        
-    def GetCmd(self):
-        """!Returns overlay command."""
-        return self.cmd
-        
-    def Corresponds(self, item):
-        return sorted(self.GetCmd()) == sorted(item.GetCmd())
-        
-class TextTexture(Texture):
-    """!Class representing OpenGL texture as a text label"""
-    def __init__(self, filepath, overlayId, coords, textDict):
-        """!Load image to texture
-
-        @param filepath path to image file
-        @param overlayId id of overlay (101 and more for text)
-        @param coords text coordinates
-        @param textDict text properties      
-        """
-        Texture.__init__(self, filepath = filepath, overlayId = overlayId, coords = coords)
-        
-        self.textDict = textDict
-        
-    def GetTextDict(self):
-        """!Returns text properties."""
-        return self.textDict
-        
-        
-    def Corresponds(self, item):
-        t = self.GetTextDict()
-        for prop in t.keys():
-            if prop in ('coords','bbox'): continue
-            if t[prop] != item[prop]:
-                return False
-                
-        return True
-    

Deleted: grass/trunk/gui/wxpython/gui_modules/wxplot.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxplot.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/wxplot.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1317 +0,0 @@
-"""!
- at package wxplot.py
-
-Iinteractive plotting using PyPlot (wx.lib.plot.py). 
-
-Classes:
- - AbstractPlotFrame
- - HistFrame
- - ProfileFrame
-
-(C) 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton, Arizona State University
-"""
-
-import os
-import sys
-import math
-
-import wx
-import wx.lib.colourselect as  csel
-
-import globalvar
-import gcmd
-from render      import Map
-from toolbars    import Histogram2Toolbar
-from toolbars    import ProfileToolbar
-from toolbars    import ScatterplotToolbar
-from preferences import globalSettings as UserSettings
-
-import wxplot_dialogs as dialogs
-
-from grass.script import core   as grass
-from grass.script import raster as raster
-
-try:
-    import numpy
-    import wx.lib.plot as plot
-except ImportError:
-    msg = _("This module requires the NumPy module, which could not be "
-            "imported. It probably is not installed (it's not part of the "
-            "standard Python distribution). See the Numeric Python site "
-            "(http://numpy.scipy.org) for information on downloading source or "
-            "binaries.")
-    print >> sys.stderr, "wxplot.py: " + msg
-
-class AbstractPlotFrame(wx.Frame):
-    """!Abstract PyPlot display frame class"""
-    def __init__(self, parent = None, id = wx.ID_ANY, size = (700, 300),
-                 style = wx.DEFAULT_FRAME_STYLE, rasterList = [],  **kwargs):
-
-        wx.Frame.__init__(self, parent, id, size = size, style = style, **kwargs)
-        
-        self.parent = parent            # MapFrame
-        self.mapwin = self.parent.MapWindow
-        self.Map    = Map()             # instance of render.Map to be associated with display
-        self.rasterList = rasterList    #list of rasters to plot
-        self.raster = {}    # dictionary of raster maps and their plotting parameters
-        self.plottype = ''
-        
-        self.linestyledict = { 'solid' : wx.SOLID,
-                            'dot' : wx.DOT,
-                            'long-dash' : wx.LONG_DASH,
-                            'short-dash' : wx.SHORT_DASH,
-                            'dot-dash' : wx.DOT_DASH }
-
-        self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
-                            'solid' : wx.SOLID }
-
-        #
-        # Icon
-        #
-        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-                
-        #
-        # Add statusbar
-        #
-        self.statusbar = self.CreateStatusBar(number = 2, style = 0)
-        self.statusbar.SetStatusWidths([-2, -1])
-
-        #
-        # Define canvas and settings
-        #
-        # 
-        self.client = plot.PlotCanvas(self)
-
-        #define the function for drawing pointLabels
-        self.client.SetPointLabelFunc(self.DrawPointLabel)
-
-        # Create mouse event for showing cursor coords in status bar
-        self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
-
-        # Show closest point when enabled
-        self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
-
-        self.plotlist = []      # list of things to plot
-        self.plot = None        # plot draw object
-        self.ptitle = ""        # title of window
-        self.xlabel = ""        # default X-axis label
-        self.ylabel = ""        # default Y-axis label
-
-        #
-        # Bind various events
-        #
-        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-        
-        self.CentreOnScreen()
-        
-        self._createColorDict()
-
-
-    def _createColorDict(self):
-        """!Create color dictionary to return wx.Color tuples
-        for assigning colors to images in imagery groups"""
-                
-        self.colorDict = {}
-        for clr in grass.named_colors.iterkeys():
-            if clr == 'white' or clr == 'black': continue
-            r = grass.named_colors[clr][0] * 255
-            g = grass.named_colors[clr][1] * 255
-            b = grass.named_colors[clr][2] * 255
-            self.colorDict[clr] = (r,g,b,255)
-
-    def InitPlotOpts(self, plottype):
-        """!Initialize options for entire plot
-        """
-        
-        self.plottype = plottype                # histogram, profile, or scatter
-
-        self.properties = {}                    # plot properties
-        self.properties['font'] = {}
-        self.properties['font']['prop'] = UserSettings.Get(group = self.plottype, key = 'font')
-        self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
-                                                    wx.FONTSTYLE_NORMAL,
-                                                    wx.FONTWEIGHT_NORMAL)
-        
-        if self.plottype == 'profile':
-            self.properties['marker'] = UserSettings.Get(group = self.plottype, key = 'marker')
-            # changing color string to tuple for markers/points
-            colstr = str(self.properties['marker']['color'])
-            self.properties['marker']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
-
-        self.properties['grid'] = UserSettings.Get(group = self.plottype, key = 'grid')        
-        colstr = str(self.properties['grid']['color']) # changing color string to tuple        
-        self.properties['grid']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
-                
-        self.properties['x-axis'] = {}
-        self.properties['x-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'x-axis')
-        self.properties['x-axis']['axis'] = None
-
-        self.properties['y-axis'] = {}
-        self.properties['y-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'y-axis')
-        self.properties['y-axis']['axis'] = None
-        
-        self.properties['legend'] = UserSettings.Get(group = self.plottype, key = 'legend')
-
-        self.zoom = False  # zooming disabled
-        self.drag = False  # draging disabled
-        self.client.SetShowScrollbars(True) # vertical and horizontal scrollbars
-
-        # x and y axis set to normal (non-log)
-        self.client.setLogScale((False, False))
-        if self.properties['x-axis']['prop']['type']:
-            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
-        else:
-            self.client.SetXSpec('auto')
-        
-        if self.properties['y-axis']['prop']['type']:
-            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
-        else:
-            self.client.SetYSpec('auto')
-        
-    def InitRasterOpts(self, rasterList, plottype):
-        """!Initialize or update raster dictionary for plotting
-        """
-
-        rdict = {} # initialize a dictionary
-
-        for r in rasterList:
-            idx = rasterList.index(r)
-            
-            try:
-                ret = raster.raster_info(r)
-            except:
-                continue
-                # if r.info cannot parse map, skip it
-                
-            self.raster[r] = UserSettings.Get(group = plottype, key = 'raster') # some default settings
-            rdict[r] = {} # initialize sub-dictionaries for each raster in the list
-
-            if ret['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
-                rdict[r]['units'] = ''
-            else:
-                self.raster[r]['units'] = ret['units']
-
-            rdict[r]['plegend'] = r.split('@')[0]
-            rdict[r]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
-            rdict[r]['pline'] = None
-            rdict[r]['datatype'] = ret['datatype']
-            rdict[r]['pwidth'] = 1
-            rdict[r]['pstyle'] = 'solid'
-            
-            if idx <= len(self.colorList):
-                rdict[r]['pcolor'] = self.colorDict[self.colorList[idx]]
-            else:
-                r = randint(0, 255)
-                b = randint(0, 255)
-                g = randint(0, 255)
-                rdict[r]['pcolor'] = ((r,g,b,255))
- 
-            
-        return rdict
-            
-    def InitRasterPairs(self, rasterList, plottype):
-        """!Initialize or update raster dictionary with raster pairs for
-            bivariate scatterplots
-        """
-        
-        if len(rasterList) == 0: return
-
-        rdict = {} # initialize a dictionary
-        for rpair in rasterList:
-            idx = rasterList.index(rpair)
-            
-            try:
-                ret0 = raster.raster_info(rpair[0])
-                ret1 = raster.raster_info(rpair[1])
-
-            except:
-                continue
-                # if r.info cannot parse map, skip it
-
-            self.raster[rpair] = UserSettings.Get(group = plottype, key = 'rasters') # some default settings
-            rdict[rpair] = {} # initialize sub-dictionaries for each raster in the list
-            rdict[rpair][0] = {}
-            rdict[rpair][1] = {}
-
-            if ret0['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
-                rdict[rpair][0]['units'] = ''
-            else:
-                self.raster[rpair][0]['units'] = ret0['units']
-
-            if ret1['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
-                rdict[rpair][1]['units'] = ''
-            else:
-                self.raster[rpair][1]['units'] = ret1['units']
-
-            rdict[rpair]['plegend'] = rpair[0].split('@')[0] + ' vs ' + rpair[1].split('@')[0]
-            rdict[rpair]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
-            rdict[rpair]['ptype'] = 'dot'
-            rdict[rpair][0]['datatype'] = ret0['datatype']
-            rdict[rpair][1]['datatype'] = ret1['datatype']
-            rdict[rpair]['psize'] = 1
-            rdict[rpair]['pfill'] = 'solid'
-            
-            if idx <= len(self.colorList):
-                rdict[rpair]['pcolor'] = self.colorDict[self.colorList[idx]]
-            else:
-                r = randint(0, 255)
-                b = randint(0, 255)
-                g = randint(0, 255)
-                rdict[rpair]['pcolor'] = ((r,g,b,255))
-            
-        return rdict
-
-    def SetGraphStyle(self):
-        """!Set plot and text options
-        """
-        self.client.SetFont(self.properties['font']['wxfont'])
-        self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
-        self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
-
-        self.client.SetEnableZoom(self.zoom)
-        self.client.SetEnableDrag(self.drag)
-        
-        #
-        # axis settings
-        #
-        if self.properties['x-axis']['prop']['type'] == 'custom':
-            self.client.SetXSpec('min')
-        else:
-            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
-
-        if self.properties['y-axis']['prop']['type'] == 'custom':
-            self.client.SetYSpec('min')
-        else:
-            self.client.SetYSpec(self.properties['y-axis']['prop'])
-
-        if self.properties['x-axis']['prop']['type'] == 'custom' and \
-               self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
-            self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
-                                                 self.properties['x-axis']['prop']['max'])
-        else:
-            self.properties['x-axis']['axis'] = None
-
-        if self.properties['y-axis']['prop']['type'] == 'custom' and \
-                self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
-            self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
-                                                 self.properties['y-axis']['prop']['max'])
-        else:
-            self.properties['y-axis']['axis'] = None
-
-        self.client.SetEnableGrid(self.properties['grid']['enabled'])
-        
-        self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
-                                           self.properties['grid']['color'][1],
-                                           self.properties['grid']['color'][2],
-                                           255))
-
-        self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
-        self.client.SetEnableLegend(self.properties['legend']['enabled'])
-
-        if self.properties['x-axis']['prop']['log'] == True:
-            self.properties['x-axis']['axis'] = None
-            self.client.SetXSpec('min')
-        if self.properties['y-axis']['prop']['log'] == True:
-            self.properties['y-axis']['axis'] = None
-            self.client.SetYSpec('min')
-            
-        self.client.setLogScale((self.properties['x-axis']['prop']['log'],
-                                 self.properties['y-axis']['prop']['log']))
-
-    def DrawPlot(self, plotlist):
-        """!Draw line and point plot from list plot elements.
-        """
-        self.plot = plot.PlotGraphics(plotlist,
-                                         self.ptitle,
-                                         self.xlabel,
-                                         self.ylabel)
-
-        if self.properties['x-axis']['prop']['type'] == 'custom':
-            self.client.SetXSpec('min')
-        else:
-            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
-
-        if self.properties['y-axis']['prop']['type'] == 'custom':
-            self.client.SetYSpec('min')
-        else:
-            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
-
-        self.client.Draw(self.plot, self.properties['x-axis']['axis'],
-                         self.properties['y-axis']['axis'])
-                
-    def DrawPointLabel(self, dc, mDataDict):
-        """!This is the fuction that defines how the pointLabels are
-            plotted dc - DC that will be passed mDataDict - Dictionary
-            of data that you want to use for the pointLabel
-
-            As an example I have decided I want a box at the curve
-            point with some text information about the curve plotted
-            below.  Any wxDC method can be used.
-        """
-        dc.SetPen(wx.Pen(wx.BLACK))
-        dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
-
-        sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
-        dc.DrawRectangle( sx-5,sy-5, 10, 10)  #10by10 square centered on point
-        px,py = mDataDict["pointXY"]
-        cNum = mDataDict["curveNum"]
-        pntIn = mDataDict["pIndex"]
-        legend = mDataDict["legend"]
-        #make a string to display
-        s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
-        dc.DrawText(s, sx , sy+1)
-
-    def OnZoom(self, event):
-        """!Enable zooming and disable dragging
-        """
-        self.zoom = True
-        self.drag = False
-        self.client.SetEnableZoom(self.zoom)
-        self.client.SetEnableDrag(self.drag)
-
-    def OnDrag(self, event):
-        """!Enable dragging and disable zooming
-        """
-        self.zoom = False
-        self.drag = True
-        self.client.SetEnableDrag(self.drag)
-        self.client.SetEnableZoom(self.zoom)
-
-    def OnRedraw(self, event):
-        """!Redraw the plot window. Unzoom to original size
-        """
-        self.client.Reset()
-        self.client.Redraw()
-       
-    def OnErase(self, event):
-        """!Erase the plot window
-        """
-        self.client.Clear()
-        self.mapwin.ClearLines(self.mapwin.pdc)
-        self.mapwin.ClearLines(self.mapwin.pdcTmp)
-        self.mapwin.polycoords = []
-        self.mapwin.Refresh()
-
-    def SaveToFile(self, event):
-        """!Save plot to graphics file
-        """
-        self.client.SaveFile()
-
-    def OnMouseLeftDown(self,event):
-        self.SetStatusText(_("Left Mouse Down at Point: (%.4f, %.4f)") % \
-                               self.client._getXY(event))
-        event.Skip() # allows plotCanvas OnMouseLeftDown to be called
-
-    def OnMotion(self, event):
-        """!Indicate when mouse is outside the plot area
-        """
-        if self.client.OnLeave(event): print 'out of area'
-        #show closest point (when enbled)
-        if self.client.GetEnablePointLabel() == True:
-            #make up dict with info for the pointLabel
-            #I've decided to mark the closest point on the closest curve
-            dlst =  self.client.GetClosetPoint( self.client._getXY(event), pointScaled =  True)
-            if dlst != []:      #returns [] if none
-                curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
-                #make up dictionary to pass to my user function (see DrawPointLabel)
-                mDataDict =  {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
-                    "pointXY":pointXY, "scaledXY":scaledXY}
-                #pass dict to update the pointLabel
-                self.client.UpdatePointLabel(mDataDict)
-        event.Skip()           #go to next handler        
- 
- 
-    def PlotOptionsMenu(self, event):
-        """!Popup menu for plot and text options
-        """
-        point = wx.GetMousePosition()
-        popt = wx.Menu()
-        # Add items to the menu
-        settext = wx.MenuItem(popt, wx.ID_ANY, _('Text settings'))
-        popt.AppendItem(settext)
-        self.Bind(wx.EVT_MENU, self.PlotText, settext)
-
-        setgrid = wx.MenuItem(popt, wx.ID_ANY, _('Plot settings'))
-        popt.AppendItem(setgrid)
-        self.Bind(wx.EVT_MENU, self.PlotOptions, setgrid)
-
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(popt)
-        popt.Destroy()
-
-    def NotFunctional(self):
-        """!Creates a 'not functional' message dialog
-        """
-        dlg = wx.MessageDialog(parent = self,
-                               message = _('This feature is not yet functional'),
-                               caption = _('Under Construction'),
-                               style = wx.OK | wx.ICON_INFORMATION)
-        dlg.ShowModal()
-        dlg.Destroy()
-
-    def OnPlotText(self, dlg):
-        """!Custom text settings for histogram plot.
-        """
-        self.ptitle = dlg.ptitle
-        self.xlabel = dlg.xlabel
-        self.ylabel = dlg.ylabel
-        dlg.UpdateSettings()
-
-        self.client.SetFont(self.properties['font']['wxfont'])
-        self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
-        self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
-
-        if self.plot:
-            self.plot.setTitle(dlg.ptitle)
-            self.plot.setXLabel(dlg.xlabel)
-            self.plot.setYLabel(dlg.ylabel)
-        
-        self.OnRedraw(event = None)
-    
-    def PlotText(self, event):
-        """!Set custom text values for profile title and axis labels.
-        """
-        dlg = dialogs.TextDialog(parent = self, id = wx.ID_ANY, 
-                                 plottype = self.plottype, 
-                                 title = _('Histogram text settings'))
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.OnPlotText(dlg)
-
-        dlg.Destroy()
-
-    def PlotOptions(self, event):
-        """!Set various profile options, including: line width, color,
-        style; marker size, color, fill, and style; grid and legend
-        options.  Calls OptDialog class.
-        """
-        dlg = dialogs.OptDialog(parent = self, id = wx.ID_ANY, 
-                                plottype = self.plottype, 
-                                title = _('Plot settings'))
-        btnval = dlg.ShowModal()
-
-        if btnval == wx.ID_SAVE:
-            dlg.UpdateSettings()            
-            self.SetGraphStyle()            
-            dlg.Destroy()            
-        elif btnval == wx.ID_CANCEL:
-            dlg.Destroy()
-
-    def PrintMenu(self, event):
-        """!Print options and output menu
-        """
-        point = wx.GetMousePosition()
-        printmenu = wx.Menu()
-        for title, handler in ((_("Page setup"), self.OnPageSetup),
-                               (_("Print preview"), self.OnPrintPreview),
-                               (_("Print display"), self.OnDoPrint)):
-            item = wx.MenuItem(printmenu, wx.ID_ANY, title)
-            printmenu.AppendItem(item)
-            self.Bind(wx.EVT_MENU, handler, item)
-        
-        # Popup the menu.  If an item is selected then its handler
-        # will be called before PopupMenu returns.
-        self.PopupMenu(printmenu)
-        printmenu.Destroy()
-
-    def OnPageSetup(self, event):
-        self.client.PageSetup()
-
-    def OnPrintPreview(self, event):
-        self.client.PrintPreview()
-
-    def OnDoPrint(self, event):
-        self.client.Printout()
-
-    def OnQuit(self, event):
-        self.Close(True)
-
-    def OnCloseWindow(self, event):
-        """!Close plot window and clean up
-        """
-        try:
-            self.mapwin.ClearLines()
-            self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
-            self.mapwin.mouse['use'] = 'pointer'
-            self.mapwin.mouse['box'] = 'point'
-            self.mapwin.polycoords = []
-            self.mapwin.UpdateMap(render = False, renderVector = False)
-        except:
-            pass
-        
-        self.mapwin.SetCursor(self.Parent.cursors["default"])
-        self.Destroy()
-        
-class HistFrame(AbstractPlotFrame):
-    def __init__(self, parent, id, pos, style, size, rasterList = []):
-        """!Mainframe for displaying histogram of raster map. Uses wx.lib.plot.
-        """
-        AbstractPlotFrame.__init__(self, parent)
-        
-        self.toolbar = Histogram2Toolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-        self.SetLabel(_("GRASS Histogramming Tool"))
-
-        #
-        # Init variables
-        #
-        self.rasterList = rasterList
-        self.plottype = 'histogram'
-        self.group = '' 
-        self.ptitle = _('Histogram of')         # title of window
-        self.xlabel = _("Raster cell values")   # default X-axis label
-        self.ylabel = _("Cell counts")          # default Y-axis label
-        self.maptype = 'raster'                 # default type of histogram to plot
-        self.histtype = 'count' 
-        self.bins = 255
-        self.colorList = ["blue", "green", "red", "yellow", "magenta", "cyan", \
-                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
-                    "indigo"]
-        
-        if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
-            self.InitRasterOpts(self.rasterList, self.plottype)
-
-        self._initOpts()
-
-    def _initOpts(self):
-        """!Initialize plot options
-        """
-        self.InitPlotOpts('histogram')            
-
-    def OnCreateHist(self, event):
-        """!Main routine for creating a histogram. Uses r.stats to
-        create a list of cell value and count/percent/area pairs. This is passed to
-        plot to create a line graph of the histogram.
-        """
-        self.SetCursor(self.parent.cursors["default"])
-        self.SetGraphStyle()
-        self.SetupHistogram()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
-
-    def OnSelectRaster(self, event):
-        """!Select raster map(s) to profile
-        """
-        dlg = dialogs.HistRasterDialog(parent = self)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.rasterList = dlg.rasterList
-            self.group = dlg.group
-            self.bins = dlg.bins
-            self.histtype = dlg.histtype
-            self.maptype = dlg.maptype
-            self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
-
-            # plot histogram
-            if len(self.rasterList) > 0:
-                self.OnCreateHist(event = None)
-
-        dlg.Destroy()
-
-    def SetupHistogram(self):
-        """!Build data list for ploting each raster
-        """
-
-        #
-        # populate raster dictionary
-        #
-        if len(self.rasterList) == 0: return  # nothing selected
-        
-        for r in self.rasterList:
-            self.raster[r]['datalist'] = self.CreateDatalist(r)
-            
-        #
-        # update title
-        #
-        if self.maptype == 'group':
-            self.ptitle = _('Histogram of %s') % self.group.split('@')[0] 
-        else: 
-            self.ptitle = _('Histogram of %s') % self.rasterList[0].split('@')[0] 
-
-        
-        #
-        # set xlabel based on first raster map in list to be histogrammed
-        #
-        units = self.raster[self.rasterList[0]]['units']
-        if units != '' and units != '(none)' and units != None:
-            self.xlabel = _('Raster cell values %s') % units
-        else:
-            self.xlabel = _('Raster cell values') 
-
-        #
-        # set ylabel from self.histtype
-        #
-        if self.histtype == 'count': self.ylabel = _('Cell counts')
-        if self.histtype == 'percent': self.ylabel = _('Percent of total cells')
-        if self.histtype == 'area': self.ylabel = _('Area')
-
-    def CreateDatalist(self, raster):
-        """!Build a list of cell value, frequency pairs for histogram
-            frequency can be in cell counts, percents, or area
-        """
-        datalist = []
-        
-        if self.histtype == 'count': freqflag = 'cn'
-        if self.histtype == 'percent': freqflag = 'pn'
-        if self.histtype == 'area': freqflag = 'an'
-                
-        try:
-            ret = gcmd.RunCommand("r.stats",
-                                  parent = self,
-                                  input = raster,
-                                  flags = freqflag,
-                                  nsteps = self.bins,
-                                  fs = ',',
-                                  quiet = True,
-                                  read = True)
-            
-            if not ret:
-                return datalist
-            
-            for line in ret.splitlines():
-                cellval, histval = line.strip().split(',')
-                histval = histval.strip()
-                if self.raster[raster]['datatype'] != 'CELL':
-                    cellval = cellval.split('-')[0]
-                if self.histtype == 'percent':
-                    histval = histval.rstrip('%')
-                    
-                datalist.append((cellval,histval))
-
-            return datalist
-        except gcmd.GException, e:
-            gcmd.GError(parent = self,
-                        message = e.value)
-            return None
-        
-    def CreatePlotList(self):
-        """!Make list of elements to plot
-        """
-        
-        # graph the cell value, frequency pairs for the histogram
-        self.plotlist = []
-
-        for r in self.rasterList:
-            if len(self.raster[r]['datalist']) > 0:
-                col = wx.Color(self.raster[r]['pcolor'][0],
-                               self.raster[r]['pcolor'][1],
-                               self.raster[r]['pcolor'][2],
-                               255)
-                self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
-                                                        colour = col,
-                                                        width = self.raster[r]['pwidth'],
-                                                        style = self.linestyledict[self.raster[r]['pstyle']],
-                                                        legend = self.raster[r]['plegend'])
-
-                self.plotlist.append(self.raster[r]['pline'])
-          
-        if len(self.plotlist) > 0:        
-            return self.plotlist
-        else:
-            return None
-
-    def Update(self):
-        """!Update histogram after changing options
-        """
-        self.SetGraphStyle()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
- 
-    def OnStats(self, event):
-        """!Displays regression information in messagebox
-        """
-        message = []
-        title = _('Statistics for Map(s) Histogrammed')
-
-        for r in self.rasterList:
-            rast = r.split('@')[0] 
-            ret = grass.read_command('r.univar', map = r, flags = 'e', quiet = True)
-            stats = _('Statistics for %s\n\n%s\n') % (rast, ret)
-            message.append(stats)
-            
-        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
-                                      title = title)
-
-        if stats.Show() == wx.ID_CLOSE:
-            stats.Destroy()       
-        
-class ProfileFrame(AbstractPlotFrame):
-    """!Mainframe for displaying profile of one or more raster maps. Uses wx.lib.plot.
-    """
-    def __init__(self, parent, id, pos, style, size, rasterList = []):
-
-        AbstractPlotFrame.__init__(self, parent)
-
-        self.toolbar = ProfileToolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-        self.SetLabel(_("GRASS Profile Analysis Tool"))
-
-        #
-        # Init variables
-        #
-        self.rasterList = rasterList
-        self.plottype = 'profile'
-        self.coordstr = ''              # string of coordinates for r.profile
-        self.seglist = []               # segment endpoint list
-        self.ppoints = ''               # segment endpoints data         
-        self.transect_length = 0.0      # total transect length        
-        self.ptitle = _('Profile of')   # title of window
-        self.raster = {}
-
-        self.colorList =  ["blue", "red", "green", "yellow", "magenta", "cyan", \
-                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
-                    "indigo"]
-
-        if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
-            self.InitRasterOpts(self.rasterList, self.plottype)
-            
-        
-        self._initOpts()
-
-        # determine units (axis labels)
-        if self.parent.Map.projinfo['units'] != '':
-            self.xlabel = _('Distance (%s)') % self.parent.Map.projinfo['units']
-        else:
-            self.xlabel = _("Distance along transect")
-        self.ylabel = _("Cell values")
-        
-    def _initOpts(self):
-        """!Initialize plot options
-        """
-        self.InitPlotOpts('profile')
-
-    def OnDrawTransect(self, event):
-        """!Draws transect to profile in map display
-        """
-        self.mapwin.polycoords = []
-        self.seglist = []
-        self.mapwin.ClearLines(self.mapwin.pdc)
-        self.ppoints = ''
-
-        self.parent.SetFocus()
-        self.parent.Raise()
-        
-        self.mapwin.mouse['use'] = 'profile'
-        self.mapwin.mouse['box'] = 'line'
-        self.mapwin.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
-        self.mapwin.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SHORT_DASH)
-        self.mapwin.SetCursor(self.Parent.cursors["cross"])
-
-    def OnSelectRaster(self, event):
-        """!Select raster map(s) to profile
-        """
-        dlg = dialogs.ProfileRasterDialog(parent = self)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            self.rasterList = dlg.rasterList
-            self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
-            
-            # plot profile
-            if len(self.mapwin.polycoords) > 0 and len(self.rasterList) > 0:
-                self.OnCreateProfile(event = None)
-
-        dlg.Destroy()
-
-    def SetupProfile(self):
-        """!Create coordinate string for profiling. Create segment list for
-           transect segment markers.
-        """
-
-        #
-        # create list of coordinate points for r.profile
-        #                
-        dist = 0
-        cumdist = 0
-        self.coordstr = ''
-        lasteast = lastnorth = None
-        
-        if len(self.mapwin.polycoords) > 0:
-            for point in self.mapwin.polycoords:
-                # build string of coordinate points for r.profile
-                if self.coordstr == '':
-                    self.coordstr = '%d,%d' % (point[0], point[1])
-                else:
-                    self.coordstr = '%s,%d,%d' % (self.coordstr, point[0], point[1])
-
-        if len(self.rasterList) == 0:
-            return
-
-        # title of window
-        self.ptitle = _('Profile of')
-
-        #
-        # create list of coordinates for transect segment markers
-        #
-        if len(self.mapwin.polycoords) > 0:
-            self.seglist = []
-            for point in self.mapwin.polycoords:
-                # get value of raster cell at coordinate point
-                ret = gcmd.RunCommand('r.what',
-                                      parent = self,
-                                      read = True,
-                                      input = self.rasterList[0],
-                                      east_north = '%d,%d' % (point[0],point[1]))
-                
-                val = ret.splitlines()[0].split('|')[3]
-                if val == None or val == '*': continue
-                val = float(val)
-                
-                # calculate distance between coordinate points
-                if lasteast and lastnorth:
-                    dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
-                cumdist += dist
-                
-                #store total transect length
-                self.transect_length = cumdist
-
-                # build a list of distance,value pairs for each segment of transect
-                self.seglist.append((cumdist,val))
-                lasteast = point[0]
-                lastnorth = point[1]
-
-            # delete extra first segment point
-            try:
-                self.seglist.pop(0)
-            except:
-                pass
-
-        #
-        # create datalist of dist/value pairs and y labels for each raster map
-        #    
-        self.ylabel = ''
-        i = 0
-
-        for r in self.raster.iterkeys():
-            self.raster[r]['datalist'] = []
-            datalist = self.CreateDatalist(r, self.coordstr)
-            if len(datalist) > 0:   
-                self.raster[r]['datalist'] = datalist
-
-                # update ylabel to match units if they exist           
-                if self.raster[r]['units'] != '':
-                    self.ylabel += '%s (%d),' % (r['units'], i)
-                i += 1
-
-                # update title
-                self.ptitle += ' %s ,' % r.split('@')[0]
-
-        self.ptitle = self.ptitle.rstrip(',')
-            
-        if self.ylabel == '':
-            self.ylabel = _('Raster values')
-        else:
-            self.ylabel = self.ylabel.rstrip(',')
-
-    def CreateDatalist(self, raster, coords):
-        """!Build a list of distance, value pairs for points along transect using r.profile
-        """
-        datalist = []
-        
-        # keep total number of transect points to 500 or less to avoid 
-        # freezing with large, high resolution maps
-        region = grass.region()
-        curr_res = min(float(region['nsres']),float(region['ewres']))
-        transect_rec = 0
-        if self.transect_length / curr_res > 500:
-            transect_res = self.transect_length / 500
-        else: transect_res = curr_res
-        
-        ret = gcmd.RunCommand("r.profile",
-                              parent = self,
-                              input = raster,
-                              profile = coords,
-                              res = transect_res,
-                              null = "nan",
-                              quiet = True,
-                              read = True)
-        
-        if not ret:
-            return []
-            
-        for line in ret.splitlines():
-            dist, elev = line.strip().split(' ')
-            if dist == None or dist == '' or dist == 'nan' or \
-                elev == None or elev == '' or elev == 'nan':
-                continue
-            dist = float(dist)
-            elev = float(elev)
-            datalist.append((dist,elev))
-
-        return datalist
-
-    def OnCreateProfile(self, event):
-        """!Main routine for creating a profile. Uses r.profile to
-        create a list of distance,cell value pairs. This is passed to
-        plot to create a line graph of the profile. If the profile
-        transect is in multiple segments, these are drawn as
-        points. Profile transect is drawn, using methods in mapdisp.py
-        """
-            
-        if len(self.mapwin.polycoords) == 0 or len(self.rasterList) == 0:
-            dlg = wx.MessageDialog(parent = self,
-                                   message = _('You must draw a transect to profile in the map display window.'),
-                                   caption = _('Nothing to profile'),
-                                   style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-            dlg.ShowModal()
-            dlg.Destroy()
-            return
-
-        self.mapwin.SetCursor(self.parent.cursors["default"])
-        self.SetCursor(self.parent.cursors["default"])
-        self.SetGraphStyle()
-        self.SetupProfile()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
-
-        # reset transect
-        self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
-        self.mapwin.mouse['use'] = 'pointer'
-        self.mapwin.mouse['box'] = 'point'
-
-    def CreatePlotList(self):
-        """!Create a plot data list from transect datalist and
-            transect segment endpoint coordinates.
-        """
-        # graph the distance, value pairs for the transect
-        self.plotlist = []
-
-        # Add segment marker points to plot data list
-        if len(self.seglist) > 0 :
-            self.ppoints = plot.PolyMarker(self.seglist,
-                                           legend = ' ' + self.properties['marker']['legend'],
-                                           colour = wx.Color(self.properties['marker']['color'][0],
-                                                           self.properties['marker']['color'][1],
-                                                           self.properties['marker']['color'][2],
-                                                           255),
-                                           size = self.properties['marker']['size'],
-                                           fillstyle = self.ptfilldict[self.properties['marker']['fill']],
-                                           marker = self.properties['marker']['type'])
-            self.plotlist.append(self.ppoints)
-
-        # Add profile distance/elevation pairs to plot data list for each raster profiled
-        for r in self.rasterList:
-            col = wx.Color(self.raster[r]['pcolor'][0],
-                           self.raster[r]['pcolor'][1],
-                           self.raster[r]['pcolor'][2],
-                           255)
-            self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
-                                                    colour = col,
-                                                    width = self.raster[r]['pwidth'],
-                                                    style = self.linestyledict[self.raster[r]['pstyle']],
-                                                    legend = self.raster[r]['plegend'])
-
-            self.plotlist.append(self.raster[r]['pline'])
-
-        if len(self.plotlist) > 0:        
-            return self.plotlist
-        else:
-            return None
-
-    def Update(self):
-        """!Update profile after changing options
-        """
-        self.SetGraphStyle()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
-
-    def SaveProfileToFile(self, event):
-        """!Save r.profile data to a csv file
-        """    
-        wildcard = _("Comma separated value (*.csv)|*.csv")
-        
-        dlg = wx.FileDialog(parent = self,
-                            message = _("Path and prefix (for raster name) to save profile values..."),
-                            defaultDir = os.getcwd(), 
-                            defaultFile = "",  wildcard = wildcard, style = wx.SAVE)
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-            
-            for r in self.rasterList:
-                pfile = path+'_'+str(r['name'])+'.csv'
-                try:
-                    file = open(pfile, "w")
-                except IOError:
-                    wx.MessageBox(parent = self,
-                                  message = _("Unable to open file <%s> for writing.") % pfile,
-                                  caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
-                    return False
-                for datapair in self.raster[r]['datalist']:
-                    file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
-                                        
-                file.close()
-
-        dlg.Destroy()
-        
-    def OnStats(self, event):
-        """!Displays regression information in messagebox
-        """
-        message = []
-        title = _('Statistics for Profile(s)')
-
-        for r in self.raster.iterkeys():
-            try:
-                rast = r.split('@')[0] 
-                statstr = 'Profile of %s\n\n' % rast
-
-                iterable = (i[1] for i in self.raster[r]['datalist'])            
-                a = numpy.fromiter(iterable, numpy.float)
-                
-                statstr += 'n: %f\n' % a.size
-                statstr += 'minimum: %f\n' % numpy.amin(a)
-                statstr += 'maximum: %f\n' % numpy.amax(a)
-                statstr += 'range: %f\n' % numpy.ptp(a)
-                statstr += 'mean: %f\n' % numpy.mean(a)
-                statstr += 'standard deviation: %f\n' % numpy.std(a)
-                statstr += 'variance: %f\n' % numpy.var(a)
-                cv = numpy.std(a)/numpy.mean(a)
-                statstr += 'coefficient of variation: %f\n' % cv
-                statstr += 'sum: %f\n' % numpy.sum(a)
-                statstr += 'median: %f\n' % numpy.median(a)
-                statstr += 'distance along transect: %f\n\n' % self.transect_length       
-                message.append(statstr)
-            except:
-                pass
-            
-        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
-                                      title = title)
-
-        if stats.Show() == wx.ID_CLOSE:
-            stats.Destroy()       
-        
-class ScatterFrame(AbstractPlotFrame):
-    """!Mainframe for displaying bivariate scatter plot of two raster maps. Uses wx.lib.plot.
-    """
-    def __init__(self, parent, id, pos, style, size, rasterList = []):
-
-        AbstractPlotFrame.__init__(self, parent)
-        
-        self.toolbar = ScatterplotToolbar(parent = self)
-        self.SetToolBar(self.toolbar)
-        self.SetLabel(_("GRASS Bivariate Scatterplot Tool"))
-
-        #
-        # Init variables
-        #
-        self.rasterList = rasterList
-        self.plottype = 'scatter'
-        self.ptitle = _('Bivariate Scatterplot')     # title of window
-        self.xlabel = _("Raster cell values")           # default X-axis label
-        self.ylabel = _("Raster cell values")           # default Y-axis label
-        self.maptype = 'raster'                         # default type of scatterplot
-        self.scattertype = 'normal' 
-        self.bins = 255
-        self.colorList = ["blue", "red", "black", "green", "yellow", "magenta", "cyan", \
-                    "aqua", "grey", "orange", "brown", "purple", "violet", \
-                    "indigo"]
-        
-        if len(self.rasterList) > 1: # set raster name(s) from layer manager if a map is selected
-            self.InitRasterOpts(self.rasterList, 'scatter')
-
-        self._initOpts()
-
-    def _initOpts(self):
-        """!Initialize plot options
-        """
-        self.InitPlotOpts('scatter')            
-
-    def OnCreateScatter(self, event):
-        """!Main routine for creating a scatterplot. Uses r.stats to
-        create a list of cell value pairs. This is passed to
-        plot to create a scatterplot.
-        """
-        self.SetCursor(self.parent.cursors["default"])
-        self.SetGraphStyle()
-        self.SetupScatterplot()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
-
-    def OnSelectRaster(self, event):
-        """!Select raster map(s) to profile
-        """
-        dlg = dialogs.ScatterRasterDialog(parent = self)
-
-        if dlg.ShowModal() == wx.ID_OK:
-            rlist = dlg.rasterList
-            if rlist < 2: 
-                dlg.Destroy()
-                return                        # need at least 2 rasters for scatterplot
-
-            self.bins = dlg.bins                        # bins for r.stats with float and dcell maps
-            self.scattertype = dlg.scattertype          # scatterplot or bubbleplot
-            self.rasterList = self.CreatePairs(rlist)   # list of raster pairs (tuples)
-            self.raster = self.InitRasterPairs(self.rasterList, 'scatter') # dictionary of raster pairs
-
-            # plot histogram
-            if len(self.rasterList) > 0:
-                self.OnCreateScatter(event = None)
-
-        dlg.Destroy()
-        
-    def CreatePairs(self, rlist):
-        """!Transforms list of rasters into tuples of raster pairs
-        """
-        rasterList = []
-        next = 'first'
-        for r in rlist:
-            if next == 'first':
-                first = r
-                next = 'second'
-            else:
-                second = r
-                t = (first, second)
-                rasterList.append(t)
-                next = 'first'
-                first = second = ''
-                
-        return rasterList
-
-    def SetupScatterplot(self):
-        """!Build data list for ploting each raster
-        """
-
-        #
-        # initialize title string
-        #
-        self.ptitle = _('Bivariate Scatterplot of ')        
-
-        #
-        # create a datalist for plotting for each raster pair
-        #
-        if len(self.rasterList) == 0: return  # at least 1 pair of maps needed to plot        
-        
-        for rpair in self.rasterList:
-            self.raster[rpair]['datalist'] = self.CreateDatalist(rpair)
-            
-            # update title
-            self.ptitle += '%s vs %s, ' % (rpair[0].split('@')[0], rpair[1].split('@')[0])
-
-        self.ptitle = self.ptitle.strip(', ')
-        
-        #
-        # set xlabel & ylabel based on raster maps of first pair to be plotted
-        #
-        units = self.raster[self.rasterList[0]][0]['units']
-        if units != '' and units != '(none)' and units != None:
-            self.xlabel = _('Raster cell values %s') % units
-        else:
-            self.xlabel = _('Raster cell values') 
-
-        units = self.raster[self.rasterList[0]][1]['units']
-        if units != '' and units != '(none)' and units != None:
-            self.ylabel = _('Raster cell values %s') % units
-        else:
-            self.ylabel = _('Raster cell values') 
-
-    def CreateDatalist(self, rpair):
-        """!Build a list of cell value, frequency pairs for histogram
-            frequency can be in cell counts, percents, or area
-        """
-        datalist = []
-        
-        if self.scattertype == 'bubble': 
-            freqflag = 'cn'
-        else:
-            freqflag = 'n'
-                
-        try:
-            ret = gcmd.RunCommand("r.stats",
-                                  parent = self,
-                                  input = '%s,%s' % rpair,
-                                  flags = freqflag,
-                                  nsteps = self.bins,
-                                  fs = ',',
-                                  quiet = True,
-                                  read = True)
-            
-            if not ret:
-                return datalist
-            
-            for line in ret.splitlines():
-                rast1, rast2 = line.strip().split(',')
-                rast1 = rast1.strip()
-                if '-' in rast1: rast1 = rast1.split('-')[0]
-                rast2 = rast2.strip()
-                if '-' in rast2: rast2 = rast2.split('-')[0]
-                
-                rast1 = rast1.encode('ascii', 'ignore')
-                rast2 = rast2.encode('ascii', 'ignore')
-                    
-                datalist.append((rast1,rast2))
-
-            return datalist
-        except gcmd.GException, e:
-            gcmd.GError(parent = self,
-                        message = e.value)
-            return None
-        
-    def CreatePlotList(self):
-        """!Make list of elements to plot
-        """
-        # graph the cell value, frequency pairs for the histogram
-        self.plotlist = []
-
-        for rpair in self.rasterList:
-            if 'datalist' not in self.raster[rpair] or \
-                self.raster[rpair]['datalist'] == None: return
-            
-            if len(self.raster[rpair]['datalist']) > 0:
-                col = wx.Color(self.raster[rpair]['pcolor'][0],
-                               self.raster[rpair]['pcolor'][1],
-                               self.raster[rpair]['pcolor'][2],
-                               255)
-                scatterpoints = plot.PolyMarker(self.raster[rpair]['datalist'],
-                                                legend = ' ' + self.raster[rpair]['plegend'],
-                                                colour = col,size = self.raster[rpair]['psize'],
-                                                fillstyle = self.ptfilldict[self.raster[rpair]['pfill']],
-                                                marker = self.raster[rpair]['ptype'])
-
-                self.plotlist.append(scatterpoints)
-          
-        if len(self.plotlist) > 0:        
-            return self.plotlist
-        else:
-            return None
-
-    def Update(self):
-        """!Update histogram after changing options
-        """
-        self.SetGraphStyle()
-        p = self.CreatePlotList()
-        self.DrawPlot(p)
-    
-    def OnRegression(self, event):
-        """!Displays regression information in messagebox
-        """
-        message = []
-        title = _('Regression Statistics for Scatterplot(s)')
-
-        for rpair in self.rasterList:
-            if isinstance(rpair, tuple) == False: continue
-            rast1, rast2 = rpair
-            rast1 = rast1.split('@')[0] 
-            rast2 = rast2.split('@')[0] 
-            ret = grass.parse_command('r.regression.line', 
-                                      map1 = rast1, 
-                                      map2 = rast2, 
-                                      flags = 'g', quiet = True,
-                                      parse = (grass.parse_key_val, { 'sep' : '=' }))
-            eqtitle = _('Regression equation for %s vs. %s:\n\n')  % (rast1, rast2)
-            eq = _('   %s = %s + %s(%s)\n\n') % (rast2, ret['a'], ret['b'], rast1)
-            num = _('N = %s\n') % ret['N']
-            rval = _('R = %s\n') % ret['R']
-            rsq = _('R-squared = %f\n') % pow(float(ret['R']), 2)
-            ftest = _('F = %s\n') % ret['F']
-            str = eqtitle + eq + num + rval + rsq + ftest
-            message.append(str)
-            
-        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
-                                      title = title)
-
-        if stats.Show() == wx.ID_CLOSE:
-            stats.Destroy()       
\ No newline at end of file

Deleted: grass/trunk/gui/wxpython/gui_modules/wxplot_dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxplot_dialogs.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/wxplot_dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1238 +0,0 @@
-"""!
- at package wxplot_dialogs.py
-
-Iinteractive plotting using PyPlot (wx.lib.plot.py). Dialogs for
-different plotting routines.
-
-Classes:
- - ProfileRasterDialog
- - HistRasterDialog
- - TextDialog
- - OptDialog
-
-(C) 2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Michael Barton, Arizona State University
-"""
-
-import os
-import sys
-from types import *
-
-import wx
-import wx.lib.colourselect as  csel
-import wx.lib.scrolledpanel as scrolled
-
-import globalvar
-import gcmd
-from gselect     import Select
-from preferences import globalSettings as UserSettings
-
-from grass.script import core   as grass
-
-class ProfileRasterDialog(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, 
-                 title = _("Select raster maps to profile"),
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
-        """!Dialog to select raster maps to profile.
-        """
-
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-
-
-        self.parent = parent
-        self.colorList = ["blue", "red", "green", "yellow", "magenta", "cyan", \
-                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
-                    "indigo"]
-
-        self.rasterList = self.parent.rasterList
-        
-        self._do_layout()
-        
-    def _do_layout(self):
-
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.GridBagSizer (hgap = 3, vgap = 3)
-        
-        rastText = ''
-        for r in self.rasterList:
-            rastText += '%s,' % r
-            
-        rastText = rastText.rstrip(',')
-        
-        txt = _("Select raster map(s) to profile:")
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = txt)
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        
-        selection = Select(self, id = wx.ID_ANY,
-                           size = globalvar.DIALOG_GSELECT_SIZE,
-                           type = 'cell', multiple=True)
-        selection.SetValue(rastText)
-        selection.Bind(wx.EVT_TEXT, self.OnSelection)
-        
-        box.Add(item = selection, pos = (0, 1))
-            
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.ALL, border = 10)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(self, wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(self, wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnSelection(self, event):
-        """!Choose maps to profile. Convert these into a list
-        """
-        self.rasterList = []
-        self.rasterList = event.GetString().split(',')
-
-class ScatterRasterDialog(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, 
-                 title = _("Select pairs of raster maps for scatterplots"),
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
-        """!Dialog to select raster maps to profile.
-        """
-
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-
-        self.parent = parent
-        self.rasterList = self.parent.rasterList
-        self.bins = self.parent.bins
-        self.scattertype = self.parent.scattertype
-        self.maptype = self.parent.maptype
-        self.spinbins = ''        
-        self.colorList = ["blue", "red", "green", "yellow", "magenta", "cyan", \
-                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
-                    "indigo"]
-        
-        self._do_layout()
-        
-    def _do_layout(self):
-
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.GridBagSizer (hgap = 3, vgap = 3)
-        
-        # parse raster pair tuples 
-        rastText = ''
-        if len(self.rasterList) > 0:
-            for r in self.rasterList:
-                if isinstance(r, tuple):
-                    rastText += '%s,%s,' % r
-                else:
-                    rastText += '%s,' % r
-            rastText = rastText.rstrip(',')
-        
-        # select rasters
-        txt = _("Select pairs of raster maps for bivariate scatterplots:")
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = txt)
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        
-        selection = Select(self, id = wx.ID_ANY,
-                           size = globalvar.DIALOG_GSELECT_SIZE,
-                           type = 'cell', multiple=True)
-        selection.SetValue(rastText)
-        selection.Bind(wx.EVT_TEXT, self.OnSelection)
-        
-        box.Add(item = selection, pos = (0, 1))
-            
-        # Nsteps for FP maps 
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-                              label = _("Number of bins (for FP maps)"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-        self.spinbins = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                      size = (100,-1), style = wx.SP_ARROW_KEYS)
-        self.spinbins.SetRange(1,1000)
-        self.spinbins.SetValue(self.bins)
-        box.Add(item = self.spinbins,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 1))
-
-#### TODO possibly make bubble plots with marker size proportional to cell counts
-#        # scatterplot type 
-#        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-#                              label = _("Scatterplot type"))
-#        box.Add(item = label,
-#                flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-#        types = ['normal', 'bubble']
-#        scattertype = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
-#                                choices = types, style = wx.CB_DROPDOWN)
-#        scattertype.SetStringSelection(self.scattertype)
-#        box.Add(item = scattertype,
-#                flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 1))
-          
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.ALL, border = 10)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(self, wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(self, wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
-        self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
-#        scattertype.Bind(wx.EVT_TEXT, self.OnSetScattertypes)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnSelection(self, event):
-        """!Select raster maps for scatterplot. Must select maps in pairs.
-        """
-        self.rasterList = []
-        self.rasterList = event.GetString().split(',')
-            
-    def OnSetBins(self, event):
-        """!Bins for histogramming FP maps (=nsteps in r.stats)
-        """
-        self.bins = self.spinbins.GetValue()
-        
-    def OnSetScattertypes(self, event):
-        self.scattertype = event.GetString()
-        
-class PlotStatsFrame(wx.Frame):
-    def __init__(self, parent, id, message = '', title = '',
-                 style = wx.DEFAULT_FRAME_STYLE, **kwargs):
-        """!Dialog to display and save statistics for plots
-        """
-        wx.Frame.__init__(self, parent, id, style = style, **kwargs)
-        self.SetLabel(_("Statistics"))
-        
-        sp = scrolled.ScrolledPanel(self, -1, size=(400, 400),
-                                    style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="Statistics" )
-                
-
-        #
-        # initialize variables
-        #
-        self.parent = parent
-        self.message = message 
-        self.title = title   
-        self.CenterOnParent()  
-        
-        #
-        # Display statistics
-        #
-        sizer = wx.BoxSizer(wx.VERTICAL)
-        txtSizer = wx.BoxSizer(wx.VERTICAL)
-
-        statstitle = wx.StaticText(parent = self, id = wx.ID_ANY, label = self.title)
-        sizer.Add(item = statstitle, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
-        for stats in self.message:
-            statstxt = wx.StaticText(parent = sp, id = wx.ID_ANY, label = stats)
-            statstxt.SetBackgroundColour("WHITE")
-            txtSizer.Add(item = statstxt, proportion = 1, 
-                         flag = wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
-            line = wx.StaticLine(parent = sp, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL) 
-            txtSizer.Add(item = line, proportion = 0,
-                         flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)      
-
-        sp.SetSizer(txtSizer)
-        sp.SetAutoLayout(1)
-        sp.SetupScrolling() 
-
-        sizer.Add(item = sp, proportion = 1, 
-                  flag = wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 3)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW |wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
-
-        #
-        # buttons
-        #
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        btn_clipboard = wx.Button(self, id = wx.ID_COPY, label = _('C&opy'))
-        btn_clipboard.SetToolTipString(_("Copy regression statistics the clipboard (Ctrl+C)"))
-        btnSizer.Add(item = btn_clipboard, proportion = 0, flag = wx.ALIGN_LEFT | wx.ALL, border = 5)
-        
-        btnCancel = wx.Button(self, wx.ID_CLOSE)
-        btnCancel.SetDefault()
-        btnSizer.Add(item = btnCancel, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)        
-
-        sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        # bindings
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnClose)
-        btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
-        
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnCopy(self, event):
-        """!Copy the regression stats to the clipboard
-        """
-        str = self.title + '\n'
-        for item in self.message:
-            str += item
-            
-        rdata = wx.TextDataObject()
-        rdata.SetText(str)
-        
-        if wx.TheClipboard.Open():
-            wx.TheClipboard.SetData(rdata)
-            wx.TheClipboard.Close()
-            wx.MessageBox(_("Regression statistics copied to clipboard"))
-        
-    def OnClose(self, event):
-        """!Button 'Close' pressed
-        """
-        self.Close(True)
-
-class HistRasterDialog(wx.Dialog):
-    def __init__(self, parent, id = wx.ID_ANY, 
-                 title = _("Select raster map or imagery group to histogram"),
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
-        """!Dialog to select raster maps to histogram.
-        """
-
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-
-        self.parent = parent
-        self.rasterList = self.parent.rasterList
-        self.group = self.parent.group
-        self.bins = self.parent.bins
-        self.histtype = self.parent.histtype
-        self.maptype = self.parent.maptype
-        self.spinbins = ''
-        
-        self._do_layout()
-        
-    def _do_layout(self):
-
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.GridBagSizer (hgap = 3, vgap = 3)
-        
-        #
-        # select single raster or image group to histogram radio buttons
-        #
-        self.rasterRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram single raster"), style = wx.RB_GROUP)
-        self.groupRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram imagery group"))
-        if self.maptype == 'raster': 
-            self.rasterRadio.SetValue(True)
-        elif self.maptype == 'group': 
-            self.groupRadio.SetValue(True)
-        box.Add(item = self.rasterRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        box.Add(item = self.groupRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
-        
-        #
-        # Select a raster to histogram
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-                              label = _("Select raster map:"))
-        box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-        self.rselection = Select(self, id = wx.ID_ANY,
-                                 size = globalvar.DIALOG_GSELECT_SIZE,
-                                 type = 'cell')
-        if self.groupRadio.GetValue() == True: 
-            self.rselection.Disable()
-        else:
-            if len(self.rasterList) > 0: self.rselection.SetValue(self.rasterList[0])
-        box.Add(item = self.rselection, pos = (1, 1))       
-
-        #
-        # Select an image group to histogram
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-                              label = _("Select image group:"))
-        box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-        self.gselection = Select(self, id = wx.ID_ANY,
-                                 size = globalvar.DIALOG_GSELECT_SIZE,
-                                 type = 'group')
-        if self.rasterRadio.GetValue() == True: 
-            self.gselection.Disable()
-        else:
-            if self.group != None: self.gselection.SetValue(self.group)
-        box.Add(item = self.gselection, pos = (2, 1))
-            
-        #
-        # Nsteps for FP maps and histogram type selection
-        #
-
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-                              label = _("Number of bins (for FP maps)"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
-        self.spinbins = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                      size = (100,-1), style = wx.SP_ARROW_KEYS)
-        self.spinbins.SetRange(1,1000)
-        self.spinbins.SetValue(self.bins)
-        box.Add(item = self.spinbins,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 1))
-
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
-                              label = _("Histogram type"))
-        box.Add(item = label,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
-        types = ['count', 'percent', 'area']
-        histtype = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
-                                choices = types, style = wx.CB_DROPDOWN)
-        histtype.SetStringSelection(self.histtype)
-        box.Add(item = histtype,
-                flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 1))
-          
-        sizer.Add(item = box, proportion = 0,
-                  flag = wx.ALL, border = 10)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
-
-        btnsizer = wx.StdDialogButtonSizer()
-
-        btn = wx.Button(self, wx.ID_OK)
-        btn.SetDefault()
-        btnsizer.AddButton(btn)
-
-        btn = wx.Button(self, wx.ID_CANCEL)
-        btnsizer.AddButton(btn)
-        btnsizer.Realize()
-
-        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        #
-        # bindings
-        #
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.rasterRadio)
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.groupRadio)
-        self.rselection.Bind(wx.EVT_TEXT, self.OnRasterSelection)
-        self.gselection.Bind(wx.EVT_TEXT, self.OnGroupSelection)
-        self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
-        self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
-        histtype.Bind(wx.EVT_TEXT, self.OnSetHisttypes)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnHistMap(self, event):
-        """!Hander for radio buttons to choose between histogramming a
-            single raster and an imagery group
-        """
-        if self.rasterRadio.GetValue() == True:
-            self.maptype = 'raster'
-            self.rselection.Enable()
-            self.gselection.Disable()
-            self.gselection.SetValue('')
-        elif self.groupRadio.GetValue() == True:
-            self.maptype = 'group'
-            self.gselection.Enable()
-            self.rselection.Disable()
-            self.rselection.SetValue('')
-        else:
-            pass
-        
-    def OnRasterSelection(self, event):
-        """!Handler for selecting a single raster map
-        """
-        self.rasterList = []
-        self.rasterList.append(event.GetString())
-
-    def OnGroupSelection(self, event):
-        """!Handler for selecting imagery group
-        """
-        self.rasterList = []
-        self.group = event.GetString()
-        ret = grass.read_command('i.group', 
-                                  group = '%s' % self.group, 
-                                  quiet = True,
-                                  flags = 'g').strip().split('\n')
-        if ret != None and ret != '':
-            self.rasterList = ret
-                                                                                            
-    def OnSetBins(self, event):
-        """!Bins for histogramming FP maps (=nsteps in r.stats)
-        """
-        self.bins = self.spinbins.GetValue()
-        
-    def OnSetHisttypes(self, event):
-        self.histtype = event.GetString()
-        
-
-class TextDialog(wx.Dialog):
-    def __init__(self, parent, id, title, plottype = '',
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
-        """!Dialog to set histogram text options: font, title
-        and font size, axis labels and font size
-        """
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-        #
-        # initialize variables
-        #
-        # combo box entry lists
-        self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
-                             'decorative' : wx.FONTFAMILY_DECORATIVE,
-                             'roman' : wx.FONTFAMILY_ROMAN,
-                             'script' : wx.FONTFAMILY_SCRIPT,
-                             'swiss' : wx.FONTFAMILY_SWISS,
-                             'modern' : wx.FONTFAMILY_MODERN,
-                             'teletype' : wx.FONTFAMILY_TELETYPE }
-
-        self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
-                            'slant' : wx.FONTSTYLE_SLANT,
-                            'italic' : wx.FONTSTYLE_ITALIC }
-
-        self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
-                         'light' : wx.FONTWEIGHT_LIGHT,
-                         'bold' : wx.FONTWEIGHT_BOLD }
-
-        self.parent = parent
-
-        self.ptitle = self.parent.ptitle
-        self.xlabel = self.parent.xlabel
-        self.ylabel = self.parent.ylabel
-
-        self.properties = self.parent.properties # read-only
-        
-        # font size
-        self.fontfamily = self.properties['font']['wxfont'].GetFamily()
-        self.fontstyle = self.properties['font']['wxfont'].GetStyle()
-        self.fontweight = self.properties['font']['wxfont'].GetWeight()
-
-        self._do_layout()
-                
-    def _do_layout(self):
-        """!Do layout"""
-        # dialog layout
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Text settings"))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-
-        #
-        # profile title
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Profile title:"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        self.ptitleentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
-        # self.ptitleentry.SetFont(self.font)
-        self.ptitleentry.SetValue(self.ptitle)
-        gridSizer.Add(item = self.ptitleentry, pos = (0, 1))
-
-        #
-        # title font
-        #
-        tlabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Title font size (pts):"))
-        gridSizer.Add(item = tlabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-        self.ptitlesize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                      size = (50,-1), style = wx.SP_ARROW_KEYS)
-        self.ptitlesize.SetRange(5,100)
-        self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
-        gridSizer.Add(item = self.ptitlesize, pos = (1, 1))
-
-        #
-        # x-axis label
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("X-axis label:"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-        self.xlabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
-        # self.xlabelentry.SetFont(self.font)
-        self.xlabelentry.SetValue(self.xlabel)
-        gridSizer.Add(item = self.xlabelentry, pos = (2, 1))
-
-        #
-        # y-axis label
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Y-axis label:"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
-        self.ylabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
-        # self.ylabelentry.SetFont(self.font)
-        self.ylabelentry.SetValue(self.ylabel)
-        gridSizer.Add(item = self.ylabelentry, pos = (3, 1))
-
-        #
-        # font size
-        #
-        llabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Label font size (pts):"))
-        gridSizer.Add(item = llabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
-        self.axislabelsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
-                                         size = (50, -1), style = wx.SP_ARROW_KEYS)
-        self.axislabelsize.SetRange(5, 100) 
-        self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
-        gridSizer.Add(item = self.axislabelsize, pos = (4,1))
-
-        boxSizer.Add(item = gridSizer)
-        sizer.Add(item = boxSizer, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        #
-        # font settings
-        #
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Font settings"))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        gridSizer.AddGrowableCol(1)
-
-        #
-        # font family
-        #
-        label1 = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Font family:"))
-        gridSizer.Add(item = label1, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-        self.ffamilycb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
-                                choices = self.ffamilydict.keys(), style = wx.CB_DROPDOWN)
-        self.ffamilycb.SetStringSelection('swiss')
-        for item in self.ffamilydict.items():
-            if self.fontfamily == item[1]:
-                self.ffamilycb.SetStringSelection(item[0])
-                break
-        gridSizer.Add(item = self.ffamilycb, pos = (0, 1), flag = wx.ALIGN_RIGHT)
-
-        #
-        # font style
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style:"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-        self.fstylecb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
-                                    choices = self.fstyledict.keys(), style = wx.CB_DROPDOWN)
-        self.fstylecb.SetStringSelection('normal')
-        for item in self.fstyledict.items():
-            if self.fontstyle == item[1]:
-                self.fstylecb.SetStringSelection(item[0])
-                break
-        gridSizer.Add(item = self.fstylecb, pos = (1, 1), flag = wx.ALIGN_RIGHT)
-
-        #
-        # font weight
-        #
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Weight:"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-        self.fwtcb = wx.ComboBox(parent = self, size = (250, -1),
-                                 choices = self.fwtdict.keys(), style = wx.CB_DROPDOWN)
-        self.fwtcb.SetStringSelection('normal')
-        for item in self.fwtdict.items():
-            if self.fontweight == item[1]:
-                self.fwtcb.SetStringSelection(item[0])
-                break
-
-        gridSizer.Add(item = self.fwtcb, pos = (2, 1), flag = wx.ALIGN_RIGHT)
-                      
-        boxSizer.Add(item = gridSizer, flag = wx.EXPAND)
-        sizer.Add(item = boxSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
-
-        #
-        # buttons
-        #
-        btnSave = wx.Button(self, wx.ID_SAVE)
-        btnApply = wx.Button(self, wx.ID_APPLY)
-        btnOk = wx.Button(self, wx.ID_OK)
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnOk.SetDefault()
-
-        # bindings
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnApply.SetToolTipString(_("Apply changes for the current session"))
-        btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
-        btnOk.SetToolTipString(_("Apply changes for the current session and close dialog"))
-        btnOk.SetDefault()
-        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-
-        # sizers
-        btnStdSizer = wx.StdDialogButtonSizer()
-        btnStdSizer.AddButton(btnOk)
-        btnStdSizer.AddButton(btnApply)
-        btnStdSizer.AddButton(btnCancel)
-        btnStdSizer.Realize()
-        
-        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
-        btnSizer.Add(item = btnSave, proportion = 0, flag = wx.ALIGN_LEFT | wx.ALL, border = 5)
-        btnSizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-        sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        #
-        # bindings
-        #
-        self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
-        self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
-        self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnTitle(self, event):
-        self.ptitle = event.GetString()
-
-    def OnXLabel(self, event):
-        self.xlabel = event.GetString()
-
-    def OnYLabel(self, event):
-        self.ylabel = event.GetString()
-
-    def UpdateSettings(self):
-        self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
-        self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()
-
-        family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
-        self.properties['font']['wxfont'].SetFamily(family)
-        style = self.fstyledict[self.fstylecb.GetStringSelection()]
-        self.properties['font']['wxfont'].SetStyle(style)
-        weight = self.fwtdict[self.fwtcb.GetStringSelection()]
-        self.properties['font']['wxfont'].SetWeight(weight)
-
-    def OnSave(self, event):
-        """!Button 'Save' pressed"""
-        self.UpdateSettings()
-        fileSettings = {}
-        UserSettings.ReadSettingsFile(settings=fileSettings)
-        fileSettings['plot'] = UserSettings.Get(group = 'plot')
-        file = UserSettings.SaveToFile(fileSettings)
-        self.parent.parent.GetLayerManager().goutput.WriteLog(_('Plot text settings saved to file \'%s\'.') % file)
-        self.EndModal(wx.ID_OK)
-
-    def OnApply(self, event):
-        """!Button 'Apply' pressed"""
-        self.UpdateSettings()
-        self.parent.OnPlotText(self)
-        
-    def OnOk(self, event):
-        """!Button 'OK' pressed"""
-        self.UpdateSettings()
-        self.EndModal(wx.ID_OK)
-
-    def OnCancel(self, event):
-        """!Button 'Cancel' pressed"""
-        self.EndModal(wx.ID_CANCEL)
-        
-class OptDialog(wx.Dialog):
-    def __init__(self, parent, id, title, plottype = '',
-                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs): 
-        """!Dialog to set various options for data plotted, including: line
-        width, color, style; marker size, color, fill, and style; grid
-        and legend options.
-        """
-        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
-        # init variables
-        self.parent = parent
-        self.linestyledict = parent.linestyledict
-        self.ptfilldict = parent.ptfilldict
-        self.plottype = plottype
-        
-        self.pttypelist = ['circle',
-                           'dot',
-                           'square',
-                           'triangle',
-                           'triangle_down',
-                           'cross',
-                           'plus']
-        
-        self.axislist = ['min',
-                         'auto',
-                         'custom']
-
-        # widgets ids
-        self.wxId = {}
-        
-        self.parent = parent
-
-        # read-only
-        self.raster = self.parent.raster
-        self.rasterList = self.parent.rasterList
-        self.properties = self.parent.properties
-        self.map = ''
-        
-        if len(self.rasterList) == 0:
-            wx.MessageBox(parent = self,
-                              message = _("No map or image group selected to plot."),
-                              caption = _("Warning"), style = wx.OK | wx.ICON_ERROR)
-            
-        self._do_layout()
-        
-    def ConvertTuples(self, tlist):
-        """!Converts tuples to strings when rasterList contains raster pairs
-            for scatterplot
-        """
-        list = []
-        for i in tlist:
-            i = str(i).strip('()')
-            list.append(i)
-            
-        return list
-
-    def _do_layout(self):
-        """!Do layout"""
-        # dialog layout
-        sizer = wx.BoxSizer(wx.VERTICAL)
-
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Plot settings")) 
-        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
-        self.wxId['pcolor']  = 0
-        self.wxId['pwidth']  = 0
-        self.wxId['pstyle']  = 0
-        self.wxId['psize'] = 0
-        self.wxId['ptype'] = 0
-        self.wxId['pfill'] = 0
-        self.wxId['plegend'] = 0
-        self.wxId['marker'] = {}
-        self.wxId['x-axis'] = {}
-        self.wxId['y-axis'] = {}
-        
-        #
-        # plot line settings and point settings
-        #
-        if len(self.rasterList) == 0: return
-        
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = _("Map/image plotted"))
-        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-        
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-        
-        row = 0
-        choicelist = []
-        for i in self.rasterList:
-            choicelist.append(str(i))
-
-        self.mapchoice = wx.Choice(parent = self, id = wx.ID_ANY, size = (300, -1),
-                                   choices = choicelist)
-        if not self.map:
-            self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
-        else:
-            self.mapchoice.SetStringSelection(str(self.map))
-            
-                
-        gridSizer.Add(item = self.mapchoice, flag = wx.ALIGN_CENTER_VERTICAL, 
-                      pos = (row, 0), span = (1, 2))
-        
-        #
-        # options for line plots (profiles and histograms)
-        #
-        if self.plottype != 'scatter':
-            row +=1            
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line color"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            color = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.raster[self.map]['pcolor'])
-            self.wxId['pcolor'] = color.GetId()
-            gridSizer.Add(item = color, pos = (row, 1))
-
-            row += 1
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line width"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            width = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
-                                 size = (50,-1), style = wx.SP_ARROW_KEYS)
-            width.SetRange(1, 10)
-            width.SetValue(self.raster[self.map]['pwidth'])
-            self.wxId['pwidth'] = width.GetId()
-            gridSizer.Add(item = width, pos = (row, 1))
-
-            row +=1
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line style"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            style = wx.Choice(parent = self, id = wx.ID_ANY, 
-                                 size = (120, -1), choices = self.linestyledict.keys(), style = wx.CB_DROPDOWN)
-            style.SetStringSelection(self.raster[self.map]['pstyle'])
-            self.wxId['pstyle'] = style.GetId()
-            gridSizer.Add(item = style, pos = (row, 1))
-
-        row += 1
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-        legend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
-        legend.SetValue(self.raster[self.map]['plegend'])
-        gridSizer.Add(item = legend, pos = (row, 1))
-        self.wxId['plegend'] = legend.GetId()
-        
-        boxSizer.Add(item = gridSizer)
-        boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
-
-        #
-        # segment marker settings for profiles only
-        #       
-        if self.plottype == 'profile':
-            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                               label = " %s " % _("Transect segment marker settings"))
-            
-            boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-            
-            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Color"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-            ptcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.properties['marker']['color'])
-            self.wxId['marker']['color'] = ptcolor.GetId()
-            gridSizer.Add(item = ptcolor, pos = (0, 1))
-
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Size"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-            ptsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
-                                 size = (50, -1), style = wx.SP_ARROW_KEYS)
-            ptsize.SetRange(1, 10)
-            ptsize.SetValue(self.properties['marker']['size'])
-            self.wxId['marker']['size'] = ptsize.GetId()
-            gridSizer.Add(item = ptsize, pos = (1, 1))
-            
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-            ptfill = wx.ComboBox(parent = self, id = wx.ID_ANY,
-                                 size = (120, -1), choices = self.ptfilldict.keys(), style = wx.CB_DROPDOWN)
-            ptfill.SetStringSelection(self.properties['marker']['fill'])
-            self.wxId['marker']['fill'] = ptfill.GetId()
-            gridSizer.Add(item = ptfill, pos = (2, 1))
-            
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
-            ptlegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
-            ptlegend.SetValue(self.properties['marker']['legend'])
-            self.wxId['marker']['legend'] = ptlegend.GetId()
-            gridSizer.Add(item = ptlegend, pos = (3, 1))
-                    
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Type"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
-            pttype = wx.ComboBox(parent = self, 
-                                 size = (200, -1), choices = self.pttypelist, style = wx.CB_DROPDOWN)
-            pttype.SetStringSelection(self.properties['marker']['type'])
-            self.wxId['marker']['type'] = pttype.GetId()
-            gridSizer.Add(item = pttype, pos = (4, 1))
-
-            boxSizer.Add(item = gridSizer)
-            boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
-            
-        #
-        # point options for scatterplots
-        #
-        elif self.plottype == 'scatter':
-            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                               label = " %s " % _("Scatterplot points"))
-            
-            boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-            
-            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Color"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
-            ptcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.raster[self.map]['pcolor'])
-            self.wxId['pcolor'] = ptcolor.GetId()
-            gridSizer.Add(item = ptcolor, pos = (0, 1))
-
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Size"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
-            ptsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
-                                 size = (50, -1), style = wx.SP_ARROW_KEYS)
-            ptsize.SetRange(1, 10)
-            ptsize.SetValue(self.raster[self.map]['psize'])
-            self.wxId['psize'] = ptsize.GetId()
-            gridSizer.Add(item = ptsize, pos = (1, 1))
-            
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
-            ptfill = wx.ComboBox(parent = self, id = wx.ID_ANY,
-                                 size = (120, -1), choices = self.ptfilldict.keys(), style = wx.CB_DROPDOWN)
-            ptfill.SetStringSelection(self.raster[self.map]['pfill'])
-            self.wxId['pfill'] = ptfill.GetId()
-            gridSizer.Add(item = ptfill, pos = (2, 1))
-            
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
-            ptlegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
-            ptlegend.SetValue(self.raster[self.map]['plegend'])
-            self.wxId['plegend'] = ptlegend.GetId()
-            gridSizer.Add(item = ptlegend, pos = (3, 1))
-                    
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Type"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
-            pttype = wx.ComboBox(parent = self, 
-                                 size = (200, -1), choices = self.pttypelist, style = wx.CB_DROPDOWN)
-            pttype.SetStringSelection(self.raster[self.map]['ptype'])
-            self.wxId['ptype'] = pttype.GetId()
-            gridSizer.Add(item = pttype, pos = (4, 1))
-
-            boxSizer.Add(item = gridSizer)
-            boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
-            
-        sizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        #
-        # axis options for all plots
-        #
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Axis settings"))
-        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
-        middleSizer = wx.BoxSizer(wx.HORIZONTAL)
-
-        idx = 0
-        for axis, atype in [(_("X-Axis"), 'x-axis'),
-                     (_("Y-Axis"), 'y-axis')]:
-            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                               label = " %s " % axis)
-            boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-
-            prop = self.properties[atype]['prop']
-            
-            row = 0
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            type = wx.Choice(parent = self, id = wx.ID_ANY,
-                               size = (100, -1), choices = self.axislist, style = wx.CB_DROPDOWN)
-            type.SetStringSelection(prop['type']) 
-            self.wxId[atype]['type'] = type.GetId()
-            gridSizer.Add(item = type, pos = (row, 1))
-                        
-            row += 1
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom min"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            min = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
-            min.SetValue(str(prop['min']))
-            self.wxId[atype]['min'] = min.GetId()
-            gridSizer.Add(item = min, pos = (row, 1))
-
-            row += 1
-            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom max"))
-            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-            max = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
-            max.SetValue(str(prop['max']))
-            self.wxId[atype]['max'] = max.GetId()
-            gridSizer.Add(item = max, pos = (row, 1))
-            
-            row += 1
-            log = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Log scale"))
-            log.SetValue(prop['log'])
-            self.wxId[atype]['log'] = log.GetId()
-            gridSizer.Add(item = log, pos = (row, 0), span = (1, 2))
-
-            if idx == 0:
-                flag = wx.ALL | wx.EXPAND
-            else:
-                flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
-
-            boxSizer.Add(item = gridSizer, flag = wx.ALL, border = 3)
-            boxMainSizer.Add(item = boxSizer, flag = flag, border = 3)
-
-            idx += 1
-            
-        middleSizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
-
-        #
-        # grid & legend options for all plots
-        #
-        self.wxId['grid'] = {}
-        self.wxId['legend'] = {}
-        self.wxId['font'] = {}
-        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
-                           label = " %s " % _("Grid and Legend settings"))
-        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
-
-        row = 0
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Grid color"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-        gridcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.properties['grid']['color'])
-        self.wxId['grid']['color'] = gridcolor.GetId()
-        gridSizer.Add(item = gridcolor, pos = (row, 1))
-
-        row +=1
-        gridshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show grid"))
-        gridshow.SetValue(self.properties['grid']['enabled'])
-        self.wxId['grid']['enabled'] = gridshow.GetId()
-        gridSizer.Add(item = gridshow, pos = (row, 0), span = (1, 2))
-
-        row +=1
-        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend font size"))
-        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
-        legendfontsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", 
-                                     size = (50, -1), style = wx.SP_ARROW_KEYS)
-        legendfontsize.SetRange(5,100)
-        legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
-        self.wxId['font']['legendSize'] = legendfontsize.GetId()
-        gridSizer.Add(item = legendfontsize, pos = (row, 1))
-
-        row += 1
-        legendshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show legend"))
-        legendshow.SetValue(self.properties['legend']['enabled'])
-        self.wxId['legend']['enabled'] = legendshow.GetId()
-        gridSizer.Add(item = legendshow, pos = (row, 0), span = (1, 2))
-
-        boxMainSizer.Add(item = gridSizer, flag = flag, border = 3)
-
-        middleSizer.Add(item = boxMainSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
-
-        sizer.Add(item = middleSizer, flag = wx.ALL, border = 0)
-        
-        #
-        # line & buttons
-        #
-        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
-        sizer.Add(item = line, proportion = 0,
-                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
-
-        #
-        # buttons
-        #
-        btnSave = wx.Button(self, wx.ID_SAVE)
-        btnApply = wx.Button(self, wx.ID_APPLY)
-        btnCancel = wx.Button(self, wx.ID_CANCEL)
-        btnSave.SetDefault()
-
-        # tooltips for buttons
-        btnApply.SetToolTipString(_("Apply changes for the current session"))
-        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
-        btnSave.SetDefault()
-        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
-
-        # sizers
-        btnStdSizer = wx.StdDialogButtonSizer()
-        btnStdSizer.AddButton(btnCancel)
-        btnStdSizer.AddButton(btnSave)
-        btnStdSizer.AddButton(btnApply)
-        btnStdSizer.Realize()
-        
-        sizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
-        #
-        # bindings for buttons and map plot settings controls
-        #
-        self.mapchoice.Bind(wx.EVT_CHOICE, self.OnSetMap)
-        
-        if self.plottype != 'scatter':
-            color.Bind(csel.EVT_COLOURSELECT, self.OnSetOpt)
-            width.Bind(wx.EVT_SPINCTRL, self.OnSetOpt)
-            style.Bind(wx.EVT_CHOICE, self.OnSetOpt)
-            legend.Bind(wx.EVT_TEXT, self.OnSetOpt)
-            
-        if self.plottype != 'histogram':
-            ptcolor.Bind(csel.EVT_COLOURSELECT, self.OnSetOpt)
-            ptsize.Bind(wx.EVT_SPINCTRL, self.OnSetOpt)
-            ptfill.Bind(wx.EVT_CHOICE, self.OnSetOpt)
-            ptlegend.Bind(wx.EVT_TEXT, self.OnSetOpt)
-            pttype.Bind(wx.EVT_CHOICE, self.OnSetOpt)
-            
-        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
-        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
-        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-
-        self.SetSizer(sizer)
-        sizer.Fit(self)
-
-    def OnSetMap(self, event):
-        """!Handler for changing map selection"""
-        idx = event.GetSelection()
-        self.map = self.rasterList[idx]
-        
-        # update settings controls for all plots
-        self.FindWindowById(self.wxId['pcolor']).SetColour(self.raster[self.map]['pcolor'])
-        self.FindWindowById(self.wxId['plegend']).SetValue(self.raster[self.map]['plegend'])
-
-        # update settings controls for histograms and profiles
-        if self.plottype != 'scatter':
-            self.FindWindowById(self.wxId['pwidth']).SetValue(self.raster[self.map]['pwidth'])
-            self.FindWindowById(self.wxId['pstyle']).SetStringSelection(self.raster[self.map]['pstyle'])
-
-        # update settings controls for scatterplots
-        elif self.plottype == 'scatter':
-            self.FindWindowById(self.wxId['psize']).SetValue(self.raster[self.map]['psize'])
-            self.FindWindowById(self.wxId['ptype']).SetStringSelection(self.raster[self.map]['ptype'])
-            self.FindWindowById(self.wxId['pfill']).SetStringSelection(self.raster[self.map]['pfill'])
-            
-        self.Refresh()
-        
-    def OnSetOpt(self, event):
-        """!Handler for changing any other option"""
-        self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
-        self.UpdateSettings()
-        self.parent.SetGraphStyle()
-        if self.parent.plot:
-            p = self.parent.CreatePlotList()
-            self.parent.DrawPlot(p)
-
-    def UpdateSettings(self):
-        """!Apply settings to each map and to entire plot"""
-        
-        # update plot settings for selected map
-        self.raster[self.map]['pcolor'] = self.FindWindowById(self.wxId['pcolor']).GetColour()
-        self.raster[self.map]['plegend'] = self.FindWindowById(self.wxId['plegend']).GetValue()
-        
-        if self.plottype != 'scatter':
-            self.raster[self.map]['pwidth'] = int(self.FindWindowById(self.wxId['pwidth']).GetValue())
-            self.raster[self.map]['pstyle'] = self.FindWindowById(self.wxId['pstyle']).GetStringSelection()
-            
-        elif self.plottype == 'scatter':
-            self.raster[self.map]['psize'] = self.FindWindowById(self.wxId['psize']).GetValue()
-            self.raster[self.map]['ptype'] = self.FindWindowById(self.wxId['ptype']).GetValue()
-            self.raster[self.map]['pfill'] = self.FindWindowById(self.wxId['pfill']).GetValue()
-
-        # update settings for entire plot
-        for axis in ('x-axis', 'y-axis'):
-            self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetStringSelection()
-            self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
-            self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
-            self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()
-
-        if self.plottype == 'profile':
-            self.properties['marker']['color'] = self.FindWindowById(self.wxId['marker']['color']).GetColour()
-            self.properties['marker']['fill'] = self.FindWindowById(self.wxId['marker']['fill']).GetStringSelection()
-            self.properties['marker']['size'] = self.FindWindowById(self.wxId['marker']['size']).GetValue()
-            self.properties['marker']['type'] = self.FindWindowById(self.wxId['marker']['type']).GetValue()
-            self.properties['marker']['legend'] = self.FindWindowById(self.wxId['marker']['legend']).GetValue()
-
-        self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
-        self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()
-
-        self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
-        self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()
-
-    def OnSave(self, event):
-        """!Button 'Save' pressed"""
-        self.OnApply(None)
-        fileSettings = {}
-        UserSettings.ReadSettingsFile(settings = fileSettings)
-        fileSettings[self.plottype] = UserSettings.Get(group = self.plottype)
-        file = UserSettings.SaveToFile(fileSettings)
-        self.parent.parent.GetLayerManager().goutput.WriteLog(_('Plot settings saved to file \'%s\'.') % file)
-        self.Close()
-
-    def OnApply(self, event):
-        """!Button 'Apply' pressed. Does not close dialog"""
-        self.UpdateSettings()
-        self.parent.SetGraphStyle()
-        if self.parent.plot:
-            p = self.parent.CreatePlotList()
-            self.parent.DrawPlot(p)
-        
-    def OnCancel(self, event):
-        """!Button 'Cancel' pressed"""
-        self.Close()
-     

Deleted: grass/trunk/gui/wxpython/gui_modules/wxvdigit.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxvdigit.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/wxvdigit.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1758 +0,0 @@
-"""!
- at package wxvdigit.py
-
- at brief wxGUI vector digitizer (base class)
-
-Code based on wxVdigit C++ component from GRASS 6.4.0
-(gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
-
-List of classes:
- - VDigitError
- - IVDigit
-
- at todo Read large amounts of data from Vlib into arrays, which could
-then be processed using NumPy and rendered using glDrawArrays or
-glDrawElements, so no per-line/per-vertex processing in Python. Bulk
-data processing with NumPy is much faster than iterating in Python
-(and NumPy would be an excellent candidate for acceleration via
-e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-from gcmd        import GError
-from debug       import Debug
-from preferences import globalSettings as UserSettings
-
-from wxvdriver   import DisplayDriver, GetLastError
-
-from grass.lib.gis    import *
-from grass.lib.vector import *
-from grass.lib.vedit  import *
-from grass.lib.dbmi   import *
-
-import grass.script.core as grass
-
-class VDigitError:
-    def __init__(self, parent):
-        """!Class for managing error messages of vector digitizer
-
-        @param parent parent window for dialogs
-        """
-        self.parent  = parent
-        self.caption = _('Digitization Error')
-    
-    def NoMap(self, name = None):
-        """!No map for editing"""
-        if name:
-            message = _('Unable to open vector map <%s>.') % name
-        else:
-            message =  _('No vector map open for editing.')
-        GError(message + ' ' + _('Operation cancelled.'),
-               parent  = self.parent,
-               caption = self.caption)
-
-    def WriteLine(self):
-        """!Writing line failed
-        """
-        GError(message = _('Writing new feature failed. '
-                           'Operation cancelled.\n\n'
-                           'Reason: %s') % GetLastError(),
-               parent  = self.parent,
-               caption = self.caption)
-
-    def ReadLine(self, line):
-        """!Reading line failed
-        """
-        GError(message = _('Reading feature id %d failed. '
-                           'Operation cancelled.') % line,
-               parent  = self.parent,
-               caption = self.caption)
-
-    def DbLink(self, dblink):
-        """!No dblink available
-        """
-        GError(message = _('Database link %d not available. '
-                           'Operation cancelled.') % dblink,
-               parent  = self.parent,
-               caption = self.caption)
-
-    def Driver(self, driver):
-        """!Staring driver failed
-        """
-        GError(message = _('Unable to start database driver <%s>. '
-                           'Operation cancelled.') % driver,
-               parent  = self.parent,
-               caption = self.caption)
-
-    def Database(self, driver, database):
-        """!Opening database failed
-        """
-        GError(message = _('Unable to open database <%(db)s> by driver <%(driver)s>. '
-                           'Operation cancelled.') % { 'db' : database, 'driver' : driver},
-               parent  = self.parent,
-               caption = self.caption)
-
-    def DbExecute(self, sql):
-        """!Sql query failed
-        """
-        GError(message = _("Unable to execute SQL query '%s'. "
-                           "Operation cancelled.") % sql,
-               parent  = self.parent,
-               caption = self.caption)
-
-    def DeadLine(self, line):
-        """!Dead line
-        """
-        GError(message = _("Feature id %d is marked as dead. "
-                           "Operation cancelled.") % line,
-               parent  = self.parent,
-               caption = self.caption)
-
-    def FeatureType(self, ftype):
-        """!Unknown feature type
-        """
-        GError(message = _("Unsupported feature type %d. "
-                           "Operation cancelled.") % ftype,
-               parent  = self.parent,
-               caption = self.caption)
-        
-class IVDigit:
-    def __init__(self, mapwindow):
-        """!Base class for vector digitizer (ctypes interface)
-        
-        @parem mapwindow reference for map window (BufferedWindow)
-        """
-        self.poMapInfo   = None      # pointer to Map_info
-        self.mapWindow = mapwindow
-
-        # background map
-        self.bgMapInfo   = Map_info()
-        self.poBgMapInfo = self.popoBgMapInfo = None
-        
-        if not mapwindow.parent.IsStandalone():
-            goutput = mapwindow.parent.GetLayerManager().GetLogWindow()
-            log = goutput.GetLog(err = True)
-            progress = goutput.GetProgressBar()
-        else:
-            log = sys.stderr
-            progress = None
-        
-        self.toolbar = mapwindow.parent.toolbars['vdigit']
-        
-        self._error   = VDigitError(parent = self.mapWindow)
-        
-        self._display = DisplayDriver(device    = mapwindow.pdcVector,
-                                      deviceTmp = mapwindow.pdcTmp,
-                                      mapObj    = mapwindow.Map,
-                                      window    = mapwindow,
-                                      glog      = log,
-                                      gprogress = progress)
-        
-        # GRASS lib
-        self.poPoints = Vect_new_line_struct()
-        self.poCats   = Vect_new_cats_struct()
-        
-        # self.SetCategory()
-        
-        # layer / max category
-        self.cats = dict()
-        
-        self._settings = dict()
-        self.UpdateSettings() # -> self._settings
-        
-        # undo/redo
-        self.changesets = dict()
-        self.changesetCurrent = -1 # first changeset to apply
-        self.changesetEnd     = -1 # last changeset to be applied
-        
-        if self.poMapInfo:
-            self.InitCats()
-        
-    def __del__(self):
-        Debug.msg(1, "IVDigit.__del__()")
-        Vect_destroy_line_struct(self.poPoints)
-        self.poPoints = None
-        Vect_destroy_cats_struct(self.poCats)
-        self.poCats = None
-        
-        if self.poBgMapInfo:
-            Vect_close(self.poBgMapInfo)
-            self.poBgMapInfo = self.popoBgMapInfo = None
-            del self.bgMapInfo
-        
-    def CloseBackgroundMap(self):
-        """!Close background vector map"""
-        if not self.poBgMapInfo:
-            return
-        
-        Vect_close(self.poBgMapInfo)
-        self.poBgMapInfo = self.popoBgMapInfo = None
-        
-    def OpenBackgroundMap(self, bgmap):
-        """!Open background vector map
-
-        @todo support more background maps then only one
-        
-        @param bgmap name of vector map to be opened
-
-        @return pointer to map_info
-        @return None on error
-        """
-        name   = create_string_buffer(GNAME_MAX)
-        mapset = create_string_buffer(GMAPSET_MAX)
-        if not G_name_is_fully_qualified(bgmap, name, mapset):
-            name   = str(bgmap)
-            mapset = str(G_find_vector2(bgmap, ''))
-        else:
-            name   = str(name.value)
-            mapset = str(mapset.value)
-        
-        if (name == Vect_get_name(self.poMapInfo) and \
-                mapset == Vect_get_mapset(self.poMapInfo)):
-            self.poBgMapInfo = self.popoBgMapInfo = None
-            self._error.NoMap(bgmap)
-            return
-        
-        self.poBgMapInfo = pointer(self.bgMapInfo)
-        self.popoBgMapInfo = pointer(self.poBgMapInfo)
-	if Vect_open_old(self.poBgMapInfo, name, mapset) == -1:
-            self.poBgMapInfo = self.popoBgMapInfo = None
-            self._error.NoMap(bgmap)
-            return
-        
-    def _getSnapMode(self):
-        """!Get snapping mode
-
-         - snap to vertex
-         - snap to nodes
-         - no snapping
-        
-        @return snap mode
-        """
-        threshold = self._display.GetThreshold()
-        if threshold > 0.0:
-            if UserSettings.Get(group = 'vdigit', key = 'snapToVertex', subkey = 'enabled'):
-                return SNAPVERTEX
-            else:
-                return SNAP
-        else:
-            return NO_SNAP
-    
-    def _breakLineAtIntersection(self, line, pointsLine, changeset):
-        """!Break given line at intersection
-
-        \param line line id
-        \param pointsLine line geometry
-        \param changeset id
-  
-        \return number of modified lines
-        """
-        if not self._checkMap():
-            return -1
-        
-        if not Vect_line_alive(self.poMapInfo, line):
-            return 0
-        
-        if not pointsLine:
-            if Vect_read_line(self.poMapInfo, self.poPoints, None, line) < 0:
-                self._error.ReadLine(line)
-                return -1
-            points = self.poPoints
-        else:
-            points = pointsLine
-        
-        listLine  = Vect_new_boxlist(0)
-        listRef   = Vect_new_list()
-        listBreak = Vect_new_list()
-    
-        pointsCheck = Vect_new_line_struct()
-    
-        lineBox = bound_box()
-        # find all relevant lines
-        Vect_get_line_box(self.poMapInfo, line, byref(lineBox))
-        Vect_select_lines_by_box(self.poMapInfo, byref(lineBox),
-                                 GV_LINES, listLine)
-    
-        # check for intersection
-        Vect_list_append(listBreak, line)
-        Vect_list_append(listRef, line)
-        for i in range(listLine.contents.n_values):
-            lineBreak = listLine.contents.id[i]
-            if lineBreak == line:
-		continue
-            
-            ltype = Vect_read_line(self.poMapInfo, pointsCheck, None, lineBreak)
-            if not (ltype & GV_LINES):
-                continue
-            
-            if Vect_line_check_intersection(self.poPoints, pointsCheck,
-                                            WITHOUT_Z):
-                Vect_list_append(listBreak, lineBreak)
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        for i in range(listBreak.contents.n_values):
-            self._addActionToChangeset(changeset, listBreak.contents.value[i], add = False)
-        
-        ret = Vect_break_lines_list(self.poMapInfo, listBreak, listRef,
-                                    GV_LINES, None)
-        
-        for i in range(listBreak.contents.n_values):
-            if Vect_line_alive(self.poMapInfo, listBreak.contents.value[i]):
-                self._removeActionFromChangeset(changeset, listBreak.contents.value[i],
-                                                add = False)
-        
-        for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo) + 1):
-            self._addActionToChangeset(changeset, line, add = True)
-        
-        Vect_destroy_line_struct(pointsCheck)
-
-        Vect_destroy_boxlist(listLine)
-        Vect_destroy_list(listBreak)
-        Vect_destroy_list(listRef)
-        
-        return ret
-    
-    def _addActionsBefore(self):
-        """!Register action before operation
-  
-        @return changeset id
-        """
-        changeset = len(self.changesets)
-        for line in self._display.selected['ids']:
-            if Vect_line_alive(self.poMapInfo, line):
-                self._addActionToChangeset(changeset, line, add = False)
-        
-        return changeset
-
-    def _applyChangeset(self, changeset, undo):
-        """!Apply changeset (undo/redo changeset)
-        
-        @param changeset changeset id
-        @param undo True for undo otherwise redo
-
-        @return 1 changeset applied
-        @return 0 changeset not applied
-        @return -1 on error
-        """
-        if changeset < 0 or changeset > len(self.changesets.keys()):
-            return -1
-        
-        if self.changesetEnd < 0:
-            self.changesetEnd = changeset
-            
-        ret = 0
-        actions = self.changesets[changeset]
-        for action in actions: 
-            add = action['add']
-            line = action['line']
-            if (undo and add) or \
-                    (not undo and not add):
-                if Vect_line_alive(self.poMapInfo, line):
-                    Debug.msg(3, "IVDigit._applyChangeset(): changeset=%d, action=add, line=%d -> deleted",
-                              changeset, line)
-                    Vect_delete_line(self.poMapInfo, line)
-                    ret = 1
-                else:
-                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
-                              changeset, line)
-            else: # delete
-                offset = action['offset']
-                if not Vect_line_alive(self.poMapInfo, line):
-                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
-                              changeset, line)
-                    if Vect_restore_line(self.poMapInfo, line, offset) < 0:
-                        return -1
-                    ret = 1
-                else:
-                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
-                              changeset, line)
-        
-        return ret
-    
-    def _addActionsAfter(self, changeset, nlines):
-        """!Register action after operation
-
-        @param changeset changeset id
-        @param nline number of lines
-        """
-        for line in self._display.selected['ids']:
-            if Vect_line_alive(self.poMapInfo, line):
-                self._removeActionFromChangeset(changeset, line, add = False)
-        
-        for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo)):
-            if Vect_line_alive(self.poMapInfo, line):
-                self._addActionToChangeset(changeset, line, add = True)
-        
-    def _addActionToChangeset(self, changeset, line, add):
-        """!Add action to changeset
-        
-        @param changeset id of changeset
-        @param line feature id
-        @param add True to add, otherwise delete
-        """
-        if not self._checkMap():
-            return 
-        
-        if not Vect_line_alive(self.poMapInfo, line):
-            return
-        
-        offset = Vect_get_line_offset(self.poMapInfo, line)
-        
-        if changeset not in self.changesets:
-            self.changesets[changeset] = list()
-            self.changesetCurrent = changeset
-        
-        self.changesets[changeset].append({ 'add'    : add,
-                                            'line'   : line,
-                                            'offset' : offset })
-        
-        Debug.msg(3, "IVDigit._addActionToChangeset(): changeset=%d, add=%d, line=%d, offset=%d",
-                  changeset, add, line, offset)
-        
-    def _removeActionFromChangeset(self, changeset, line, add):
-        """!Remove action from changeset
-        
-        @param changeset changeset id
-        @param line line id
-        @param add True for add, False for delete
-        
-        @return number of actions in changeset
-        @return -1 on error
-        """
-        if changeset not in self.changesets.keys():
-            return -1
-        
-        alist = self.changesets[changeset] 
-        for action in alist:
-            if action['add'] == add and action['line'] == line:
-                alist.remove(action)
-        
-        return len(alist)
-
-    def AddFeature(self, ftype, points):
-        """!Add new feature
-        
-        @param ftype feature type (point, line, centroid, boundary)
-        @param points tuple of points ((x, y), (x, y), ...)
-        
-        @return tuple (number of added features, feature ids)
-        """
-        if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') == 2:
-            layer = -1 # -> no category
-            cat   = -1
-        else:
-            layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
-            cat   = self.SetCategory()
-        
-        if ftype == 'point':
-            vtype = GV_POINT
-        elif ftype == 'line':
-            vtype = GV_LINE
-        elif ftype == 'centroid':
-            vtype = GV_CENTROID
-        elif ftype == 'boundary':
-            vtype = GV_BOUNDARY
-        elif ftype == 'area':
-            vtype = GV_AREA
-        else:
-            GError(parent = self.mapWindow,
-                   message = _("Unknown feature type '%s'") % ftype)
-            return (-1, None)
-        
-        if vtype & GV_LINES and len(points) < 2:
-            GError(parent = self.mapWindow,
-                   message = _("Not enough points for line"))
-            return (-1, None)
-        
-        self.toolbar.EnableUndo()
-        
-        return self._addFeature(vtype, points, layer, cat,
-                                self._getSnapMode(), self._display.GetThreshold())
-    
-    def DeleteSelectedLines(self):
-        """!Delete selected features
-
-        @return number of deleted features
-        """
-        deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
-        if not self._checkMap():
-            return -1
-        
-        n_dblinks = Vect_get_num_dblinks(self.poMapInfo)
-        Cats_del = None
-        
-        # collect categories for delete if requested
-        if deleteRec:
-            poCats    = Vect_new_cats_struct()
-            poCatsDel = Vect_new_cats_struct()
-            for i in self._display.selected['ids']:
-                if Vect_read_line(self.poMapInfo, None, poCats, i) < 0:
-                    Vect_destroy_cats_struct(poCatsDel)
-                    self._error.ReadLine(i)
-                    return -1
-                
-                cats = poCats.contents
-                for j in range(cats.n_cats):
-                    Vect_cat_set(poCatsDel, cats.field[j], cats.cat[j])
-            
-            Vect_destroy_cats_struct(poCats)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        nlines = Vedit_delete_lines(self.poMapInfo, poList)
-        Vect_destroy_list(poList)
-        self._display.selected['ids'] = list()
-        
-        if nlines > 0 and deleteRec:
-            handle  = dbHandle()
-            poHandle = pointer(handle)
-            stmt    = dbString()
-            poStmt   = pointer(stmt)
-            
-            for dblink in range(n_dblinks):
-                poFi = Vect_get_dblink(self.poMapInfo, dblink)
-                if poFi is None:
-                    self._error.DbLink(dblink)
-                    return -1
-                
-                Fi = poFi.contents
-                poDriver = db_start_driver(Fi.driver)
-                if poDriver is None:
-                    self._error.Driver(Fi.driver)
-                    return -1
-                
-                db_init_handle(poHandle)
-                db_set_handle(poHandle, Fi.database, None)
-                if db_open_database(poDriver, poHandle) != DB_OK:
-                    self._error.Database(Fi.driver, Fi.database)
-                    return -1
-                
-                db_init_string(poStmt)
-                db_set_string(poStmt, "DELETE FROM %s WHERE" % Fi.table)
-                n_cats = 0;
-                catsDel = poCatsDel.contents
-                for c in range(catsDel.n_cats):
-                    if catsDel.field[c] == Fi.number:
-                        if n_cats > 0:
-                            db_append_string(poStmt, " or")
-                    
-		    db_append_string(poStmt, " %s = %d" % (Fi.key, catsDel.cat[c]))
-		    n_cats += 1
-                
-                Vect_cat_del(poCatsDel, Fi.number)
-                
-                if n_cats and \
-                        db_execute_immediate(poDriver, poStmt) != DB_OK:
-                    self._error.DbExecute(db_get_string(poStmt))
-                    return -1
-                
-                db_close_database(poDriver)
-                db_shutdown_driver(poDriver)
-        
-        if poCatsDel:
-            Vect_destroy_cats_struct(poCatsDel)
-        
-        if nlines > 0:
-            self.toolbar.EnableUndo()
-        
-        return nlines
-
-    def MoveSelectedLines(self, move):
-        """!Move selected features
-
-        @param move direction (x, y)
-        """
-        if not self._checkMap():
-            return -1
-        
-        thresh = self._display.GetThreshold()
-        snap   = self._getSnapMode()
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
-                                  poList,
-                                  move[0], move[1], 0,
-                                  snap, thresh)
-        Vect_destroy_list(poList)
-        
-        if nlines > 0:
-            self._addActionsAfter(changeset, nlines)
-        else:
-            del self.changesets[changeset]
-        
-        if nlines > 0 and self._settings['breakLines']:
-            for i in range(1, nlines):
-                self._breakLineAtIntersection(nlines + i, None, changeset)
-        
-        if nlines > 0:
-            self.toolbar.EnableUndo()
-        
-        return nlines
-
-    def MoveSelectedVertex(self, point, move):
-        """!Move selected vertex of the line
-
-        @param point location point
-        @param move  x,y direction
-        
-        @return id of new feature
-        @return 0 vertex not moved (not found, line is not selected)
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        if len(self._display.selected['ids']) != 1:
-            return -1
-        
-        Vect_reset_line(self.poPoints)
-        Vect_append_point(self.poPoints, point[0], point[1], 0.0)
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        
-        # move only first found vertex in bbox 
-        poList = self._display.GetSelectedIList()
-        moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
-                                  poList, self.poPoints,
-                                  self._display.GetThreshold(type = 'selectThresh'),
-                                  self._display.GetThreshold(),
-                                  move[0], move[1], 0.0,
-                                  1, self._getSnapMode())
-        Vect_destroy_list(poList)
-        
-        if moved > 0:
-            self._addActionsAfter(changeset, nlines)
-        else:
-            del self.changesets[changeset]
-        
-        if moved > 0 and self._settings['breakLines']:
-            self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                          None, changeset)
-        
-        if moved > 0:
-            self.toolbar.EnableUndo()
-        
-        return moved
-
-    def AddVertex(self, coords):
-        """!Add new vertex to the selected line/boundary on position 'coords'
-
-        @param coords coordinates to add vertex
-
-        @return id of new feature
-        @return 0 nothing changed
-        @return -1 on failure
-        """
-        added = self._ModifyLineVertex(coords, add = True)
-        
-        if added > 0:
-            self.toolbar.EnableUndo()
-
-        return added
-
-    def RemoveVertex(self, coords):
-        """!Remove vertex from the selected line/boundary on position 'coords'
-
-        @param coords coordinates to remove vertex
-
-        @return id of new feature
-        @return 0 nothing changed
-        @return -1 on failure
-        """
-        deleted = self._ModifyLineVertex(coords, add = False)
-        
-        if deleted > 0:
-            self.toolbar.EnableUndo()
-
-        return deleted
-
-
-    def SplitLine(self, point):
-        """!Split/break selected line/boundary on given position
-
-        @param point point where to split line
-        
-        @return 1 line modified
-        @return 0 nothing changed
-        @return -1 error
-        """
-        thresh = self._display.GetThreshold('selectThresh')
-        if not self._checkMap():
-            return -1
-        
-        poList  = self._display.GetSelectedIList()
-        Vect_reset_line(self.poPoints)
-        Vect_append_point(self.poPoints, point[0], point[1], 0.0)
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        
-        ret = Vedit_split_lines(self.poMapInfo, poList,
-                                self.poPoints, thresh, None)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        return ret
-
-    def EditLine(self, line, coords):
-        """!Edit existing line/boundary
-
-        @param line feature id to be modified
-        @param coords list of coordinates of modified line
-
-        @return feature id of new line
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        if len(coords) < 2:
-            self.DeleteSelectedLines()
-            return 0
-        
-        if not Vect_line_alive(self.poMapInfo, line):
-            self._error.DeadLine(line)
-            return -1
-        
-        # read original feature
-        ltype = Vect_read_line(self.poMapInfo, None, self.poCats, line)
-        if ltype < 0:
-            self._error.ReadLine(line)
-            return -1
-        
-        # build feature geometry
-        Vect_reset_line(self.poPoints)
-        for p in coords:
-            Vect_append_point(self.poPoints, p[0], p[1], 0.0)
-
-        # apply snapping (node or vertex)
-        snap = self._getSnapMode()
-        if snap != NO_SNAP:
-            modeSnap = not (snap == SNAP)
-            Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo,
-                            int(self.poBgMapInfo is not None),
-                           -1, self.poPoints, self._display.GetThreshold(), modeSnap)
-
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
-                                    self.poPoints, self.poCats)
-        if newline > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        if newline > 0 and self._settings['breakLines']:
-            self._breakLineAtIntersection(newline, None, changeset)
-        
-        return newline
-
-    def FlipLine(self):
-        """!Flip selected lines/boundaries
-
-        @return number of modified lines
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vedit_flip_lines(self.poMapInfo, poList)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        return ret
-
-    def MergeLine(self):
-        """!Merge selected lines/boundaries
-
-        @return number of modified lines
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vedit_merge_lines(self.poMapInfo, poList)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-                
-        return ret
-
-    def BreakLine(self):
-        """!Break selected lines/boundaries
-
-        @return number of modified lines
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vect_break_lines_list(self.poMapInfo, poList, None,
-                                    GV_LINES, None)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-                
-        return ret
-
-    def SnapLine(self):
-        """!Snap selected lines/boundaries
-
-        @return on success
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        Vect_snap_lines_list(self.poMapInfo, poList,
-                             self._display.GetThreshold(), None)
-        Vect_destroy_list(poList)
-        
-        if nlines < Vect_get_num_lines(self.poMapInfo):
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-    def ConnectLine(self):
-        """!Connect selected lines/boundaries
-
-        @return 1 lines connected
-        @return 0 lines not connected
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vedit_connect_lines(self.poMapInfo, poList,
-                                  self._display.GetThreshold())
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        return ret
-        
-    def CopyLine(self, ids = []):
-        """!Copy features from (background) vector map
-
-        @param ids list of line ids to be copied
-
-        @return number of copied features
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        poList = self._display.GetSelectedIList(ids)
-        ret = Vedit_copy_lines(self.poMapInfo, self.poBgMapInfo,
-                               poList)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            changeset = len(self.changesets)
-            for line in (range(nlines + 1, Vect_get_num_lines(self.poMapInfo))):
-                self._addActionToChangeset(changeset, line, add = True)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-
-        if ret > 0 and self.poBgMapInfo and self._settings['breakLines']:
-            for i in range(1, ret):
-                self._breakLineAtIntersection(nlines + i, None, changeset)
-        
-        return ret
-
-    def CopyCats(self, fromId, toId, copyAttrb = False):
-        """!Copy given categories to objects with id listed in ids
-
-        @param cats ids of 'from' feature
-        @param ids  ids of 'to' feature(s)
-
-        @return number of modified features
-        @return -1 on error
-        """
-        if len(fromId) < 1 or len(toId) < 1:
-            return 0
-        
-        poCatsFrom = self.poCats
-        poCatsTo = Vect_new_cats_struct();
-        
-        nlines = 0
-        
-        for fline in fromId:
-            if not Vect_line_alive(self.poMapInfo, fline):
-                continue
-            
-            if Vect_read_line(self.poMapInfo, None, poCatsFrom, fline) < 0:
-                self._error.ReadLine(fline)
-                return -1
-            
-            for tline in toId:
-                if not Vect_line_alive(self.poMapInfo, tline):
-                    continue
-                
-                ltype = Vect_read_line(self.poMapInfo, self.poPoints, poCatsTo, tline)
-                if ltype < 0:
-                    self._error.ReadLine(fline)
-                    return -1
-                
-                catsFrom = poCatsFrom.contents
-                for i in range(catsFrom.n_cats):
-                    if not copyAttrb:
-                        # duplicate category
-                        cat = catsFrom.cat[i]
-                    else:
-                        # duplicate attributes
-                        cat = self.cats[catsFrom.field[i]] + 1
-                        self.cats[catsFrom.field[i]] = cat
-                        poFi = Vect_get_field(self.poMapInfo, catsFrom.field[i])
-                        if not poFi:
-                            self._error.DbLink(i)
-                            return -1
-                        
-                        fi = poFi.contents
-                        driver = db_start_driver(fi.driver)
-                        if not driver:
-                            self._error.Driver(fi.driver)
-                            return -1
-                        
-                        handle = dbHandle()
-                        db_init_handle(byref(handle))
-                        db_set_handle(byref(handle), fi.database, None)
-                        if db_open_database(driver, byref(handle)) != DB_OK:
-                            db_shutdown_driver(driver)
-                            self._error.Database(fi.driver, fi.database)
-                            return -1
-                        
-                        stmt = dbString()
-                        db_init_string(byref(stmt))
-                        db_set_string(byref(stmt),
-                                      "SELECT * FROM %s WHERE %s=%d" % (fi.table, fi.key,
-                                                                        catsFrom.cat[i]))
-                        
-                        cursor = dbCursor()
-                        if db_open_select_cursor(driver, byref(stmt), byref(cursor),
-                                                 DB_SEQUENTIAL) != DB_OK:
-                                db_close_database_shutdown_driver(driver)
-                                return -1
-                        
-                        table = db_get_cursor_table(byref(cursor))
-                        ncols = db_get_table_number_of_columns(table)
-                        
-                        sql = "INSERT INTO %s VALUES (" % fi.table
-                        # fetch the data
-                        more = c_int()
-                        while True:
-                            if db_fetch(byref(cursor), DB_NEXT, byref(more)) != DB_OK:
-                                db_close_database_shutdown_driver(driver)
-                                return -1
-                            if not more.value:
-                                break
-                            
-                            value_string = dbString()
-                            for col in range(ncols):
-                                if col > 0:
-                                    sql += ","
-                                    
-                                column = db_get_table_column(table, col)
-                                if db_get_column_name(column) == fi.key:
-                                    sql += "%d" % cat
-                                    continue
-                                
-                                value = db_get_column_value(column)
-                                db_convert_column_value_to_string(column, byref(value_string))
-                                if db_test_value_isnull(value):
-                                    sql += "NULL"
-                                else:
-                                    ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column))
-                                    if ctype != DB_C_TYPE_STRING:
-                                        sql += db_get_string(byref(value_string))
-                                    else:
-                                        sql += "'%s'" % db_get_string(byref(value_string))
-                        
-                        sql += ")"
-                        db_set_string(byref(stmt), sql)
-                        if db_execute_immediate(driver, byref(stmt)) != DB_OK:
-                            db_close_database_shutdown_driver(driver)
-                            return -1
-                        
-                        db_close_database_shutdown_driver(driver)
-                        G_free(poFi)
-                
-                if Vect_cat_set(poCatsTo, catsFrom.field[i], cat) < 1:
-                    continue
-                
-                if Vect_rewrite_line(self.poMapInfo, tline, ltype, self.poPoints, poCatsTo) < 0:
-                    self._error.WriteLine()
-                    return -1
-                
-                nlines +=1
-        
-        Vect_destroy_cats_struct(poCatsTo)
-        
-        if nlines > 0:
-            self.toolbar.EnableUndo()
-        
-        return nlines
-
-    def _selectLinesByQueryThresh(self):
-        """!Generic method used for SelectLinesByQuery() -- to get
-        threshold value"""
-        thresh = 0.0
-        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
-            thresh = UserSettings.Get(group = 'vdigit', key = 'queryLength', subkey = 'thresh')
-            if UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection') == 0:
-                thresh = -1 * thresh
-        else:
-            thresh = UserSettings.Get(group = 'vdigit', key = 'queryDangle', subkey = 'thresh')
-            if UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection') == 0:
-                thresh = -1 * thresh
-        
-        return thresh
-
-    def SelectLinesByQuery(self, bbox):
-        """!Select features by query
-        
-        @todo layer / 3D
-        
-        @param bbox bounding box definition
-        """
-        if not self._checkMap():
-            return -1
-        
-        thresh = self._selectLinesByQueryThresh()
-        
-        query = QUERY_UNKNOWN
-        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
-            query = QUERY_LENGTH
-        else:
-            query = QUERY_DANGLE
-        
-        ftype = GV_POINTS | GV_LINES # TODO: 3D
-        layer = 1 # TODO
-        
-        ids = list()
-        poList = Vect_new_list()
-        coList = poList.contents
-        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'box'):
-            Vect_reset_line(self.poPoints)
-            x1, y1 = bbox[0]
-            x2, y2 = bbox[1]
-            z1 = z2 = 0.0
-            
-            Vect_append_point(self.poPoints, x1, y1, z1)
-            Vect_append_point(self.poPoints, x2, y1, z2)
-            Vect_append_point(self.poPoints, x2, y2, z1)
-            Vect_append_point(self.poPoints, x1, y2, z2)
-            Vect_append_point(self.poPoints, x1, y1, z1)
-	
-            Vect_select_lines_by_polygon(self.poMapInfo, self.poPoints, 0, None,
-                                         ftype, poList)
-            
-            if coList.n_values == 0:
-                return ids
-        
-        Vedit_select_by_query(self.poMapInfo,
-                              ftype, layer, thresh, query,
-                              poList)
-        
-        for i in range(coList.n_values):
-            ids.append(int(coList.value[i]))
-            
-        Debug.msg(3, "IVDigit.SelectLinesByQuery(): lines=%d", coList.n_values)    
-        Vect_destroy_list(poList)
-        
-        return ids
-
-    def IsVector3D(self):
-        """!Check if open vector map is 3D
-        """
-        if not self._checkMap():
-            return False
-        
-        return Vect_is_3d(self.poMapInfo)
-    
-    def GetLineLength(self, line):
-        """!Get line length
-
-        @param line feature id
-
-        @return line length
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        if not Vect_line_alive(self.poMapInfo, line):
-            return -1
-    
-        ltype = Vect_read_line(self.poMapInfo, self.poPoints, None, line)
-        if ltype < 0:
-            self._error.ReadLine(line)
-            return ret
-        
-        length = -1
-        if ltype & GV_LINES: # lines & boundaries
-            length = Vect_line_length(self.poPoints)
-        
-        return length
-
-    def GetAreaSize(self, centroid):
-        """!Get area size
-
-        @param centroid centroid id
-
-        @return area size
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
-        if ltype < 0:
-            self._error.ReadLine(line)
-            return ret
-        
-        if ltype != GV_CENTROID:
-            return -1
-        
-        area = Vect_get_centroid_area(self.poMapInfo, centroid)
-        size = -1
-        if area > 0:
-            if not Vect_area_alive(self.poMapInfo, area):
-                return size
-            
-            size = Vect_get_area_area(self.poMapInfo, area)
-        
-        return size
-        
-    def GetAreaPerimeter(self, centroid):
-        """!Get area perimeter
-        
-        @param centroid centroid id
-        
-        @return area size
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
-        if ltype < 0:
-            self._error.ReadLine(line)
-            return ret
-        
-        if ltype != GV_CENTROID:
-            return -1
-        
-        area = Vect_get_centroid_area(self.poMapInfo, centroid)
-        perimeter = -1
-        if area > 0:
-            if not Vect_area_alive(self.poMapInfo, area):
-                return -1
-            
-            Vect_get_area_points(self.poMapInfo, area, self.poPoints)
-            perimeter = Vect_area_perimeter(self.poPoints)
-        
-        return perimeter
-    
-    def SetLineCats(self, line, layer, cats, add = True):
-        """!Set categories for given line and layer
-
-        @param line feature id
-        @param layer layer number (-1 for first selected line)
-        @param cats list of categories
-        @param add if True to add, otherwise do delete categories
-
-        @return new feature id (feature need to be rewritten)
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        if line < 1 and len(self._display.selected['ids']) < 1:
-            return -1
-        
-        update = False
-        if line == -1:
-            update = True
-            line = self._display.selected['ids'][0]
-	
-        if not Vect_line_alive(self.poMapInfo, line):
-            return -1
-        
-        ltype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
-        if ltype < 0:
-            self._error.ReadLine(line)
-            return -1
-        
-        for c in cats:
-            if add:
-                Vect_cat_set(self.poCats, layer, c)
-            else:
-                Vect_field_cat_del(self.poCats, layer, c)
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        changeset = self._addActionsBefore()
-        newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
-                                    self.poPoints, self.poCats)
-        
-        if newline > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        
-        if update:
-            # update line id since the line was rewritten
-            self._display.selected['ids'][0] =  newline
-        
-        return newline
-
-    def TypeConvForSelectedLines(self):
-        """!Feature type conversion for selected objects.
-
-        Supported conversions:
-         - point <-> centroid
-         - line <-> boundary
-
-        @return number of modified features
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vedit_chtype_lines(self.poMapInfo, poList)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        return ret
-
-    def Undo(self, level = -1):
-        """!Undo action
-
-        @param level levels to undo (0 to revert all)
-
-        @return id of current changeset
-        """
-        changesetLast = len(self.changesets.keys()) - 1
-
-        if changesetLast < 0:
-            return changesetLast
-        
-        if self.changesetCurrent == -2: # value uninitialized 
-            self.changesetCurrent = changesetLast
-            
-        if level > 0 and self.changesetCurrent < 0:
-            self.changesetCurrent = 0
-        
-        if level == 0:
-            # 0 -> undo all
-            level = -1 * changesetLast + 1
-
-        Debug.msg(2, "Digit.Undo(): changeset_last=%d, changeset_current=%d, level=%d",
-                  changesetLast, self.changesetCurrent, level)
-    
-        if level < 0: # undo
-            if self.changesetCurrent + level < -1:
-                return changesetCurrent;
-            for changeset in range(self.changesetCurrent, self.changesetCurrent + level, -1):
-                self._applyChangeset(changeset, undo = True)
-        elif level > 0: # redo 
-            if self.changesetCurrent + level > len(self.changesets.keys()):
-                return self.changesetCurrent
-            for changeset in range(self.changesetCurrent, self.changesetCurrent + level):
-                self._applyChangeset(changeset, undo = False)
-        
-        self.changesetCurrent += level
-
-        Debug.msg(2, "Digit.Undo(): changeset_current=%d, changeset_last=%d, changeset_end=%d",
-                  self.changesetCurrent, changesetLast, self.changesetEnd)
-        
-        if self.changesetCurrent == self.changesetEnd:
-            self.changesetEnd = changesetLast
-            return -1
-        
-        self.mapWindow.UpdateMap(render = False)
-        
-        if self.changesetCurrent < 0: # disable undo tool
-            self.toolbar.EnableUndo(False)
-
-    def ZBulkLines(self, pos1, pos2, start, step):
-        """!Z-bulk labeling
-
-        @param pos1 reference line (start point)
-        @param pos1 reference line (end point)
-        @param start starting value
-        @param step step value
-
-        @return number of modified lines
-        @return -1 on error
-        """
-        if not self._checkMap():
-            return -1
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        
-        # register changeset
-        changeset = self._addActionsBefore()
-        
-        poList = self._display.GetSelectedIList()
-        ret = Vedit_bulk_labeling(self.poMapInfo, poList,
-                                  pos1[0], pos1[1], pos2[0], pos2[1],
-                                  start, step)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-            self.toolbar.EnableUndo()
-        else:
-            del self.changesets[changeset]
-        
-        return ret
-    
-    def GetDisplay(self):
-        """!Get display driver instance"""
-        return self._display
-    
-    def OpenMap(self, name):
-        """!Open vector map for editing
-        
-        @param map name of vector map to be set up
-        """
-        Debug.msg (3, "AbstractDigit.SetMapName map=%s" % name)
-
-        if '@' in name:
-            name, mapset = name.split('@')
-        else:
-            mapset = grass.gisenv()['MAPSET']
-        
-        self.poMapInfo = self._display.OpenMap(str(name), str(mapset), True)
-        
-        if self.poMapInfo:
-            self.InitCats()
-        
-        return self.poMapInfo
-    
-    def CloseMap(self):
-        """!Close currently open vector map
-        """
-        if not self._checkMap():
-            return
-        
-        self._display.CloseMap()
-
-    def InitCats(self):
-        """!Initialize categories information
-        
-        @return 0 on success
-        @return -1 on error
-        """
-        self.cats.clear()
-        if not self._checkMap():
-            return -1
-        
-        ndblinks = Vect_get_num_dblinks(self.poMapInfo)
-        for i in range(ndblinks):
-            fi = Vect_get_dblink(self.poMapInfo, i).contents
-            if fi:
-                self.cats[fi.number] = None
-        
-        # find max category
-        nfields = Vect_cidx_get_num_fields(self.poMapInfo)
-        Debug.msg(2, "wxDigit.InitCats(): nfields=%d", nfields)
-        
-        for i in range(nfields):
-            field = Vect_cidx_get_field_number(self.poMapInfo, i)
-            ncats = Vect_cidx_get_num_cats_by_index(self.poMapInfo, i)
-            if field <= 0:
-                continue
-            for j in range(ncats):
-                cat = c_int()
-                type = c_int()
-                id = c_int()
-                Vect_cidx_get_cat_by_index(self.poMapInfo, i, j,
-                                           byref(cat), byref(type), byref(id))
-                if field in self.cats:
-                    if cat > self.cats[field]:
-                        self.cats[field] = cat.value
-                else:
-                    self.cats[field] = cat.value
-            Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
-            
-        # set default values
-        for field, cat in self.cats.iteritems():
-            if cat == None:
-                self.cats[field] = 0 # first category 1
-	    Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
-        
-    def _checkMap(self):
-        """!Check if map is open
-        """
-        if not self.poMapInfo:
-            self._error.NoMap()
-            return False
-        
-        return True
-
-    def _addFeature(self, ftype, coords, layer, cat, snap, threshold):
-        """!Add new feature(s) to the vector map
-
-        @param ftype feature type (GV_POINT, GV_LINE, GV_BOUNDARY, ...)
-        @coords tuple of coordinates ((x, y), (x, y), ...)
-        @param layer layer number (-1 for no cat)
-        @param cat category number
-        @param snap snap to node/vertex
-        @param threshold threshold for snapping
-        
-        @return tuple (number of added features, list of fids)
-        @return number of features -1 on error
-        """
-        fids = list()
-        if not self._checkMap():
-            return (-1, None)
-        
-        is3D = bool(Vect_is_3d(self.poMapInfo))
-        
-        Debug.msg(2, "IVDigit._addFeature(): npoints=%d, layer=%d, cat=%d, snap=%d",
-                  len(coords), layer, cat, snap)
-        
-        if not (ftype & (GV_POINTS | GV_LINES | GV_AREA)): # TODO: 3D
-            self._error.FeatureType(ftype)
-            return (-1, None)
-        
-        # set category
-        Vect_reset_cats(self.poCats)
-        if layer > 0 and ftype != GV_AREA:
-            Vect_cat_set(self.poCats, layer, cat)
-            self.cats[layer] = max(cat, self.cats.get(layer, 1))
-        
-        # append points
-        Vect_reset_line(self.poPoints)
-        for c in coords:
-            Vect_append_point(self.poPoints, c[0], c[1], 0.0)
-        
-        if ftype & (GV_BOUNDARY | GV_AREA):
-            # close boundary
-            points = self.poPoints.contents
-            last = points.n_points - 1
-            if Vect_points_distance(points.x[0], points.x[0], points.z[0],
-                                    points.x[last], points.x[last], points.z[last],
-                                    is3D) <= threshold:
-                points.x[last] = points.x[0]
-                points.y[last] = points.y[0]
-                points.z[last] = points.z[0]
-        
-        if snap != NO_SNAP:
-            # apply snapping (node or vertex)
-            modeSnap = not (snap == SNAP)
-            Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
-                            -1, self.poPoints, threshold, modeSnap)
-        
-        if ftype == GV_AREA:
-            ltype = GV_BOUNDARY
-        else:
-            ltype = ftype
-        newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats)
-        if newline < 0:
-            self._error.WriteLine()
-            return (-1, None)
-        else:
-            fids.append(newline)
-        
-        left = right = -1
-        if ftype & GV_AREA:
-            # add centroids for left/right area
-            bpoints = Vect_new_line_struct()
-            cleft = c_int()
-            cright = c_int()
-            
-            Vect_get_line_areas(self.poMapInfo, newline,
-                                byref(cleft), byref(cright))
-            left = cleft.value
-            right = cright.value
-            
-            # check if area exists and has no centroid inside
-            if layer > 0 and (left > 0 or right > 0):
-                Vect_cat_set(self.poCats, layer, cat)
-                self.cats[layer] = max(cat, self.cats.get(layer, 0))
-            
-            x = c_double()
-            y = c_double()
-            if left > 0 and \
-                    Vect_get_area_centroid(self.poMapInfo, left) == 0:
-                # if Vect_get_area_points(self.poMapInfo, left, bpoints) > 0 and
-                # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
-                if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
-                    Vect_reset_line(bpoints)
-                    Vect_append_point(bpoints, x.value, y.value, 0.0)
-                    newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
-                                              bpoints, self.poCats)
-                    if newline < 0:
-                        self._error.WriteLine()
-                        return (len(fids), fids)
-                    else:
-                        fids.append(newline)
-                    
-            if right > 0 and \
-                    Vect_get_area_centroid(self.poMapInfo, right) == 0:
-                # if Vect_get_area_points(byref(self.poMapInfo), right, bpoints) > 0 and 
-                # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
-                if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
-                    Vect_reset_line(bpoints)
-                    Vect_append_point(bpoints, x.value, y.value, 0.0)
-                    newline =  Vect_write_line(self.poMapInfo, GV_CENTROID,
-                                               bpoints, self.poCats)
-                    if newline < 0:
-                        self._error.WriteLine()
-                        return (len(fids, fids))
-                    else:
-                        fids.append(newline)
-                    
-            Vect_destroy_line_struct(bpoints)
-        
-        # register changeset
-        changeset = len(self.changesets)
-        self._addActionToChangeset(changeset, newline, add = True)
-        
-        # break at intersection
-        if self._settings['breakLines']:
-            self._breakLineAtIntersection(newline, self.poPoints, changeset)
-        
-        return (len(fids), fids)
-    
-    def _ModifyLineVertex(self, coords, add = True):
-        """!Add or remove vertex
-        
-        Shape of line/boundary is not changed when adding new vertex.
-        
-        @param coords coordinates of point
-        @param add True to add, False to remove
-        
-        @return id id of the new feature
-        @return 0 nothing changed
-        @return -1 error
-        """
-        if not self._checkMap():
-            return -1
-        
-        selected = self._display.selected
-        if len(selected['ids']) != 1:
-            return 0
-        
-        poList  = self._display.GetSelectedIList()
-        Vect_reset_line(self.poPoints)
-        Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
-        
-        nlines = Vect_get_num_lines(self.poMapInfo)
-        thresh = self._display.GetThreshold(type = 'selectThresh')
-        
-        changeset = self._addActionsBefore()
-        
-        if add:
-            ret = Vedit_add_vertex(self.poMapInfo, poList,
-                                   self.poPoints, thresh)
-        else:
-            ret = Vedit_remove_vertex(self.poMapInfo, poList,
-                                      self.poPoints, thresh)
-        Vect_destroy_list(poList)
-        
-        if ret > 0:
-            self._addActionsAfter(changeset, nlines)
-        else:
-            del self.changesets[changeset]
-        
-        if not add and ret > 0 and self._settings['breakLines']:
-            self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                          None, changeset)
-                
-        return nlines + 1 # feature is write at the end of the file
-    
-    def GetLineCats(self, line):
-        """!Get list of layer/category(ies) for selected feature.
-
-        @param line feature id (-1 for first selected feature)
-
-        @return list of layer/cats
-        """
-        ret = dict()
-        if not self._checkMap():
-            return ret
-        
-        if line == -1 and len(self._display.selected['ids']) < 1:
-            return ret
-        
-        if line == -1:
-            line = self._display.selected['ids'][0]
-            
-        if not Vect_line_alive(self.poMapInfo, line):
-            self._error.DeadLine(line)
-            return ret
-        
-        if Vect_read_line(self.poMapInfo, None, self.poCats, line) < 0:
-            self._error.ReadLine(line)
-            return ret
-        
-        cats = self.poCats.contents
-        for i in range(cats.n_cats):
-            field = cats.field[i]
-            if field not in ret:
-                ret[field] = list()
-            ret[field].append(cats.cat[i])
-        
-        return ret
-
-    def GetLayers(self):
-        """!Get list of layers
-        
-        Requires self.InitCats() to be called.
-
-        @return list of layers
-        """
-        return self.cats.keys()
-    
-    def UpdateSettings(self):
-        """!Update digit (and display) settings
-        """
-        self._display.UpdateSettings()
-        
-        self._settings['breakLines']  = bool(UserSettings.Get(group = 'vdigit', key = "breakLines",
-                                                              subkey = 'enabled'))
-        
-    def SetCategory(self):
-        """!Update self.cats based on settings"""
-        sel = UserSettings.Get(group = 'vdigit', key = 'categoryMode', subkey = 'selection')
-        cat = None
-        if sel == 0: # next to usep
-            cat = self._setCategoryNextToUse()
-        elif sel == 1:
-            cat = UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')
-        
-        if cat:
-            layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
-            self.cats[layer] = cat
-        
-        return cat
-    
-    def _setCategoryNextToUse(self):
-        """!Find maximum category number for the given layer and
-        update the settings
-
-        @return category to be used
-        """
-        # get max category number for given layer and update the settings
-        layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
-        cat = self.cats.get(layer, 0) + 1
-        UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value',
-                         value = cat)
-        Debug.msg(1, "IVDigit._setCategoryNextToUse(): cat=%d", cat)
-        
-        return cat
-
-    def SelectLinesFromBackgroundMap(self, bbox):
-        """!Select features from background map
-
-        @param bbox bounding box definition
-        
-        @return list of selected feature ids
-        """
-        # try select features by box first
-        if self._display.SelectLinesByBox(bbox, poMapInfo = self.poBgMapInfo) < 1:
-            self._display.SelectLineByPoint(bbox[0], poMapInfo = self.poBgMapInfo)['line']
-            
-        return self._display.selected['ids']
-        
-    def GetUndoLevel(self):
-        """!Get undo level (number of active changesets)
-        
-        Note: Changesets starts wiht 0
-        """
-        return self.changesetCurrent
-    
-    def GetFeatureType(self):
-        """!Get feature type for OGR layers
-
-        @return feature type as string (Point, Line String, Polygon)
-        @return None for native format
-        """
-        return Vect_get_ogr_geometry_type(self.poMapInfo)
-        

Deleted: grass/trunk/gui/wxpython/gui_modules/wxvdriver.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxvdriver.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/gui_modules/wxvdriver.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,1012 +0,0 @@
-"""!
- at package wxvdriver.py
-
- at brief wxGUI vector digitizer (display driver)
-
-Code based on wxVdigit C++ component from GRASS 6.4.0
-(gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
-
-List of classes:
- - DisplayDriver
-
-(C) 2007-2011 by the GRASS Development Team
-
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import math
-import locale
-
-import wx
-
-from debug import Debug
-from preferences import globalSettings as UserSettings
-
-from grass.lib.gis    import *
-from grass.lib.vector import *
-from grass.lib.vedit  import *
-
-log       = None
-progress  = None
-last_error = ''
-
-def print_error(msg, type):
-    """!Redirect stderr"""
-    global log
-    if log:
-        log.write(msg)
-    else:
-        print msg
-    global last_error
-    last_error += ' ' + msg
-
-    return 0
-
-def print_progress(value):
-    """!Redirect progress info"""
-    global progress
-    if progress:
-        progress.SetValue(value)
-    else:
-        print value
-    
-    return 0
-
-def GetLastError():
-    global last_error
-    ret = last_error
-    if ret[-1] != '.':
-        ret += '.'
-    
-    last_error = '' # reset
-    
-    return ret
-
-errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
-errfunc = errtype(print_error)
-pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
-perfunc = pertype(print_progress)
-
-class DisplayDriver:
-    def __init__(self, device, deviceTmp, mapObj, window, glog, gprogress):
-        """!Display driver used by vector digitizer
-        
-        @param device    wx.PseudoDC device where to draw vector objects
-        @param deviceTmp wx.PseudoDC device where to draw temporary vector objects
-        @param mapOng    Map Object (render.Map)
-        @param windiow   parent window for dialogs
-        @param glog      logging device (None to discard messages)
-        @param gprogress progress bar device (None to discard message)
-        """
-        global errfunc, perfunc, log, progress
-        log = glog
-        progress = gprogress
-        
-        G_gisinit('wxvdigit')
-        locale.setlocale(locale.LC_NUMERIC, 'C')
-        G_set_error_routine(errfunc) 
-        G_set_percent_routine(perfunc)
-        # G_set_fatal_error(FATAL_RETURN)
-        
-        self.mapInfo   = None     # open vector map (Map_Info structure)
-        self.poMapInfo = None     # pointer to self.mapInfo
-        self.is3D      = False    # is open vector map 3D
-        
-        self.dc      = device     # PseudoDC devices
-        self.dcTmp   = deviceTmp
-        self.mapObj  = mapObj
-        self.region  = mapObj.GetCurrentRegion()
-        self.window  = window
-        self.log     = log        # log device
-
-        self.firstNode = True     # track PseudoDC Id of selected features
-        self.lastNodeId = -1
-        
-        # GRASS lib
-        self.poPoints = Vect_new_line_struct()
-        self.poCats   = Vect_new_cats_struct()
-        
-        # selected objects
-        self.selected = {
-            'field'   : -1,      # field number
-            'cats'    : list(),  # list of cats
-            'ids'     : list(),  # list of ids
-            'idsDupl' : list(),  # list of duplicated features
-            }
-        
-        # digitizer settings
-        self.settings = {
-            'highlight'     : None,
-            'highlightDupl' : { 'enabled' : False,
-                                'color'   : None },
-            'point'         : { 'enabled' : False,
-                                'color'   : None },
-            'line'          : { 'enabled' : False,
-                                'color'   : None },
-            'boundaryNo'    : { 'enabled' : False,
-                                'color'   : None },
-            'boundaryOne'   : { 'enabled' : False,
-                                'color'   : None },
-            'boundaryTwo'   : { 'enabled' : False,
-                                'color'   : None },
-            'centroidIn'    : { 'enabled' : False,
-                                'color'   : None },
-            'centroidOut'   : { 'enabled' : False,
-                                'color'   : None },
-            'centroidDup'   : { 'enabled' : False,
-                                'color'   : None },
-            'nodeOne'       : { 'enabled' : False,
-                                'color'   : None },
-            'nodeTwo'       : { 'enabled' : False,
-                                'color'   : None },
-            'vertex'        : { 'enabled' : False,
-                                'color'   : None },
-            'area'          : { 'enabled' : False,
-                                'color'   : None },
-            'direction'     : { 'enabled' : False,
-                                'color'   : None },
-            'lineWidth'     : -1,    # screen units 
-            }
-        
-        # topology
-        self._resetTopology()
-        
-        self._drawSelected = False
-        self._drawSegments = False
-        
-        self.UpdateSettings()
-        
-    def __del__(self):
-        """!Close currently open vector map"""
-        G_unset_error_routine()
-        G_unset_percent_routine()
-        
-        if self.poMapInfo:
-            self.CloseMap()
-        
-        Vect_destroy_line_struct(self.poPoints)
-        Vect_destroy_cats_struct(self.poCats)
-
-    def _resetTopology(self):
-        """!Reset topology dict
-        """
-        self.topology = {
-            'highlight'   : 0,
-            'point'       : 0,
-            'line'        : 0,
-            'boundaryNo'  : 0,
-            'boundaryOne' : 0,
-            'boundaryTwo' : 0,
-            'centroidIn'  : 0,
-            'centroidOut' : 0,
-            'centroidDup' : 0,
-            'nodeOne'     : 0,
-            'nodeTwo'     : 0,
-            'vertex'      : 0,
-            }
-        
-    def _cell2Pixel(self, east, north, elev):
-        """!Conversion from geographic coordinates (east, north)
-        to screen (x, y)
-  
-        @todo 3D stuff...
-
-        @param east, north, elev geographical coordinates
-
-        @return x, y screen coordinates (integer)
-        """
-        map_res = max(self.region['ewres'], self.region['nsres'])
-        w = self.region['center_easting']  - (self.mapObj.width  / 2) * map_res
-        n = self.region['center_northing'] + (self.mapObj.height / 2) * map_res
-        
-        return int((east - w) / map_res), int((n - north) / map_res)
-    
-    def _drawCross(self, pdc, point, size = 5):
-        """!Draw cross symbol of given size to device content
-   
-        Used for points, nodes, vertices
-
-        @param[in,out] PseudoDC where to draw
-        @param point coordinates of center
-        @param size size of the cross symbol
-   
-        @return 0 on success
-        @return -1 on failure
-        """
-        if not pdc or not point:
-            return -1
-        
-        pdc.DrawLine(point.x - size, point.y, point.x + size, point.y)
-        pdc.DrawLine(point.x, point.y - size, point.x, point.y + size)
-        
-        return 0
-    
-    def _drawObject(self, robj):
-        """!Draw given object to the device
-        
-        The object is defined as robject() from vedit.h.
-        
-        @param robj object to be rendered
-        
-        @return  1 on success
-        @return -1 on failure (vector feature marked as dead, etc.)
-        """
-        if not self.dc or not self.dcTmp:
-            return -1
-        
-        Debug.msg(3, "_drawObject(): type=%d npoints=%d", robj.type, robj.npoints)
-        brush = None
-        if self._isSelected(robj.fid):
-            pdc = self.dcTmp
-            if self.settings['highlightDupl']['enabled'] and self._isDuplicated(robj.fid):
-                pen = wx.Pen(self.settings['highlightDupl']['color'], self.settings['lineWidth'], wx.SOLID)
-            else:            
-                pen = wx.Pen(self.settings['highlight'], self.settings['lineWidth'], wx.SOLID)
-            
-            dcId = 1
-            self.topology['highlight'] += 1
-            if not self._drawSelected:
-                return
-        else:
-            pdc = self.dc
-            pen, brush = self._definePen(robj.type)
-            dcId = 0
-        
-        pdc.SetPen(pen)        
-        if brush:
-            pdc.SetBrush(brush)
-        
-        if robj.type & (TYPE_POINT | TYPE_CENTROIDIN | TYPE_CENTROIDOUT | TYPE_CENTROIDDUP |
-                        TYPE_NODEONE | TYPE_NODETWO | TYPE_VERTEX): # -> point
-            if dcId > 0:
-                if robj.type == TYPE_VERTEX:
-                    dcId = 3 # first vertex
-                elif robj.type & (TYPE_NODEONE | TYPE_NODETWO):
-                    if self.firstNode:
-                        dcId = 1
-                        self.firstNode = False
-                    else:
-                        dcId = self.lastNodeId
-            
-            for i in range(robj.npoints):
-                p = robj.point[i]
-                if dcId > 0:
-                    pdc.SetId(dcId)
-                    dcId += 2
-                self._drawCross(pdc, p)
-        else:
-            if dcId > 0 and self._drawSegments:
-                self.fisrtNode = True
-                self.lastNodeId = robj.npoints * 2 - 1
-                dcId = 2 # first segment
-                i = 0
-                while i < robj.npoints - 1:
-                    point_beg = wx.Point(robj.point[i].x, robj.point[i].y)
-                    point_end = wx.Point(robj.point[i+1].x, robj.point[i+1].y)
-                    pdc.SetId(dcId) # set unique id & set bbox for each segment
-                    pdc.SetPen(pen)
-                    pdc.SetIdBounds(dcId - 1, wx.Rect(point_beg.x, point_beg.y, 0, 0))
-                    pdc.SetIdBounds(dcId, wx.RectPP(point_beg, point_end))
-                    pdc.DrawLine(point_beg.x, point_beg.y,
-                                 point_end.x, point_end.y)
-                    i    += 1
-                    dcId += 2
-                pdc.SetIdBounds(dcId - 1, wx.Rect(robj.point[robj.npoints - 1].x,
-                                                  robj.point[robj.npoints - 1].y,
-                                                  0, 0))
-            else:
-                points = list()
-                for i in range(robj.npoints):
-                    p = robj.point[i]
-                    points.append(wx.Point(p.x, p.y))
-                    
-                if robj.type == TYPE_AREA:
-                    pdc.DrawPolygon(points)
-                else:
-                    pdc.DrawLines(points)
-        
-    def _definePen(self, rtype):
-        """!Define pen/brush based on rendered object)
-        
-        Updates also self.topology dict
-
-        @return pen, brush
-        """
-        if rtype == TYPE_POINT:
-            key = 'point'
-        elif rtype == TYPE_LINE:
-            key = 'line'
-        elif rtype == TYPE_BOUNDARYNO:
-            key = 'boundaryNo'
-        elif rtype == TYPE_BOUNDARYTWO:
-            key = 'boundaryTwo'
-        elif rtype == TYPE_BOUNDARYONE:
-            key = 'boundaryOne'
-        elif rtype == TYPE_CENTROIDIN:
-            key = 'centroidIn'
-        elif rtype == TYPE_CENTROIDOUT:
-            key = 'centroidOut'
-        elif rtype == TYPE_CENTROIDDUP:
-            key = 'centroidDup'
-        elif rtype == TYPE_NODEONE:
-            key = 'nodeOne'
-        elif rtype == TYPE_NODETWO:
-            key = 'nodeTwo'
-        elif rtype == TYPE_VERTEX:
-            key = 'vertex'
-        elif rtype == TYPE_AREA:
-            key = 'area' 
-        elif rtype == TYPE_ISLE:
-            key = 'isle'
-        elif rtype == TYPE_DIRECTION:
-            key = 'direction'
-        
-        if key not in ('direction', 'area', 'isle'):
-            self.topology[key] += 1
-        
-        if key in ('area', 'isle'):
-            pen = wx.TRANSPARENT_PEN
-            if key == 'area':
-                brush = wx.Brush(self.settings[key]['color'], wx.SOLID)
-            else:
-                brush = wx.TRANSPARENT_BRUSH
-        else:
-            pen = wx.Pen(self.settings[key]['color'], self.settings['lineWidth'], wx.SOLID)
-            brush = None
-        
-        return pen, brush
-        
-    def _getDrawFlag(self):
-        """!Get draw flag from the settings
-        
-        See vedit.h for list of draw flags.
-        
-        @return draw flag (int)
-        """
-        ret = 0
-        if self.settings['point']['enabled']:
-            ret |= DRAW_POINT
-        if self.settings['line']['enabled']:
-            ret |= DRAW_LINE
-        if self.settings['boundaryNo']['enabled']:
-            ret |= DRAW_BOUNDARYNO
-        if self.settings['boundaryTwo']['enabled']:
-            ret |= DRAW_BOUNDARYTWO
-        if self.settings['boundaryOne']['enabled']:
-            ret |= DRAW_BOUNDARYONE
-        if self.settings['centroidIn']['enabled']:
-            ret |= DRAW_CENTROIDIN
-        if self.settings['centroidOut']['enabled']:
-            ret |= DRAW_CENTROIDOUT
-        if self.settings['centroidDup']['enabled']:
-            ret |= DRAW_CENTROIDDUP
-        if self.settings['nodeOne']['enabled']:
-            ret |= DRAW_NODEONE
-        if self.settings['nodeTwo']['enabled']:
-            ret |= DRAW_NODETWO
-        if self.settings['vertex']['enabled']:
-            ret |= DRAW_VERTEX
-        if self.settings['area']['enabled']:
-            ret |= DRAW_AREA
-        if self.settings['direction']['enabled']:
-            ret |= DRAW_DIRECTION
-        
-        return ret
-        
-    def _isSelected(self, line, force = False):
-        """!Check if vector object selected?
-   
-        @param line feature id
-
-        @return True if vector object is selected
-        @return False if vector object is not selected
-        """
-        if len(self.selected['cats']) < 1 or force:
-            # select by id
-            if line in self.selected['ids']:
-                return True
-        else: 
-            # select by cat
-            cats = self.poCats.contents
-            for i in range(cats.n_cats):
-                if cats.field[i] == self.selected['field'] and \
-                        cats.cat[i] in self.selected['cats']:
-                    # remember id
-                    # -> after drawing all features selected.cats is reseted */
-                    self.selected['ids'].append(line)
-                    return True
-        
-        return False
-
-    def _isDuplicated(self, line):
-        """!Check for already marked duplicates
-        
-        @param line feature id
-
-        @return True line already marked as duplicated
-        @return False not duplicated
-        """
-        return line in self.selected['idsDupl']
-    
-    def _getRegionBox(self):
-        """!Get bound_box() from current region
-
-        @return bound_box
-        """
-        box = bound_box()
-        
-        box.N = self.region['n']
-        box.S = self.region['s']
-        box.E = self.region['e']
-        box.W = self.region['w']
-        box.T = PORT_DOUBLE_MAX
-        box.B = -PORT_DOUBLE_MAX
-        
-        return box
-
-    def DrawMap(self, force = False):
-        """!Draw content of the vector map to the device
-        
-        @param force force drawing
-        @return number of drawn features
-        @return -1 on error
-        """
-        Debug.msg(1, "DisplayDriver.DrawMap(): force=%d", force)
-        
-        if not self.poMapInfo or not self.dc or not self.dcTmp:
-            return -1
-        
-        try:
-            rlist = Vedit_render_map(self.poMapInfo, byref(self._getRegionBox()), self._getDrawFlag(),
-                                     self.region['center_easting'], self.region['center_northing'],
-                                     self.mapObj.width, self.mapObj.height,
-                                     max(self.region['nsres'], self.region['ewres'])).contents
-        except SystemExit:
-            pass
-        
-        self._resetTopology()
-        
-        self.dc.BeginDrawing()
-        self.dcTmp.BeginDrawing()
-        
-        # draw objects
-        for i in range(rlist.nitems):
-            robj = rlist.item[i].contents
-            self._drawObject(robj)
-        
-        self.dc.EndDrawing()
-        self.dcTmp.EndDrawing()
-        
-        # reset list of selected features by cat 
-        # list of ids - see IsSelected()
-        self.selected['field'] = -1
-        self.selected['cats'] = list()
-        
-    def _getSelectType(self):
-        """!Get type(s) to be selected
-
-        Used by SelectLinesByBox() and SelectLineByPoint()
-        """
-        ftype = 0
-        for feature in (('point',    GV_POINT),
-                        ('line',     GV_LINE),
-                        ('centroid', GV_CENTROID),
-                        ('boundary', GV_BOUNDARY)):
-            if UserSettings.Get(group = 'vdigit', key = 'selectType',
-                                subkey = [feature[0], 'enabled']):
-                ftype |= feature[1]
-        
-        return ftype
-
-    def _validLine(self, line):
-        """!Check if feature id is valid
-
-        @param line feature id
-
-        @return True valid feature id
-        @return False invalid
-        """
-        if line > 0 and line <= Vect_get_num_lines(self.poMapInfo):
-            return True
-        
-        return False
-    
-    def SelectLinesByBox(self, bbox, drawSeg = False, poMapInfo = None):
-        """!Select vector objects by given bounding box
-        
-        If line id is already in the list of selected lines, then it will
-        be excluded from this list.
-        
-        @param bbox bounding box definition
-        @param drawSeg True to draw segments of line
-        @param poMapInfo use external Map_info, None for self.poMapInfo
-
-        @return number of selected features
-        @return None on error
-        """
-        thisMapInfo = poMapInfo is None
-        if not poMapInfo:
-            poMapInfo = self.poMapInfo
-        
-        if not poMapInfo:
-            return None
-        
-        if thisMapInfo:
-            self._drawSegments = drawSeg
-            self._drawSelected = True
-        
-            # select by ids
-            self.selected['cats'] = list()
-        
-        poList = Vect_new_list()
-        x1, y1 = bbox[0]
-        x2, y2 = bbox[1]
-        poBbox = Vect_new_line_struct()
-        Vect_append_point(poBbox, x1, y1, 0.0)
-        Vect_append_point(poBbox, x2, y1, 0.0)
-        Vect_append_point(poBbox, x2, y2, 0.0)
-        Vect_append_point(poBbox, x1, y2, 0.0)
-        Vect_append_point(poBbox, x1, y1, 0.0)
-        
-        Vect_select_lines_by_polygon(poMapInfo, poBbox,
-                                     0, None, # isles
-                                     self._getSelectType(), poList)
-        
-        flist = poList.contents
-        nlines = flist.n_values
-        Debug.msg(1, "DisplayDriver.SelectLinesByBox() num = %d", nlines)
-        for i in range(nlines):
-            line = flist.value[i]
-            if UserSettings.Get(group = 'vdigit', key = 'selectInside',
-                                subkey = 'enabled'):
-                inside = True
-                if not self._validLine(line):
-                    return None
-                Vect_read_line(poMapInfo, self.poPoints, None, line)
-                points = self.poPoints.contents
-                for p in range(points.n_points):
-                    if not Vect_point_in_poly(points.x[p], points.y[p],
-                                              poBbox):
-                        inside = False
-                        break
-                    
-                if not inside:
-                    continue # skip lines just overlapping bbox
-            
-            if not self._isSelected(line):
-                self.selected['ids'].append(line)
-            else:
-                self.selected['ids'].remove(line)
-        
-        Vect_destroy_line_struct(poBbox)
-        Vect_destroy_list(poList)
-        
-        return nlines
-
-    def SelectLineByPoint(self, point, poMapInfo = None):
-        """!Select vector feature by given point in given
-        threshold
-   
-        Only one vector object can be selected. Bounding boxes of
-        all segments are stores.
-        
-        @param point points coordinates (x, y)
-        @param poMapInfo use external Map_info, None for self.poMapInfo
-
-        @return dict {'line' : feature id, 'point' : point on line}
-        """
-        thisMapInfo = poMapInfo is None
-        if not poMapInfo:
-            poMapInfo = self.poMapInfo
-        
-        if not poMapInfo:
-            return { 'line' : -1, 'point': None }
-        
-        if thisMapInfo:
-            self._drawSelected = True
-            # select by ids 
-            self.selected['cats'] = list()
-        
-        poFound = Vect_new_list()
-        
-        lineNearest = Vect_find_line_list(poMapInfo, point[0], point[1], 0,
-                                           self._getSelectType(), self.GetThreshold(), self.is3D,
-                                           None, poFound)
-        Debug.msg(1, "DisplayDriver.SelectLineByPoint() found = %d", lineNearest)
-        
-        if lineNearest > 0:
-            if not self._isSelected(lineNearest):
-                self.selected['ids'].append(lineNearest)
-            else:
-                self.selected['ids'].remove(lineNearest)
-        
-        px = c_double()
-        py = c_double()
-        pz = c_double()
-        if not self._validLine(lineNearest):
-            return { 'line' : -1, 'point': None }
-	ftype = Vect_read_line(poMapInfo, self.poPoints, self.poCats, lineNearest)
-	Vect_line_distance (self.poPoints, point[0], point[1], 0.0, self.is3D,
-			    byref(px), byref(py), byref(pz),
-			    None, None, None)
-        
-	# check for duplicates 
-	if self.settings['highlightDupl']['enabled']:
-            found = poFound.contents
-	    for i in range(found.n_values):
-		line = found.value[i]
-		if line != lineNearest:
-                    self.selected['ids'].append(line)
-	    
-            self.GetDuplicates()
-	    
-	    for i in range(found.n_values):
-		line = found.value[i]
-		if line != lineNearest and not self._isDuplicated(line):
-                    self.selected['ids'].remove(line)
-        
-        Vect_destroy_list(poFound)
-        
-        if thisMapInfo:
-            # drawing segments can be very expensive
-            # only one features selected
-            self._drawSegments = True
-        
-        return { 'line'  : lineNearest,
-                 'point' : (px.value, py.value, pz.value) }
-    
-    def _listToIList(self, plist):
-        """!Generate from list struct_ilist
-        """
-        ilist = Vect_new_list()
-        for val in plist:
-            Vect_list_append(ilist, val)
-        
-        return ilist
-        
-    def GetSelectedIList(self, ilist = None):
-        """!Get list of selected objects as struct_ilist
-
-        Returned IList must be freed by Vect_destroy_list().
-        
-        @return struct_ilist
-        """
-        if ilist:
-            return self._listToIList(ilist)
-        
-        return self._listToIList(self.selected['ids'])
-        
-    def GetSelected(self, grassId = True):
-        """!Get ids of selected objects
-        
-        @param grassId True for feature id, False for PseudoDC id
-        
-        @return list of ids of selected vector objects
-        """
-        if grassId:
-            return self.selected['ids']
-        
-        dc_ids = list()
-        
-        if not self._drawSegments:
-            dc_ids.append(1)
-        elif len(self.selected['ids']) > 0:
-            # only first selected feature
-            Vect_read_line(self.poMapInfo, self.poPoints, None,
-                           self.selected['ids'][0])
-            points = self.poPoints.contents
-            # node - segment - vertex - segment - node
-            for i in range(1, 2 * points.n_points):
-                dc_ids.append(i)
-        
-        return dc_ids
-        
-    def SetSelected(self, ids, layer = -1):
-        """!Set selected vector objects
-
-        @param list of ids (None to unselect features)
-        @param layer layer number for features selected based on category number
-        """
-        if ids:
-            self._drawSelected = True
-        else:
-            self._drawSelected = False
-        
-        if layer > 0:
-            selected.field = layer
-            self.selected['cats'] = ids
-        else:
-            field = -1
-            self.selected['ids'] = ids
-        
-    def GetSelectedVertex(self, pos):
-        """!Get PseudoDC vertex id of selected line
-
-        Set bounding box for vertices of line.
-        
-        @param pos position
-        
-        @return id of center, left and right vertex
-        @return 0 no line found
-        @return -1 on error
-        """
-        returnId = list()
-        # only one object can be selected
-        if len(self.selected['ids']) != 1 or not self._drawSegments:
-            return returnId
-        
-        startId = 1
-        line = self.selected['ids'][0]
-        
-        if not self._validLine(line):
-            return -1
-        ftype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
-        
-        minDist = 0.0
-        Gid = -1
-        # find the closest vertex (x, y)
-        DCid = 1
-        points = self.poPoints.contents
-        for idx in range(points.n_points):
-            dist = Vect_points_distance(pos[0], pos[1], 0.0,
-                                        points.x[idx], points.y[idx], points.z[idx], 0)
-            
-            if idx == 0:
-                minDist = dist
-                Gid     = idx
-            else:
-                if minDist > dist:
-                    minDist = dist
-                    Gid = idx
-            
-            vx, vy = self._cell2Pixel(points.x[idx], points.y[idx], points.z[idx])
-            rect = wx.Rect(vx, vy, 0, 0)
-            self.dc.SetIdBounds(DCid, rect)
-            DCid += 2
-        
-        if minDist > self.GetThreshold():
-            return returnId
-        
-        # translate id
-        DCid = Gid * 2 + 1
-        
-        # add selected vertex
-        returnId.append(DCid)
-        # left vertex
-        if DCid == startId:
-            returnId.append(-1)
-        else:
-            returnId.append(DCid - 2)
-        # right vertex
-        if DCid == (points.n_points - 1) * 2 + startId:
-            returnId.append(-1)
-        else:
-            returnId.append(DCid + 2)
-        
-        return returnId
-
-    def DrawSelected(self, flag):
-        """!Draw selected features
-        
-        @param flag True to draw selected features
-        """
-        self._drawSelected = bool(flag)
-        
-    def CloseMap(self):
-        """!Close vector map
-        
-        @return 0 on success
-        @return non-zero on error
-        """
-        ret = 0
-        if self.poMapInfo:
-            # rebuild topology
-            Vect_build_partial(self.poMapInfo, GV_BUILD_NONE)
-            Vect_build(self.poMapInfo)
-
-            # close map and store topo/cidx
-            ret = Vect_close(self.poMapInfo)
-            del self.mapInfo
-            self.poMapInfo = self.mapInfo = None
-        
-        return ret
-    
-    def OpenMap(self, name, mapset, update = True):
-        """!Open vector map by the driver
-        
-        @param name name of vector map to be open
-        @param mapset name of mapset where the vector map lives
-   
-        @return map_info
-        @return None on error
-        """
-        Debug.msg("DisplayDriver.OpenMap(): name=%s mapset=%s updated=%d",
-                  name, mapset, update)
-        if not self.mapInfo:
-            self.mapInfo = Map_info()
-            self.poMapInfo = pointer(self.mapInfo)
-        
-        # open existing map
-        if update:
-            ret = Vect_open_update(self.poMapInfo, name, mapset)
-        else:
-            ret = Vect_open_old(self.poMapInfo, name, mapset)
-        self.is3D = Vect_is_3d(self.poMapInfo)
-        
-        if ret == -1: # error
-            del self.mapInfo
-            self.poMapInfo = self.mapInfo = None
-        elif ret < 2:
-            dlg = wx.MessageDialog(parent = self.window,
-                                   message = _("Topology for vector map <%s> is not available. "
-                                               "Topology is required by digitizer. Do you want to "
-                                               "rebuild topology (takes some time) and open the vector map "
-                                               "for editing?") % name,
-                                   caption=_("Topology missing"),
-                                   style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
-            ret = dlg.ShowModal()
-            if ret != wx.ID_YES:
-                del self.mapInfo
-                self.poMapInfo = self.mapInfo = None
-            else:
-                Vect_build(self.poMapInfo)
-        
-        return self.poMapInfo
-    
-    def GetMapBoundingBox(self):
-        """!Get bounding box of (opened) vector map layer
-
-        @return (w,s,b,e,n,t)
-        """
-        if not self.poMapInfo:
-            return None
-        
-        bbox = bound_box()
-        Vect_get_map_box(self.poMapInfo, byref(bbox))
-
-        return bbox.W, bbox.S, bbox.B, \
-            bbox.E, bbox.N, bbox.T
-    
-    def UpdateSettings(self, alpha = 255):
-        """!Update display driver settings
-
-        @todo map units
-        
-        @alpha color value for aplha channel
-        """
-        color = dict()
-        for key in self.settings.keys():
-            if key == 'lineWidth':
-                self.settings[key] = int(UserSettings.Get(group = 'vdigit', key = 'lineWidth',
-                                                          subkey = 'value'))
-                continue
-            
-            color = wx.Color(UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                              subkey = [key, 'color'])[0],
-                             UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                              subkey = [key, 'color'])[1],
-                             UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                              subkey = [key, 'color'])[2],
-                             alpha)
-            
-            if key == 'highlight':
-                self.settings[key] = color
-                continue
-            
-            if key == 'highlightDupl':
-                self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
-                                                                      subkey = 'enabled'))
-            else:
-                self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'symbol',
-                                                                      subkey = [key, 'enabled']))
-            
-            self.settings[key]['color'] = color
-        
-    def UpdateRegion(self):
-        """!Update geographical region used by display driver
-        """
-        self.region = self.mapObj.GetCurrentRegion()
-        
-    def GetThreshold(self, type = 'snapping', value = None, units = None):
-        """!Return threshold value in map units
-        
-        @param type snapping mode (node, vertex)
-        @param value threshold to be set up
-        @param units units (map, screen)
-
-        @return threshold value
-        """
-        if value is None:
-            value = UserSettings.Get(group = 'vdigit', key = type, subkey = 'value')
-        
-        if units is None:
-            units = UserSettings.Get(group = 'vdigit', key = type, subkey = 'units')
-        
-        if value < 0:
-            value = (self.region['nsres'] + self.region['ewres']) / 2.0
-        
-        if units == "screen pixels":
-            # pixel -> cell
-            res = max(self.region['nsres'], self.region['ewres'])
-            return value * res
-        
-        return value
-    
-    def GetDuplicates(self):
-        """!Return ids of (selected) duplicated vector features
-        """
-        if not self.poMapInfo:
-            return
-        
-        ids = dict()
-        APoints = Vect_new_line_struct()
-        BPoints = Vect_new_line_struct()
-        
-        self.selected['idsDupl'] = list()
-        
-        for i in range(len(self.selected['ids'])):
-            line1 = self.selected['ids'][i]
-            if self._isDuplicated(line1):
-                continue
-            
-            Vect_read_line(self.poMapInfo, APoints, None, line1)
-            
-            for line2 in self.selected['ids']:
-                if line1 == line2 or self._isDuplicated(line2):
-                    continue
-                
-                Vect_read_line(self.poMapInfo, BPoints, None, line2)
-	    
-                if Vect_line_check_duplicate(APoints, BPoints, WITHOUT_Z):
-                    if i not in ids:
-                        ids[i] = list()
-                        ids[i].append((line1, self._getCatString(line1)))
-                        self.selected['idsDupl'].append(line1)
-                    
-                    ids[i].append((line2, self._getCatString(line2)))
-                    self.selected['idsDupl'].append(line2)
-        
-        Vect_destroy_line_struct(APoints)
-        Vect_destroy_line_struct(BPoints)
-
-        return ids
-    
-    def _getCatString(self, line):
-        Vect_read_line(self.poMapInfo, None, self.poCats, line)
-        
-        cats = self.poCats.contents
-        catsDict = dict()
-        for i in range(cats.n_cats):
-            layer = cats.field[i]
-            if layer not in catsDict:
-                catsDict[layer] = list()
-            catsDict[layer].append(cats.cat[i])
-        
-        catsStr = ''
-        for l, c in catsDict.iteritems():
-            catsStr = '%d: (%s)' % (l, ','.join(map(str, c)))
-        
-        return catsStr
-
-    def UnSelect(self, lines):
-        """!Unselect vector features
-
-        @param lines list of feature id(s)
-        """
-        checkForDupl = False
-
-        for line in lines:
-            if self._isSelected(line):
-                self.selected['ids'].remove(line)
-            if self.settings['highlightDupl']['enabled'] and self._isDuplicated(line):
-                checkForDupl = True
-
-        if checkForDupl:
-            self.GetDuplicates()
-        
-        return len(self.selected['ids'])
-    
-

Modified: grass/trunk/gui/wxpython/icons/grass_icons.py
===================================================================
--- grass/trunk/gui/wxpython/icons/grass_icons.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/icons/grass_icons.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -7,7 +7,7 @@
 
 import os
 
-import globalvar
+from core import globalvar
 
 iconPath = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass")
 

Modified: grass/trunk/gui/wxpython/icons/icon.py
===================================================================
--- grass/trunk/gui/wxpython/icons/icon.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/icons/icon.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -26,7 +26,7 @@
 
 import wx
 
-from preferences import globalSettings as UserSettings
+from core.settings import UserSettings
 
 # default icon set
 import grass_icons

Copied: grass/trunk/gui/wxpython/lmgr/layertree.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/layertree.py)
===================================================================
--- grass/trunk/gui/wxpython/lmgr/layertree.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/lmgr/layertree.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1644 @@
+"""!
+ at package lmgr.layertree
+
+ at brief Utility classes for map layer management.
+
+Classes:
+ - LayerTree
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+ 
+ at author Michael Barton (Arizona State University)
+ at author Jachym Cepicky (Mendel University of Agriculture)
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import wx
+try:
+    import wx.lib.agw.customtreectrl as CT
+except ImportError:
+    import wx.lib.customtreectrl as CT
+import wx.lib.buttons  as buttons
+try:
+    import treemixin 
+except ImportError:
+    from wx.lib.mixins import treemixin
+
+from grass.script import core as grass
+
+from core                import globalvar
+from gui_core.dialogs    import SqlQueryFrame, SetOpacityDialog
+from core.forms          import GUI
+from mapdisp.frame       import MapFrame
+from core.render         import Map
+from modules.histogram   import HistogramFrame
+from core.utils          import GetLayerNameFromCmd
+from wxplot.profile      import ProfileFrame
+from core.debug          import Debug
+from icon                import Icons
+from core.settings       import UserSettings
+from vdigit.main         import haveVDigit
+from core.gcmd           import GWarning
+
+TREE_ITEM_HEIGHT = 25
+
+class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
+    """!Creates layer tree structure
+    """
+    def __init__(self, parent,
+                 id = wx.ID_ANY, style = wx.SUNKEN_BORDER,
+                 ctstyle = CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
+                 CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
+                 CT.TR_MULTIPLE, **kwargs):
+        
+        if 'style' in kwargs:
+            ctstyle |= kwargs['style']
+            del kwargs['style']
+        self.disp_idx = kwargs['idx']
+        del kwargs['idx']
+        self.lmgr = kwargs['lmgr']
+        del kwargs['lmgr']
+        self.notebook = kwargs['notebook']   # GIS Manager notebook for layer tree
+        del kwargs['notebook']
+        self.auimgr = kwargs['auimgr']       # aui manager
+        del kwargs['auimgr']
+        showMapDisplay = kwargs['showMapDisplay']
+        del kwargs['showMapDisplay']
+        self.treepg = parent                 # notebook page holding layer tree
+        self.Map = Map()                     # instance of render.Map to be associated with display
+        self.root = None                     # ID of layer tree root node
+        self.groupnode = 0                   # index value for layers
+        self.optpage = {}                    # dictionary of notebook option pages for each map layer
+        self.layer_selected = None           # ID of currently selected layer
+        self.saveitem = {}                   # dictionary to preserve layer attributes for drag and drop
+        self.first = True                    # indicates if a layer is just added or not
+        self.flag = ''                       # flag for drag and drop hittest
+        self.rerender = False                # layer change requires a rerendering if auto render
+        self.reorder = False                 # layer change requires a reordering
+        
+        try:
+            ctstyle |= CT.TR_ALIGN_WINDOWS
+        except AttributeError:
+            pass
+        
+        if globalvar.hasAgw:
+            super(LayerTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
+        else:
+            super(LayerTree, self).__init__(parent, id, style = ctstyle, **kwargs)
+        self.SetName("LayerTree")
+        
+        ### SetAutoLayout() causes that no vertical scrollbar is displayed
+        ### when some layers are not visible in layer tree
+        # self.SetAutoLayout(True)
+        self.SetGradientStyle(1)
+        self.EnableSelectionGradient(True)
+        self._setGradient()
+        
+        # init associated map display
+        pos = wx.Point((self.disp_idx + 1) * 25, (self.disp_idx + 1) * 25)
+        self.mapdisplay = MapFrame(self, id = wx.ID_ANY, pos = pos,
+                                   size = globalvar.MAP_WINDOW_SIZE,
+                                   style = wx.DEFAULT_FRAME_STYLE,
+                                   tree = self, notebook = self.notebook,
+                                   lmgr = self.lmgr, page = self.treepg,
+                                   Map = self.Map, auimgr = self.auimgr)
+        
+        # title
+        self.mapdisplay.SetTitle(_("GRASS GIS Map Display: %(id)d  - Location: %(loc)s") % \
+                                     { 'id' : self.disp_idx + 1,
+                                       'loc' : grass.gisenv()["LOCATION_NAME"] })
+        
+        # show new display
+        if showMapDisplay is True:
+            self.mapdisplay.Show()
+            self.mapdisplay.Refresh()
+            self.mapdisplay.Update()
+        
+        self.root = self.AddRoot(_("Map Layers"))
+        self.SetPyData(self.root, (None, None))
+        
+        # create image list to use with layer tree
+        il = wx.ImageList(16, 16, mask = False)
+        
+        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
+        self.folder_open = il.Add(trart)
+        trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
+        self.folder = il.Add(trart)
+        
+        bmpsize = (16, 16)
+        icons = Icons['layerManager']
+        trgif = icons["addRast"].GetBitmap(bmpsize)
+        self.rast_icon = il.Add(trgif)
+        
+        trgif = icons["addRast3d"].GetBitmap(bmpsize)
+        self.rast3d_icon = il.Add(trgif)
+        
+        trgif = icons["addRgb"].GetBitmap(bmpsize)
+        self.rgb_icon = il.Add(trgif)
+        
+        trgif = icons["addHis"].GetBitmap(bmpsize)
+        self.his_icon = il.Add(trgif)
+        
+        trgif = icons["addShaded"].GetBitmap(bmpsize)
+        self.shaded_icon = il.Add(trgif)
+        
+        trgif = icons["addRArrow"].GetBitmap(bmpsize)
+        self.rarrow_icon = il.Add(trgif)
+        
+        trgif = icons["addRNum"].GetBitmap(bmpsize)
+        self.rnum_icon = il.Add(trgif)
+        
+        trgif = icons["addVect"].GetBitmap(bmpsize)
+        self.vect_icon = il.Add(trgif)
+        
+        trgif = icons["addThematic"].GetBitmap(bmpsize)
+        self.theme_icon = il.Add(trgif)
+        
+        trgif = icons["addChart"].GetBitmap(bmpsize)
+        self.chart_icon = il.Add(trgif)
+        
+        trgif = icons["addGrid"].GetBitmap(bmpsize)
+        self.grid_icon = il.Add(trgif)
+        
+        trgif = icons["addGeodesic"].GetBitmap(bmpsize)
+        self.geodesic_icon = il.Add(trgif)
+        
+        trgif = icons["addRhumb"].GetBitmap(bmpsize)
+        self.rhumb_icon = il.Add(trgif)
+        
+        trgif = icons["addLabels"].GetBitmap(bmpsize)
+        self.labels_icon = il.Add(trgif)
+        
+        trgif = icons["addCmd"].GetBitmap(bmpsize)
+        self.cmd_icon = il.Add(trgif)
+        
+        self.AssignImageList(il)
+        
+        self.Bind(wx.EVT_TREE_ITEM_EXPANDING,   self.OnExpandNode)
+        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED,   self.OnCollapseNode)
+        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED,   self.OnActivateLayer)
+        self.Bind(wx.EVT_TREE_SEL_CHANGED,      self.OnChangeSel)
+        self.Bind(CT.EVT_TREE_ITEM_CHECKED,     self.OnLayerChecked)
+        self.Bind(wx.EVT_TREE_DELETE_ITEM,      self.OnDeleteLayer)
+        self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnLayerContextMenu)
+        self.Bind(wx.EVT_TREE_END_DRAG,         self.OnEndDrag)
+        self.Bind(wx.EVT_TREE_END_LABEL_EDIT,   self.OnRenamed)
+        self.Bind(wx.EVT_KEY_UP,                self.OnKeyUp)
+        self.Bind(wx.EVT_IDLE,                  self.OnIdle)
+
+    def _setGradient(self, iType = None):
+        """!Set gradient for items
+
+        @param iType bgmap, vdigit or None
+        """
+        if iType == 'bgmap':
+            self.SetFirstGradientColour(wx.Colour(0, 100, 0))
+            self.SetSecondGradientColour(wx.Colour(0, 150, 0))
+        elif iType == 'vdigit':
+            self.SetFirstGradientColour(wx.Colour(100, 0, 0))
+            self.SetSecondGradientColour(wx.Colour(150, 0, 0))
+        else:
+            self.SetFirstGradientColour(wx.Colour(100, 100, 100))
+            self.SetSecondGradientColour(wx.Colour(150, 150, 150))
+        
+    def GetMap(self):
+        """!Get map instace"""
+        return self.Map
+    
+    def GetMapDisplay(self):
+        """!Get associated MapFrame"""
+        return self.mapdisplay
+    
+    def OnIdle(self, event):
+        """!Only re-order and re-render a composite map image from GRASS during
+        idle time instead of multiple times during layer changing.
+        """
+        if self.rerender:
+            if self.mapdisplay.GetToolbar('vdigit'):
+                vector = True
+            else:
+                vector = False
+            if self.mapdisplay.IsAutoRendered():
+                self.mapdisplay.MapWindow.UpdateMap(render = True, renderVector = vector)
+                if self.lmgr.IsPaneShown('toolbarNviz'): # nviz
+                    self.mapdisplay.MapWindow3D.UpdateMap(render = True)
+            self.rerender = False
+        
+        event.Skip()
+        
+    def OnKeyUp(self, event):
+        """!Key pressed"""
+        key = event.GetKeyCode()
+        
+        if key == wx.WXK_DELETE and self.lmgr and \
+                not self.GetEditControl():
+            self.lmgr.OnDeleteLayer(None)
+        
+        event.Skip()
+        
+    def OnLayerContextMenu (self, event):
+        """!Contextual menu for item/layer"""
+        if not self.layer_selected:
+            event.Skip()
+            return
+
+        ltype = self.GetPyData(self.layer_selected)[0]['type']
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        
+        Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \
+                       ltype)
+
+        if not hasattr (self, "popupID"):
+            self.popupID = dict()
+            for key in ('remove', 'rename', 'opacity', 'nviz', 'zoom',
+                        'region', 'export', 'attr', 'edit0', 'edit1',
+                        'bgmap', 'topo', 'meta', 'null', 'zoom1', 'region1',
+                        'color', 'hist', 'univar', 'prof', 'properties', 'sql'):
+                self.popupID[key] = wx.NewId()
+        
+        self.popupMenu = wx.Menu()
+        
+        numSelected = len(self.GetSelections())
+        
+        self.popupMenu.Append(self.popupID['remove'], text = _("Remove"))
+        self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id = self.popupID['remove'])
+        
+        if ltype != "command":
+            self.popupMenu.Append(self.popupID['rename'], text = _("Rename"))
+            self.Bind(wx.EVT_MENU, self.OnRenameLayer, id = self.popupID['rename'])
+            if numSelected > 1:
+                self.popupMenu.Enable(self.popupID['rename'], False)
+        
+        # map layer items
+        if ltype not in ("group", "command"):
+            self.popupMenu.AppendSeparator()
+            self.popupMenu.Append(self.popupID['opacity'], text = _("Change opacity level"))
+            self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id = self.popupID['opacity'])
+            self.popupMenu.Append(self.popupID['properties'], text = _("Properties"))
+            self.Bind(wx.EVT_MENU, self.OnPopupProperties, id = self.popupID['properties'])
+            
+            if numSelected > 1:
+                self.popupMenu.Enable(self.popupID['opacity'], False)
+                self.popupMenu.Enable(self.popupID['properties'], False)
+            
+            if ltype in ('raster', 'vector', '3d-raster') and self.lmgr.IsPaneShown('toolbarNviz'):
+                self.popupMenu.Append(self.popupID['nviz'], _("3D view properties"))
+                self.Bind (wx.EVT_MENU, self.OnNvizProperties, id = self.popupID['nviz'])
+            
+            if ltype in ('raster', 'vector', 'rgb'):
+                self.popupMenu.Append(self.popupID['zoom'], text = _("Zoom to selected map(s)"))
+                self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id = self.popupID['zoom'])
+                self.popupMenu.Append(self.popupID['region'], text = _("Set computational region from selected map(s)"))
+                self.Bind(wx.EVT_MENU, self.OnSetCompRegFromMap, id = self.popupID['region'])
+        
+        # specific items
+        try:
+            mltype = self.GetPyData(self.layer_selected)[0]['type']
+        except:
+            mltype = None
+        
+        # vector layers (specific items)
+        if mltype and mltype == "vector":
+            self.popupMenu.AppendSeparator()
+            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
+            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['v.out.ogr',
+                                                                        'input=%s' % mapLayer.GetName()]),
+                      id = self.popupID['export'])
+            
+            self.popupMenu.AppendSeparator()
+
+            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
+            self.Bind (wx.EVT_MENU, self.OnVectorColorTable, id = self.popupID['color'])
+
+            self.popupMenu.Append(self.popupID['attr'], text = _("Show attribute data"))
+            self.Bind(wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id = self.popupID['attr'])
+
+            self.popupMenu.Append(self.popupID['edit0'], text = _("Start editing"))
+            self.popupMenu.Append(self.popupID['edit1'], text = _("Stop editing"))
+            self.popupMenu.Enable(self.popupID['edit1'], False)
+            self.Bind (wx.EVT_MENU, self.OnStartEditing, id = self.popupID['edit0'])
+            self.Bind (wx.EVT_MENU, self.OnStopEditing,  id = self.popupID['edit1'])
+            
+            layer = self.GetPyData(self.layer_selected)[0]['maplayer']
+            # enable editing only for vector map layers available in the current mapset
+            digitToolbar = self.mapdisplay.GetToolbar('vdigit')
+            if digitToolbar:
+                # background vector map
+                self.popupMenu.Append(self.popupID['bgmap'],
+                                      text = _("Use as background vector map for digitizer"),
+                                      kind = wx.ITEM_CHECK)
+                self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap'])
+                if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
+                                    internal = True) == layer.GetName():
+                    self.popupMenu.Check(self.popupID['bgmap'], True)
+            
+            self.popupMenu.Append(self.popupID['topo'], text = _("Rebuild topology"))
+            self.Bind(wx.EVT_MENU, self.OnTopology, id = self.popupID['topo'])
+
+            # determine format
+            if layer and layer.GetType() == 'vector':
+                if 'info' not in self.GetPyData(self.layer_selected)[0]:
+                    info = grass.parse_command('v.info',
+                                               flags = 'g',
+                                               map = layer.GetName())
+                    self.GetPyData(self.layer_selected)[0]['info'] = info
+                info = self.GetPyData(self.layer_selected)[0]['info']
+                if info and info['format'] == 'ogr,PostgreSQL':
+                    self.popupMenu.Append(self.popupID['sql'], text = _("SQL Spatial Query"))
+                    self.Bind(wx.EVT_MENU, self.OnSqlQuery, id = self.popupID['sql'])
+            
+            if layer.GetMapset() != grass.gisenv()['MAPSET']:
+                # only vector map in current mapset can be edited
+                self.popupMenu.Enable (self.popupID['edit0'], False)
+                self.popupMenu.Enable (self.popupID['edit1'], False)
+                self.popupMenu.Enable (self.popupID['topo'], False)
+            elif digitToolbar and digitToolbar.GetLayer():
+                # vector map already edited
+                vdigitLayer = digitToolbar.GetLayer()
+                if vdigitLayer is layer:
+                    self.popupMenu.Enable(self.popupID['edit0'],  False)
+                    self.popupMenu.Enable(self.popupID['edit1'],  True)
+                    self.popupMenu.Enable(self.popupID['remove'], False)
+                    self.popupMenu.Enable(self.popupID['bgmap'],  False)
+                    self.popupMenu.Enable(self.popupID['topo'],   False)
+                else:
+                    self.popupMenu.Enable(self.popupID['edit0'], False)
+                    self.popupMenu.Enable(self.popupID['edit1'], False)
+                    self.popupMenu.Enable(self.popupID['bgmap'], True)
+            
+            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
+            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
+            if numSelected > 1:
+                self.popupMenu.Enable(self.popupID['attr'],   False)
+                self.popupMenu.Enable(self.popupID['edit0'],  False)
+                self.popupMenu.Enable(self.popupID['edit1'],  False)
+                self.popupMenu.Enable(self.popupID['meta'],   False)
+                self.popupMenu.Enable(self.popupID['bgmap'],  False)
+                self.popupMenu.Enable(self.popupID['topo'],   False)
+                self.popupMenu.Enable(self.popupID['export'], False)
+        
+        # raster layers (specific items)
+        elif mltype and mltype == "raster":
+            self.popupMenu.Append(self.popupID['zoom1'], text = _("Zoom to selected map(s) (ignore NULLs)"))
+            self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id = self.popupID['zoom1'])
+            self.popupMenu.Append(self.popupID['region1'], text = _("Set computational region from selected map(s) (ignore NULLs)"))
+            self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id = self.popupID['region1'])
+            
+            self.popupMenu.AppendSeparator()
+            self.popupMenu.Append(self.popupID['export'], text = _("Export"))
+            self.Bind(wx.EVT_MENU, lambda x: self.lmgr.OnMenuCmd(cmd = ['r.out.gdal',
+                                                                        'input=%s' % mapLayer.GetName()]),
+                      id = self.popupID['export'])
+            
+            self.popupMenu.AppendSeparator()
+            self.popupMenu.Append(self.popupID['color'], _("Set color table"))
+            self.Bind (wx.EVT_MENU, self.OnRasterColorTable, id = self.popupID['color'])
+            self.popupMenu.Append(self.popupID['hist'], _("Histogram"))
+            self.Bind (wx.EVT_MENU, self.OnHistogram, id = self.popupID['hist'])
+            self.popupMenu.Append(self.popupID['univar'], _("Univariate raster statistics"))
+            self.Bind (wx.EVT_MENU, self.OnUnivariateStats, id = self.popupID['univar'])
+            self.popupMenu.Append(self.popupID['prof'], _("Profile"))
+            self.Bind (wx.EVT_MENU, self.OnProfile, id = self.popupID['prof'])
+            self.popupMenu.Append(self.popupID['meta'], _("Metadata"))
+            self.Bind (wx.EVT_MENU, self.OnMetadata, id = self.popupID['meta'])
+            
+            if numSelected > 1:
+                self.popupMenu.Enable(self.popupID['zoom1'],   False)
+                self.popupMenu.Enable(self.popupID['region1'], False)
+                self.popupMenu.Enable(self.popupID['color'],   False)
+                self.popupMenu.Enable(self.popupID['hist'],    False)
+                self.popupMenu.Enable(self.popupID['univar'],  False)
+                self.popupMenu.Enable(self.popupID['prof'],    False)
+                self.popupMenu.Enable(self.popupID['meta'],    False)
+                self.popupMenu.Enable(self.popupID['nviz'],    False)
+                self.popupMenu.Enable(self.popupID['export'],  False)
+
+        self.PopupMenu(self.popupMenu)
+        self.popupMenu.Destroy()
+        
+    def OnTopology(self, event):
+        """!Rebuild topology of selected vector map"""
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        cmd = ['v.build',
+               'map=%s' % mapLayer.GetName()]
+        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
+        
+    def OnSqlQuery(self, event):
+        """!Show SQL query window for PostGIS layers
+        """
+        dlg = SqlQueryFrame(parent = self)
+        dlg.CentreOnScreen()
+        dlg.Show()
+        
+    def OnMetadata(self, event):
+        """!Print metadata of raster/vector map layer
+        TODO: Dialog to modify metadata
+        """
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        mltype = self.GetPyData(self.layer_selected)[0]['type']
+
+        if mltype == 'raster':
+            cmd = ['r.info']
+        elif mltype == 'vector':
+            cmd = ['v.info']
+        cmd.append('map=%s' % mapLayer.GetName())
+
+        # print output to command log area
+        self.lmgr.goutput.RunCmd(cmd, switchPage = True)
+
+    def OnSetCompRegFromRaster(self, event):
+        """!Set computational region from selected raster map (ignore NULLs)"""
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        
+        cmd = ['g.region',
+               '-p',
+               'zoom=%s' % mapLayer.GetName()]
+        
+        # print output to command log area
+        self.lmgr.goutput.RunCmd(cmd)
+         
+    def OnSetCompRegFromMap(self, event):
+        """!Set computational region from selected raster/vector map
+        """
+        rast = []
+        vect = []
+        rast3d = []
+        for layer in self.GetSelections():
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            mltype = self.GetPyData(layer)[0]['type']
+                
+            if mltype == 'raster':
+                rast.append(mapLayer.GetName())
+            elif mltype == 'vector':
+                vect.append(mapLayer.GetName())
+            elif mltype == '3d-raster':
+                rast3d.append(mapLayer.GetName())
+            elif mltype == 'rgb':
+                for rname in mapLayer.GetName().splitlines():
+                    rast.append(rname)
+        
+        cmd = ['g.region']
+        if rast:
+            cmd.append('rast=%s' % ','.join(rast))
+        if vect:
+            cmd.append('vect=%s' % ','.join(vect))
+        if rast3d:
+            cmd.append('rast3d=%s' % ','.join(rast3d))
+        
+        # print output to command log area
+        if len(cmd) > 1:
+            cmd.append('-p')
+            self.lmgr.goutput.RunCmd(cmd)
+        
+    def OnProfile(self, event):
+        """!Plot profile of given raster map layer"""
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        if not mapLayer.GetName():
+            wx.MessageBox(parent = self,
+                          message = _("Unable to create profile of "
+                                    "raster map."),
+                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return False
+
+        if not hasattr (self, "profileFrame"):
+            self.profileFrame = None
+
+        if hasattr (self.mapdisplay, "profile") and self.mapdisplay.profile:
+            self.profileFrame = self.mapdisplay.profile
+
+        if not self.profileFrame:
+            self.profileFrame = ProfileFrame(parent = self.mapdisplay,
+                                             rasterList = [mapLayer.GetName()])
+            # show new display
+            self.profileFrame.Show()
+        
+    def OnRasterColorTable(self, event):
+        """!Set color table for raster map"""
+        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+        GUI(parent = self, centreOnParent = False).ParseCommand(['r.colors',
+                                                                 'map=%s' % name])
+
+    def OnVectorColorTable(self, event):
+        """!Set color table for vector map"""
+        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+        GUI(parent = self, centreOnParent = False).ParseCommand(['v.colors',
+                                                                 'map=%s' % name])
+        
+    def OnHistogram(self, event):
+        """
+        Plot histogram for given raster map layer
+        """
+        mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        if not mapLayer.GetName():
+            wx.MessageBox(parent = self,
+                          message = _("Unable to display histogram of "
+                                    "raster map."),
+                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            return False
+
+        if not hasattr (self, "histogramFrame"):
+            self.histogramFrame = None
+
+        if hasattr (self.mapdisplay, "histogram") and self.mapdisplay.histogram:
+            self.histogramFrame = self.mapdisplay.histogram
+
+        if not self.histogramFrame:
+            self.histogramFrame = HistFrame(self, size = globalvar.HIST_WINDOW_SIZE,
+                                            style = wx.DEFAULT_FRAME_STYLE)
+            self.histogramFrame.CentreOnScreen()
+            # show new display
+            self.histogramFrame.Show()
+
+        self.histogramFrame.SetHistLayer(mapLayer.GetName())
+        self.histogramFrame.HistWindow.UpdateHist()
+        self.histogramFrame.Refresh()
+        self.histogramFrame.Update()
+
+        return True
+
+    def OnUnivariateStats(self, event):
+        """!Univariate raster statistics"""
+        name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+        GUI(parent = self).ParseCommand(['r.univar',
+                                         'map=%s' % name])
+
+    def OnStartEditing(self, event):
+        """!Start editing vector map layer requested by the user
+        """
+        try:
+            maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        except:
+            event.Skip()
+            return
+        
+        if not haveVDigit:
+            from vdigit import errorMsg
+            msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
+                    "TCL/TK digitizer (v.digit) instead?\n\n"
+                    "Details: %s" % errorMsg)
+            
+            self.mapdisplay.toolbars['map'].combo.SetValue (_("2D view"))
+            dlg = wx.MessageDialog(parent = self.mapdisplay,
+                                   message = msg,
+                                   caption=_("Vector digitizer failed"),
+                                   style = wx.YES_NO | wx.CENTRE)
+            if dlg.ShowModal() == wx.ID_YES:
+                self.lmgr.goutput.RunCmd(['v.digit', 'map=%s' % maplayer.GetName()],
+                                         switchPage = False)
+            
+            dlg.Destroy()
+            return
+        
+        if not self.mapdisplay.GetToolbar('vdigit'): # enable tool
+            self.mapdisplay.AddToolbar('vdigit')
+        else: # tool already enabled
+            pass
+        
+        # mark layer as 'edited'
+        self.mapdisplay.toolbars['vdigit'].StartEditing(maplayer)
+        
+        self._setGradient('vdigit')
+        self.RefreshLine(self.layer_selected)
+        
+    def OnStopEditing(self, event):
+        """!Stop editing the current vector map layer
+        """
+        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        
+        self.mapdisplay.toolbars['vdigit'].OnExit()
+        if self.lmgr:
+            self.lmgr.toolbars['tools'].Enable('vdigit', enable = True)
+        
+        self._setGradient()
+        self.RefreshLine(self.layer_selected)
+        
+    def OnSetBgMap(self, event):
+        """!Set background vector map for editing sesstion"""
+        digit = self.mapdisplay.GetWindow().digit
+        if event.IsChecked():
+            mapName = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
+                             value = str(mapName), internal = True)
+            digit.OpenBackgroundMap(mapName)
+            self._setGradient('bgmap')
+        else:
+            UserSettings.Set(group = 'vdigit', key = 'bgmap', subkey = 'value',
+                             value = '', internal = True)
+            digit.CloseBackgroundMap()
+            self._setGradient()
+        
+        self.RefreshLine(self.layer_selected)
+
+    def OnPopupProperties (self, event):
+        """!Popup properties dialog"""
+        self.PropertiesDialog(self.layer_selected)
+
+    def OnPopupOpacityLevel(self, event):
+        """!Popup opacity level indicator"""
+        if not self.GetPyData(self.layer_selected)[0]['ctrl']:
+            return
+        
+        maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+        current_opacity = maplayer.GetOpacity()
+        
+        dlg = SetOpacityDialog(self, opacity = current_opacity,
+                               title = _("Set opacity <%s>") % maplayer.GetName())
+        dlg.CentreOnParent()
+
+        if dlg.ShowModal() == wx.ID_OK:
+            new_opacity = dlg.GetOpacity() # string
+            self.Map.ChangeOpacity(maplayer, new_opacity)
+            maplayer.SetOpacity(new_opacity)
+            self.SetItemText(self.layer_selected,
+                             self._getLayerName(self.layer_selected))
+            
+            # vector layer currently edited
+            if self.mapdisplay.GetToolbar('vdigit') and \
+                    self.mapdisplay.GetToolbar('vdigit').GetLayer() == maplayer:   
+                alpha = int(new_opacity * 255)
+                self.mapdisplay.GetWindow().digit.GetDisplay().UpdateSettings(alpha = alpha)
+                
+            # redraw map if auto-rendering is enabled
+            self.rerender = True
+            self.reorder = True
+
+    def OnNvizProperties(self, event):
+        """!Nviz-related properties (raster/vector/volume)
+
+        @todo vector/volume
+        """
+        self.lmgr.notebook.SetSelectionByName('nviz')
+        ltype = self.GetPyData(self.layer_selected)[0]['type']
+        if ltype == 'raster':
+            self.lmgr.nviz.SetPage('surface')
+        elif ltype == 'vector':
+            self.lmgr.nviz.SetPage('vector')
+        elif ltype == '3d-raster':
+            self.lmgr.nviz.SetPage('volume')
+        
+    def OnRenameLayer (self, event):
+        """!Rename layer"""
+        self.EditLabel(self.layer_selected)
+        self.GetEditControl().SetSelection(-1, -1)
+        
+    def OnRenamed(self, event):
+        """!Layer renamed"""
+        if not event.GetLabel():
+            event.Skip()
+            return
+        
+        item = self.layer_selected
+        self.GetPyData(item)[0]['label'] = event.GetLabel()
+        self.SetItemText(item, self._getLayerName(item))
+        
+        event.Skip()
+
+    def AddLayer(self, ltype, lname = None, lchecked = None,
+                 lopacity = 1.0, lcmd = None, lgroup = None, lvdigit = None, lnviz = None, multiple = True):
+        """!Add new item to the layer tree, create corresponding MapLayer instance.
+        Launch property dialog if needed (raster, vector, etc.)
+
+        @param ltype layer type (raster, vector, 3d-raster, ...)
+        @param lname layer name
+        @param lchecked if True layer is checked
+        @param lopacity layer opacity level
+        @param lcmd command (given as a list)
+        @param lgroup index of group item (-1 for root) or None
+        @param lvdigit vector digitizer settings (eg. geometry attributes)
+        @param lnviz layer Nviz properties
+        @param multiple True to allow multiple map layers in layer tree
+        """
+        if lname and not multiple:
+            # check for duplicates
+            item = self.GetFirstVisibleItem()
+            while item and item.IsOk():
+                if self.GetPyData(item)[0]['type'] == 'vector':
+                    name = self.GetPyData(item)[0]['maplayer'].GetName()
+                    if name == lname:
+                        return
+                item = self.GetNextVisible(item)
+        
+        self.first = True
+        params = {} # no initial options parameters
+        
+        # deselect active item
+        if self.layer_selected:
+            self.SelectItem(self.layer_selected, select = False)
+        
+        Debug.msg (3, "LayerTree().AddLayer(): ltype=%s" % (ltype))
+        
+        if ltype == 'command':
+            # generic command item
+            ctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
+                               pos = wx.DefaultPosition, size = (self.GetSize()[0]-100,25),
+                               # style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
+                               style = wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
+            ctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
+            # ctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
+        elif ltype == 'group':
+            # group item
+            ctrl = None
+            grouptext = _('Layer group:') + str(self.groupnode)
+            self.groupnode += 1
+        else:
+            btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
+            ctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24,24))
+            ctrl.SetToolTipString(_("Click to edit layer settings"))
+            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, ctrl)
+        # add layer to the layer tree
+        if self.layer_selected and self.layer_selected != self.GetRootItem():
+            if self.GetPyData(self.layer_selected)[0]['type'] == 'group' \
+                and self.IsExpanded(self.layer_selected):
+                # add to group (first child of self.layer_selected) if group expanded
+                layer = self.PrependItem(parent = self.layer_selected,
+                                         text = '', ct_type = 1, wnd = ctrl)
+            else:
+                # prepend to individual layer or non-expanded group
+                if lgroup == -1:
+                    # -> last child of root (loading from workspace)
+                    layer = self.AppendItem(parentId = self.root,
+                                            text = '', ct_type = 1, wnd = ctrl)
+                elif lgroup > -1:
+                    # -> last child of group (loading from workspace)
+                    parent = self.FindItemByIndex(index = lgroup)
+                    if not parent:
+                        parent = self.root
+                    layer = self.AppendItem(parentId = parent,
+                                            text = '', ct_type = 1, wnd = ctrl)
+                elif lgroup is None:
+                    # -> previous sibling of selected layer
+                    parent = self.GetItemParent(self.layer_selected)
+                    layer = self.InsertItem(parentId = parent,
+                                            input = self.GetPrevSibling(self.layer_selected),
+                                            text = '', ct_type = 1, wnd = ctrl)
+        else: # add first layer to the layer tree (first child of root)
+            layer = self.PrependItem(parent = self.root, text = '', ct_type = 1, wnd = ctrl)
+        
+        # layer is initially unchecked as inactive (beside 'command')
+        # use predefined value if given
+        if lchecked is not None:
+            checked = lchecked
+        else:
+            checked = True
+        
+        self.CheckItem(layer, checked = checked)
+        
+        # add text and icons for each layer ltype
+        label =  _('(double click to set properties)') + ' ' * 15
+        if ltype == 'raster':
+            self.SetItemImage(layer, self.rast_icon)
+            self.SetItemText(layer, '%s %s' % (_('raster'), label))
+        elif ltype == '3d-raster':
+            self.SetItemImage(layer, self.rast3d_icon)
+            self.SetItemText(layer, '%s %s' % (_('3D raster'), label))
+        elif ltype == 'rgb':
+            self.SetItemImage(layer, self.rgb_icon)
+            self.SetItemText(layer, '%s %s' % (_('RGB'), label))
+        elif ltype == 'his':
+            self.SetItemImage(layer, self.his_icon)
+            self.SetItemText(layer, '%s %s' % (_('HIS'), label))
+        elif ltype == 'shaded':
+            self.SetItemImage(layer, self.shaded_icon)
+            self.SetItemText(layer, '%s %s' % (_('shaded relief'), label))
+        elif ltype == 'rastnum':
+            self.SetItemImage(layer, self.rnum_icon)
+            self.SetItemText(layer, '%s %s' % (_('raster cell numbers'), label))
+        elif ltype == 'rastarrow':
+            self.SetItemImage(layer, self.rarrow_icon)
+            self.SetItemText(layer, '%s %s' % (_('raster flow arrows'), label))
+        elif ltype == 'vector':
+            self.SetItemImage(layer, self.vect_icon)
+            self.SetItemText(layer, '%s %s' % (_('vector'), label))
+        elif ltype == 'thememap':
+            self.SetItemImage(layer, self.theme_icon)
+            self.SetItemText(layer, '%s %s' % (_('thematic area (choropleth) map'), label))
+        elif ltype == 'themechart':
+            self.SetItemImage(layer, self.chart_icon)
+            self.SetItemText(layer, '%s %s' % (_('thematic charts'), label))
+        elif ltype == 'grid':
+            self.SetItemImage(layer, self.grid_icon)
+            self.SetItemText(layer, '%s %s' % (_('grid'), label))
+        elif ltype == 'geodesic':
+            self.SetItemImage(layer, self.geodesic_icon)
+            self.SetItemText(layer, '%s %s' % (_('geodesic line'), label))
+        elif ltype == 'rhumb':
+            self.SetItemImage(layer, self.rhumb_icon)
+            self.SetItemText(layer, '%s %s' % (_('rhumbline'), label))
+        elif ltype == 'labels':
+            self.SetItemImage(layer, self.labels_icon)
+            self.SetItemText(layer, '%s %s' % (_('vector labels'), label))
+        elif ltype == 'command':
+            self.SetItemImage(layer, self.cmd_icon)
+        elif ltype == 'group':
+            self.SetItemImage(layer, self.folder)
+            self.SetItemText(layer, grouptext)
+        
+        self.first = False
+        
+        if ltype != 'group':
+            if lcmd and len(lcmd) > 1:
+                cmd = lcmd
+                render = False
+                name, found = GetLayerNameFromCmd(lcmd)
+            else:
+                cmd = []
+                if ltype == 'command' and lname:
+                    for c in lname.split(';'):
+                        cmd.append(c.split(' '))
+                
+                render = False
+                name = None
+            
+            if ctrl:
+                ctrlId = ctrl.GetId()
+            else:
+                ctrlId = None
+            
+            # add a data object to hold the layer's command (does not apply to generic command layers)
+            self.SetPyData(layer, ({'cmd'      : cmd,
+                                    'type'     : ltype,
+                                    'ctrl'     : ctrlId,
+                                    'label'    : None,
+                                    'maplayer' : None,
+                                    'vdigit'   : lvdigit,
+                                    'nviz'     : lnviz,
+                                    'propwin'  : None}, 
+                                   None))
+            
+            # find previous map layer instance 
+            prevItem = self.GetFirstChild(self.root)[0]
+            prevMapLayer = None 
+            pos = -1
+            while prevItem and prevItem.IsOk() and prevItem != layer: 
+                if self.GetPyData(prevItem)[0]['maplayer']: 
+                    prevMapLayer = self.GetPyData(prevItem)[0]['maplayer'] 
+                
+                prevItem = self.GetNextSibling(prevItem) 
+                
+                if prevMapLayer: 
+                    pos = self.Map.GetLayerIndex(prevMapLayer)
+                else: 
+                    pos = -1
+            
+            maplayer = self.Map.AddLayer(pos = pos,
+                                         type = ltype, command = self.GetPyData(layer)[0]['cmd'], name = name,
+                                         l_active = checked, l_hidden = False,
+                                         l_opacity = lopacity, l_render = render)
+            self.GetPyData(layer)[0]['maplayer'] = maplayer
+            
+            # run properties dialog if no properties given
+            if len(cmd) == 0:
+                self.PropertiesDialog(layer, show = True)
+        
+        else: # group
+            self.SetPyData(layer, ({'cmd'      : None,
+                                    'type'     : ltype,
+                                    'ctrl'     : None,
+                                    'label'    : None,
+                                    'maplayer' : None,
+                                    'propwin'  : None}, 
+                                   None))
+        
+        # select new item
+        self.SelectItem(layer, select = True)
+        self.layer_selected = layer
+        
+        # use predefined layer name if given
+        if lname:
+            if ltype == 'group':
+                self.SetItemText(layer, lname)
+            elif ltype == 'command':
+                ctrl.SetValue(lname)
+            else:
+                self.SetItemText(layer, self._getLayerName(layer, lname))
+        else:
+            if ltype == 'group':
+                self.OnRenameLayer(None)
+        
+        # updated progress bar range (mapwindow statusbar)
+        if checked:
+            self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
+        
+        return layer
+
+    def PropertiesDialog (self, layer, show = True):
+        """!Launch the properties dialog"""
+        if 'propwin' in self.GetPyData(layer)[0] and \
+                self.GetPyData(layer)[0]['propwin'] is not None:
+            # recycle GUI dialogs
+            win = self.GetPyData(layer)[0]['propwin']
+            # update properties (columns, layers)
+            win.notebookpanel.OnUpdateSelection(None)
+            if win.IsShown():
+                win.SetFocus()
+            else:
+                win.Show()
+            
+            return
+        
+        completed = ''
+        params = self.GetPyData(layer)[1]
+        ltype  = self.GetPyData(layer)[0]['type']
+                
+        Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
+                   ltype)
+        
+        if self.GetPyData(layer)[0]['cmd']:
+            module = GUI(parent = self, show = show, centreOnParent = False)
+            module.ParseCommand(self.GetPyData(layer)[0]['cmd'],
+                                completed = (self.GetOptData,layer,params))
+            
+            self.GetPyData(layer)[0]['cmd'] = module.GetCmd()
+        elif ltype == 'raster':
+            cmd = ['d.rast']
+            
+            if UserSettings.Get(group = 'cmd', key = 'rasterOpaque', subkey = 'enabled'):
+                cmd.append('-n')
+            GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
+                                                                    completed = (self.GetOptData,layer,params))
+                         
+        elif ltype == '3d-raster':
+            cmd = ['d.rast3d']
+            GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
+                                                                    completed = (self.GetOptData,layer,params))
+                                        
+        elif ltype == 'rgb':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.rgb'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'his':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.his'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'shaded':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.shadedmap'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'rastarrow':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.arrow'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'rastnum':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.rast.num'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'vector':
+            types = list()
+            for ftype in ['point', 'line', 'boundary', 'centroid', 'area', 'face']:
+                if UserSettings.Get(group = 'cmd', key = 'showType', subkey = [ftype, 'enabled']):
+                    types.append(ftype)
+            
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect', 'type=%s' % ','.join(types)],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'thememap':
+            # -s flag requested, otherwise only first thematic category is displayed
+            # should be fixed by C-based d.thematic.* modules
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.thematic.area'], 
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'themechart':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.vect.chart'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'grid':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.grid'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'geodesic':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.geodesic'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'rhumb':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.rhumbline'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'labels':
+            GUI(parent = self, centreOnParent = False).ParseCommand(['d.labels'],
+                                                                    completed = (self.GetOptData,layer,params))
+            
+        elif ltype == 'cmdlayer':
+            pass
+        elif ltype == 'group':
+            pass
+        
+    def OnActivateLayer(self, event):
+        """!Double click on the layer item.
+        Launch property dialog, or expand/collapse group of items, etc.
+        """
+        self.lmgr.WorkspaceChanged()
+        layer = event.GetItem()
+        self.layer_selected = layer
+        
+        self.PropertiesDialog(layer)
+        
+        if self.GetPyData(layer)[0]['type'] == 'group':
+            if self.IsExpanded(layer):
+                self.Collapse(layer)
+            else:
+                self.Expand(layer)
+        
+    def OnDeleteLayer(self, event):
+        """!Remove selected layer item from the layer tree"""
+        self.lmgr.WorkspaceChanged()
+        item = event.GetItem()
+        
+        try:
+            item.properties.Close(True)
+        except:
+            pass
+
+        if item != self.root:
+            Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \
+                           (self.GetItemText(item)))
+        else:
+            self.root = None
+
+        # unselect item
+        self.Unselect()
+        self.layer_selected = None
+
+        try:
+            if self.GetPyData(item)[0]['type'] != 'group':
+                self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer'])
+        except:
+            pass
+
+        # redraw map if auto-rendering is enabled
+        self.rerender = True
+        self.reorder = True
+        
+        if self.mapdisplay.GetToolbar('vdigit'):
+            self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers (updateTool = True)
+
+        # update progress bar range (mapwindow statusbar)
+        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
+
+        #
+        # nviz
+        #
+        if self.lmgr.IsPaneShown('toolbarNviz') and \
+                self.GetPyData(item) is not None and not self.rerender:
+            # nviz - load/unload data layer
+            mapLayer = self.GetPyData(item)[0]['maplayer']
+            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
+            if mapLayer.type == 'raster':
+                self.mapdisplay.MapWindow.UnloadRaster(item)
+            elif mapLayer.type == '3d-raster':
+                self.mapdisplay.MapWindow.UnloadRaster3d(item)
+            elif mapLayer.type == 'vector':
+                self.mapdisplay.MapWindow.UnloadVector(item)
+            self.mapdisplay.SetStatusText("", 0)
+            
+        event.Skip()
+
+    def OnLayerChecked(self, event):
+        """!Enable/disable data layer"""
+        self.lmgr.WorkspaceChanged()
+        
+        item    = event.GetItem()
+        checked = item.IsChecked()
+        
+        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
+        if not self.first:
+            # change active parameter for item in layers list in render.Map
+            if self.GetPyData(item)[0]['type'] == 'group':
+                child, cookie = self.GetFirstChild(item)
+                while child:
+                    self.CheckItem(child, checked)
+                    mapLayer = self.GetPyData(child)[0]['maplayer']
+                    if not digitToolbar or \
+                           (digitToolbar and digitToolbar.GetLayer() != mapLayer):
+                        # ignore when map layer is edited
+                        self.Map.ChangeLayerActive(mapLayer, checked)
+                    child = self.GetNextSibling(child)
+            else:
+                mapLayer = self.GetPyData(item)[0]['maplayer']
+                if not digitToolbar or \
+                       (digitToolbar and digitToolbar.GetLayer() != mapLayer):
+                    # ignore when map layer is edited
+                    self.Map.ChangeLayerActive(mapLayer, checked)
+        
+        self.Unselect()
+        
+        # update progress bar range (mapwindow statusbar)
+        self.mapdisplay.GetProgressBar().SetRange(len(self.Map.GetListOfLayers(l_active = True)))
+        
+        # nviz
+        if self.lmgr.IsPaneShown('toolbarNviz') and \
+                self.GetPyData(item) is not None:
+            # nviz - load/unload data layer
+            mapLayer = self.GetPyData(item)[0]['maplayer']
+
+            self.mapdisplay.SetStatusText(_("Please wait, updating data..."), 0)
+
+            if checked: # enable
+                if mapLayer.type == 'raster':
+                    self.mapdisplay.MapWindow.LoadRaster(item)
+                elif mapLayer.type == '3d-raster':
+                    self.mapdisplay.MapWindow.LoadRaster3d(item)
+                elif mapLayer.type == 'vector':
+                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(mapLayer)
+                    if npoints > 0:
+                        self.mapdisplay.MapWindow.LoadVector(item, points = True)
+                    if nlines > 0:
+                        self.mapdisplay.MapWindow.LoadVector(item, points = False)
+
+            else: # disable
+                if mapLayer.type == 'raster':
+                    self.mapdisplay.MapWindow.UnloadRaster(item)
+                elif mapLayer.type == '3d-raster':
+                    self.mapdisplay.MapWindow.UnloadRaster3d(item)
+                elif mapLayer.type == 'vector':
+                    self.mapdisplay.MapWindow.UnloadVector(item)
+            
+            self.mapdisplay.SetStatusText("", 0)
+        
+        # redraw map if auto-rendering is enabled
+        self.rerender = True
+        self.reorder = True
+        
+    def OnCmdChanged(self, event):
+        """!Change command string"""
+        ctrl = event.GetEventObject().GetId()
+        cmd = event.GetString()
+        
+        layer = self.GetFirstVisibleItem()
+
+        while layer and layer.IsOk():
+            if self.GetPyData(layer)[0]['ctrl'] == ctrl:
+                break
+            
+            layer = self.GetNextVisible(layer)
+
+        # change parameters for item in layers list in render.Map
+        self.ChangeLayer(layer)
+        
+        event.Skip()
+
+    def OnChangeSel(self, event):
+        """!Selection changed"""
+        oldlayer = event.GetOldItem()
+        layer = event.GetItem()
+        if layer == oldlayer:
+            event.Veto()
+            return
+        
+        digitToolbar = self.mapdisplay.GetToolbar('vdigit')
+        if digitToolbar:
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            bgmap = UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value',
+                                     internal = True)
+            
+            if digitToolbar.GetLayer() == mapLayer:
+                self._setGradient('vdigit')
+            elif bgmap == mapLayer.GetName():
+                self._setGradient('bgmap')
+            else:
+                self._setGradient()
+        else:
+            self._setGradient()
+        
+        self.layer_selected = layer
+        
+        try:
+            if self.IsSelected(oldlayer):
+                self.SetItemWindowEnabled(oldlayer, True)
+            else:
+                self.SetItemWindowEnabled(oldlayer, False)
+
+            if self.IsSelected(layer):
+                self.SetItemWindowEnabled(layer, True)
+            else:
+                self.SetItemWindowEnabled(layer, False)
+        except:
+            pass
+        
+        try:
+            self.RefreshLine(oldlayer)
+            self.RefreshLine(layer)
+        except:
+            pass
+        
+        # update statusbar -> show command string
+        if self.GetPyData(layer) and self.GetPyData(layer)[0]['maplayer']:
+            cmd = self.GetPyData(layer)[0]['maplayer'].GetCmd(string = True)
+            if len(cmd) > 0:
+                self.lmgr.SetStatusText(cmd)
+        
+        # set region if auto-zooming is enabled
+        if self.GetPyData(layer) and self.GetPyData(layer)[0]['cmd'] and \
+               UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            if mapLayer.GetType() in ('raster', 'vector'):
+                render = self.mapdisplay.IsAutoRendered()
+                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
+                                                    render = render)
+        
+        # update nviz tools
+        if self.lmgr.IsPaneShown('toolbarNviz') and \
+                self.GetPyData(self.layer_selected) is not None:
+            if self.layer_selected.IsChecked():
+                # update Nviz tool window
+                type = self.GetPyData(self.layer_selected)[0]['maplayer'].type
+                
+                if type == 'raster':
+                    self.lmgr.nviz.UpdatePage('surface')
+                    self.lmgr.nviz.SetPage('surface')
+                elif type == 'vector':
+                    self.lmgr.nviz.UpdatePage('vector')
+                    self.lmgr.nviz.SetPage('vector')
+                elif type == '3d-raster':
+                    self.lmgr.nviz.UpdatePage('volume')
+                    self.lmgr.nviz.SetPage('volume')
+        
+    def OnCollapseNode(self, event):
+        """!Collapse node
+        """
+        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
+            self.SetItemImage(self.layer_selected, self.folder)
+
+    def OnExpandNode(self, event):
+        """!Expand node
+        """
+        self.layer_selected = event.GetItem()
+        if self.GetPyData(self.layer_selected)[0]['type'] == 'group':
+            self.SetItemImage(self.layer_selected, self.folder_open)
+    
+    def OnEndDrag(self, event):
+        self.StopDragging()
+        dropTarget = event.GetItem()
+        self.flag = self.HitTest(event.GetPoint())[1]
+        if self.lmgr.IsPaneShown('toolbarNviz'):
+            self.mapdisplay.MapWindow.UnloadDataLayers(True)
+        if self.IsValidDropTarget(dropTarget):
+            self.UnselectAll()
+            if dropTarget != None:
+                self.SelectItem(dropTarget)
+            self.OnDrop(dropTarget, self._dragItem)
+        elif dropTarget == None:
+            self.OnDrop(dropTarget, self._dragItem)
+            
+    def OnDrop(self, dropTarget, dragItem):
+        # save everthing associated with item to drag
+        try:
+            old = dragItem  # make sure this member exists
+        except:
+            return
+
+        Debug.msg (4, "LayerTree.OnDrop(): layer=%s" % \
+                   (self.GetItemText(dragItem)))
+        
+        # recreate data layer, insert copy of layer in new position, and delete original at old position
+        newItem  = self.RecreateItem (dragItem, dropTarget)
+
+        # if recreated layer is a group, also recreate its children
+        if  self.GetPyData(newItem)[0]['type'] == 'group':
+            (child, cookie) = self.GetFirstChild(dragItem)
+            if child:
+                while child:
+                    self.RecreateItem(child, dropTarget, parent = newItem)
+                    self.Delete(child)
+                    child = self.GetNextChild(old, cookie)[0]
+        
+        # delete layer at original position
+        try:
+            self.Delete(old) # entry in render.Map layers list automatically deleted by OnDeleteLayer handler
+        except AttributeError:
+            pass
+
+        # redraw map if auto-rendering is enabled
+        self.rerender = True
+        self.reorder = True
+        
+        # select new item
+        self.SelectItem(newItem)
+        
+    def RecreateItem (self, dragItem, dropTarget, parent = None):
+        """!Recreate item (needed for OnEndDrag())
+        """
+        Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \
+                   self.GetItemText(dragItem))
+
+        # fetch data (dragItem)
+        checked = self.IsItemChecked(dragItem)
+        image   = self.GetItemImage(dragItem, 0)
+        text    = self.GetItemText(dragItem)
+        if self.GetPyData(dragItem)[0]['ctrl']:
+            # recreate data layer
+            btnbmp = Icons['layerManager']["layerOptions"].GetBitmap((16,16))
+            newctrl = buttons.GenBitmapButton(self, id = wx.ID_ANY, bitmap = btnbmp, size = (24, 24))
+            newctrl.SetToolTipString(_("Click to edit layer settings"))
+            self.Bind(wx.EVT_BUTTON, self.OnLayerContextMenu, newctrl)
+            data    = self.GetPyData(dragItem)
+        
+        elif self.GetPyData(dragItem)[0]['type'] == 'command':
+            # recreate command layer
+            oldctrl = None
+            newctrl = wx.TextCtrl(self, id = wx.ID_ANY, value = '',
+                                  pos = wx.DefaultPosition, size = (250,25),
+                                  style = wx.TE_MULTILINE|wx.TE_WORDWRAP)
+            try:
+                newctrl.SetValue(self.GetPyData(dragItem)[0]['maplayer'].GetCmd(string = True))
+            except:
+                pass
+            newctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
+            newctrl.Bind(wx.EVT_TEXT,       self.OnCmdChanged)
+            data    = self.GetPyData(dragItem)
+
+        elif self.GetPyData(dragItem)[0]['type'] == 'group':
+            # recreate group
+            newctrl = None
+            data    = None
+            
+        # decide where to put recreated item
+        if dropTarget != None and dropTarget != self.GetRootItem():
+            if parent:
+                # new item is a group
+                afteritem = parent
+            else:
+                # new item is a single layer
+                afteritem = dropTarget
+
+            # dragItem dropped on group
+            if  self.GetPyData(afteritem)[0]['type'] == 'group':
+                newItem = self.PrependItem(afteritem, text = text, \
+                                      ct_type = 1, wnd = newctrl, image = image, \
+                                      data = data)
+                self.Expand(afteritem)
+            else:
+                #dragItem dropped on single layer
+                newparent = self.GetItemParent(afteritem)
+                newItem = self.InsertItem(newparent, self.GetPrevSibling(afteritem), \
+                                       text = text, ct_type = 1, wnd = newctrl, \
+                                       image = image, data = data)
+        else:
+            # if dragItem not dropped on a layer or group, append or prepend it to the layer tree
+            if self.flag & wx.TREE_HITTEST_ABOVE:
+                newItem = self.PrependItem(self.root, text = text, \
+                                      ct_type = 1, wnd = newctrl, image = image, \
+                                      data = data)
+            elif (self.flag &  wx.TREE_HITTEST_BELOW) or (self.flag & wx.TREE_HITTEST_NOWHERE) \
+                     or (self.flag & wx.TREE_HITTEST_TOLEFT) or (self.flag & wx.TREE_HITTEST_TORIGHT):
+                newItem = self.AppendItem(self.root, text = text, \
+                                      ct_type = 1, wnd = newctrl, image = image, \
+                                      data = data)
+
+        #update new layer 
+        self.SetPyData(newItem, self.GetPyData(dragItem))
+        if newctrl:
+            self.GetPyData(newItem)[0]['ctrl'] = newctrl.GetId()
+        else:
+            self.GetPyData(newItem)[0]['ctrl'] = None
+            
+        self.CheckItem(newItem, checked = checked) # causes a new render
+        
+        return newItem
+
+    def _getLayerName(self, item, lname = ''):
+        """!Get layer name string
+
+        @param lname optional layer name
+        """
+        mapLayer = self.GetPyData(item)[0]['maplayer']
+        if not mapLayer:
+            return lname
+        
+        if not lname:
+            lname  = self.GetPyData(item)[0]['label']
+        opacity  = int(mapLayer.GetOpacity(float = True) * 100)
+        if not lname:
+            dcmd    = self.GetPyData(item)[0]['cmd']
+            lname, found = GetLayerNameFromCmd(dcmd, layerType = mapLayer.GetType(),
+                                               fullyQualified = True)
+            if not found:
+                return None
+        
+        if opacity < 100:
+            return lname + ' (%s %d' % (_('opacity:'), opacity) + '%)'
+        
+        return lname
+                
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """!Process layer data (when changes in properties dialog are applied)
+        """
+        # set layer text to map name
+        if dcmd:
+            self.GetPyData(layer)[0]['cmd'] = dcmd
+            mapText  = self._getLayerName(layer)
+            mapName, found = GetLayerNameFromCmd(dcmd)
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            self.SetItemText(layer, mapName)
+            
+            if not mapText or not found:
+                propwin.Hide()
+                GWarning(parent = self,
+                         message = _("Map <%s> not found.") % mapName)
+                return
+        
+        # update layer data
+        if params:
+            self.SetPyData(layer, (self.GetPyData(layer)[0], params))
+        self.GetPyData(layer)[0]['propwin'] = propwin
+        
+        # change parameters for item in layers list in render.Map
+        self.ChangeLayer(layer)
+        
+        # set region if auto-zooming is enabled
+        if dcmd and UserSettings.Get(group = 'display', key = 'autoZooming', subkey = 'enabled'):
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            if mapLayer.GetType() in ('raster', 'vector'):
+                render = UserSettings.Get(group = 'display', key = 'autoRendering', subkey = 'enabled')
+                self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
+                                                    render = render)
+        
+        # update nviz session        
+        if self.lmgr.IsPaneShown('toolbarNviz') and dcmd:
+            mapLayer = self.GetPyData(layer)[0]['maplayer']
+            mapWin = self.mapdisplay.MapWindow
+            if len(mapLayer.GetCmd()) > 0:
+                id = -1
+                if mapLayer.type == 'raster':
+                    if mapWin.IsLoaded(layer):
+                        mapWin.UnloadRaster(layer)
+                    
+                    mapWin.LoadRaster(layer)
+                    
+                elif mapLayer.type == '3d-raster':
+                    if mapWin.IsLoaded(layer):
+                        mapWin.UnloadRaster3d(layer)
+                    
+                    mapWin.LoadRaster3d(layer)
+                    
+                elif mapLayer.type == 'vector':
+                    if mapWin.IsLoaded(layer):
+                        mapWin.UnloadVector(layer)
+                    
+                    mapWin.LoadVector(layer)
+
+                # reset view when first layer loaded
+                nlayers = len(mapWin.Map.GetListOfLayers(l_type = ('raster', 'vector'),
+                                                         l_active = True))
+                if nlayers < 2:
+                    mapWin.ResetView()
+        
+    def ReorderLayers(self):
+        """!Add commands from data associated with any valid layers
+        (checked or not) to layer list in order to match layers in
+        layer tree."""
+
+        # make a list of visible layers
+        treelayers = []
+        
+        vislayer = self.GetFirstVisibleItem()
+        
+        if not vislayer or self.GetPyData(vislayer) is None:
+            return
+        
+        itemList = ""
+        
+        for item in range(self.GetCount()):
+            itemList += self.GetItemText(vislayer) + ','
+            if self.GetPyData(vislayer)[0]['type'] != 'group':
+                treelayers.append(self.GetPyData(vislayer)[0]['maplayer'])
+
+            if not self.GetNextVisible(vislayer):
+                break
+            else:
+                vislayer = self.GetNextVisible(vislayer)
+        
+        Debug.msg (4, "LayerTree.ReorderLayers(): items=%s" % \
+                   (itemList))
+        
+        # reorder map layers
+        treelayers.reverse()
+        self.Map.ReorderLayers(treelayers)
+        self.reorder = False
+        
+    def ChangeLayer(self, item):
+        """!Change layer"""
+        type = self.GetPyData(item)[0]['type']
+        layerName = None
+        
+        if type == 'command':
+            win = self.FindWindowById(self.GetPyData(item)[0]['ctrl'])
+            if win.GetValue() != None:
+                cmd = win.GetValue().split(';')
+                cmdlist = []
+                for c in cmd:
+                    cmdlist.append(c.split(' '))
+                opac = 1.0
+                chk = self.IsItemChecked(item)
+                hidden = not self.IsVisible(item)
+        elif type != 'group':
+            if self.GetPyData(item)[0] is not None:
+                cmdlist = self.GetPyData(item)[0]['cmd']
+                opac = self.GetPyData(item)[0]['maplayer'].GetOpacity(float = True)
+                chk = self.IsItemChecked(item)
+                hidden = not self.IsVisible(item)
+                # determine layer name
+                layerName, found = GetLayerNameFromCmd(cmdlist, fullyQualified = True)
+                if not found:
+                    layerName = self.GetItemText(item)
+        
+        maplayer = self.Map.ChangeLayer(layer = self.GetPyData(item)[0]['maplayer'], type = type,
+                                        command = cmdlist, name = layerName,
+                                        l_active = chk, l_hidden = hidden, l_opacity = opac, l_render = False)
+        
+        self.GetPyData(item)[0]['maplayer'] = maplayer
+        
+        # if digitization tool enabled -> update list of available vector map layers
+        if self.mapdisplay.GetToolbar('vdigit'):
+            self.mapdisplay.GetToolbar('vdigit').UpdateListOfLayers(updateTool = True)
+        
+        # redraw map if auto-rendering is enabled
+        self.rerender = True
+        self.reorder = True
+        
+    def OnCloseWindow(self, event):
+        pass
+        # self.Map.Clean()
+
+    def FindItemByData(self, key, value):
+        """!Find item based on key and value (see PyData[0]).
+        
+        If key is 'name', finds item(s) of given maplayer name.
+        
+        @return item instance
+        @return None not found
+        """
+        item = self.GetFirstChild(self.root)[0]
+        if key == 'name':
+            return self.__FindSubItemByName(item, value)
+        else:
+            return self.__FindSubItemByData(item, key, value)
+
+    def FindItemByIndex(self, index):
+        """!Find item by index (starting at 0)
+
+        @return item instance
+        @return None not found
+        """
+        item = self.GetFirstChild(self.root)[0]
+        i = 0
+        while item and item.IsOk():
+            if i == index:
+                return item
+            
+            item = self.GetNextVisible(item)
+            i += 1
+        
+        return None
+    
+    def EnableItemType(self, type, enable = True):
+        """!Enable/disable items in layer tree"""
+        item = self.GetFirstChild(self.root)[0]
+        while item and item.IsOk():
+            mapLayer = self.GetPyData(item)[0]['maplayer']
+            if mapLayer and type == mapLayer.type:
+                self.EnableItem(item, enable)
+            
+            item = self.GetNextSibling(item)
+        
+    def __FindSubItemByData(self, item, key, value):
+        """!Support method for FindItemByData"""
+        while item and item.IsOk():
+            try:
+                itemValue = self.GetPyData(item)[0][key]
+            except KeyError:
+                return None
+            
+            if value == itemValue:
+                return item
+            if self.GetPyData(item)[0]['type'] == 'group':
+                subItem = self.GetFirstChild(item)[0]
+                found = self.__FindSubItemByData(subItem, key, value)
+                if found:
+                    return found
+            item = self.GetNextSibling(item)
+
+        return None
+
+    def __FindSubItemByName(self, item, value):
+        """!Support method for FindItemByData for searching by name"""
+        items = []
+        while item and item.IsOk():
+            try:
+                itemLayer = self.GetPyData(item)[0]['maplayer']
+            except KeyError:
+                return None
+            
+            if value == itemLayer.GetName():
+                items.append(item)
+            if self.GetPyData(item)[0]['type'] == 'group':
+                subItem = self.GetFirstChild(item)[0]
+                found = self.__FindSubItemByName(subItem, name)
+                if found:
+                    items.extend(found)
+            item = self.GetNextSibling(item)
+        
+        if items:
+            return items
+        return None

Added: grass/trunk/gui/wxpython/lmgr/menudata.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/menudata.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/lmgr/menudata.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,70 @@
+"""!
+ at package lmrg.menudata
+
+ at brief Complex list for menu entries for wxGUI
+
+Classes:
+ - MenuData
+
+Usage:
+ at code
+python menudata.py [action] [manager|modeler]
+ at endcode
+
+where <i>action</i>:
+ - strings (default)
+ - tree
+ - commands
+ - dump
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Yann Chemin <yann.chemin gmail.com>
+ at author Martin Landa <landa.martin gmail.com>
+ at author Glynn Clements
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import os
+import sys
+
+from core.globalvar import ETCWXDIR
+from core.menudata  import MenuData
+
+class ManagerData(MenuData):
+    def __init__(self, filename = None):
+        if not filename:
+            gisbase = os.getenv('GISBASE')
+            global etcwxdir
+	    filename = os.path.join(ETCWXDIR, 'xml', 'menudata.xml')
+        
+        MenuData.__init__(self, filename)
+        
+    def GetModules(self):
+        """!Create dictionary of modules used to search module by
+        keywords, description, etc."""
+        modules = dict()
+        
+        for node in self.tree.getiterator():
+            if node.tag == 'menuitem':
+                module = description = ''
+                keywords = []
+                for child in node.getchildren():
+                    if child.tag == 'help':
+                        description = child.text
+                    if child.tag == 'command':
+                        module = child.text
+                    if child.tag == 'keywords':
+                        if child.text:
+                            keywords = child.text.split(',')
+                    
+                if module:
+                    modules[module] = { 'desc': description,
+                                        'keywords' : keywords }
+                    if len(keywords) < 1:
+                        print >> sys.stderr, "WARNING: Module <%s> has no keywords" % module
+                
+        return modules


Property changes on: grass/trunk/gui/wxpython/lmgr/menudata.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/lmgr/pyshell.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/gpyshell.py)
===================================================================
--- grass/trunk/gui/wxpython/lmgr/pyshell.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/lmgr/pyshell.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,111 @@
+"""!
+ at package lmgr.pyshell
+
+ at brief wxGUI Interactive Python Shell for Layer Manager
+
+Classes:
+ - PyShellWindow
+
+ at todo run pyshell and evaluate code in a separate instance of python
+& design the widget communicate back and forth with it
+
+(C) 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import sys
+
+import wx
+from wx.py.shell   import Shell as PyShell
+from wx.py.version import VERSION
+
+import grass.script as grass
+
+class PyShellWindow(wx.Panel):
+    """!Python Shell Window"""
+    def __init__(self, parent, id = wx.ID_ANY, **kwargs):
+        self.parent = parent # GMFrame
+        
+        wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+        
+        self.intro = _("Welcome to wxGUI Interactive Python Shell %s") % VERSION + "\n\n" + \
+            _("Type %s for more GRASS scripting related information.") % "\"help(grass)\"" + "\n" + \
+            _("Type %s to add raster or vector to the layer tree.") % "\"AddLayer()\"" + "\n\n"
+        self.shell = PyShell(parent = self, id = wx.ID_ANY,
+                             introText = self.intro, locals = {'grass' : grass,
+                                                               'AddLayer' : self.AddLayer})
+        
+        sys.displayhook = self._displayhook
+        
+        self.btnClear = wx.Button(self, wx.ID_CLEAR)
+        self.btnClear.Bind(wx.EVT_BUTTON, self.OnClear)
+        self.btnClear.SetToolTipString(_("Delete all text from the shell"))
+                
+        self._layout()
+        
+    def _displayhook(self, value):
+        print value # do not modify __builtin__._
+        
+    def _layout(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        sizer.Add(item = self.shell, proportion = 1,
+                  flag = wx.EXPAND)
+        
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = self.btnClear, proportion = 0,
+                     flag = wx.EXPAND | wx.RIGHT, border = 5)
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        
+        sizer.Fit(self)
+        sizer.SetSizeHints(self)
+        
+        self.SetSizer(sizer)
+        
+        self.Fit()
+        self.SetAutoLayout(True)        
+        self.Layout()
+
+    def AddLayer(self, name, ltype = 'auto'):
+        """!Add selected map to the layer tree
+
+        @param name name of raster/vector map to be added
+        @param type map type ('raster', 'vector', 'auto' for autodetection)
+        """
+        fname = None
+        if ltype == 'raster' or ltype != 'vector':
+            # check for raster
+            fname = grass.find_file(name, element = 'cell')['fullname']
+            if fname:
+                ltype = 'raster'
+                lcmd = 'd.rast'
+        
+        if not fname and (ltype == 'vector' or ltype != 'raster'):
+            # if not found check for vector
+            fname = grass.find_file(name, element = 'vector')['fullname']
+            if fname:
+                ltype = 'vector'
+                lcmd = 'd.vect'
+        
+        if not fname:
+            return _("Raster or vector map <%s> not found") % (name)
+        
+        self.parent.GetLayerTree().AddLayer(ltype = ltype,
+                                            lname = fname,
+                                            lchecked = True,
+                                            lcmd = [lcmd, 'map=%s' % fname])
+        if ltype == 'raster':
+            return _('Raster map <%s> added') % fname
+        
+        return _('Vector map <%s> added') % fname
+    
+    def OnClear(self, event):
+        """!Delete all text from the shell
+        """
+        self.shell.clear()
+        self.shell.showIntro(self.intro)
+        self.shell.prompt()

Added: grass/trunk/gui/wxpython/lmgr/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/lmgr/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,210 @@
+"""!
+ at package lmgr.toolbars
+
+ at brief wxGUI Layer Manager - toolbars
+
+Classes:
+ - LMWorkspaceToolbar
+ - LMDataToolbar
+ - LMToolsToolbar
+ - LMMiscToolbar
+ - LMVectorToolbar
+ - LMNvizToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import os
+import sys
+
+from core               import globalvar
+from core.gcmd          import RunCommand
+from nviz.preferences   import NvizPreferencesDialog
+from gui_core.toolbars  import BaseToolbar
+
+sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
+from icons.icon        import Icons
+
+class LMWorkspaceToolbar(BaseToolbar):
+    """!Layer Manager `workspace` toolbar
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['layerManager']
+        return self._getToolbarData((('newdisplay', icons["newdisplay"],
+                                      self.parent.OnNewDisplay),
+                                     (None, ),
+                                     ('workspaceNew', icons["workspaceNew"],
+                                      self.parent.OnWorkspaceNew),
+                                     ('workspaceOpen', icons["workspaceOpen"],
+                                      self.parent.OnWorkspaceOpen),
+                                     ('workspaceSave', icons["workspaceSave"],
+                                      self.parent.OnWorkspaceSave),
+                                     ))
+
+class LMDataToolbar(BaseToolbar):
+    """!Layer Manager `data` toolbar
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['layerManager']
+        return self._getToolbarData((('addMulti', icons["addMulti"],
+                                      self.parent.OnAddMaps),
+                                     ('addrast', icons["addRast"],
+                                      self.parent.OnAddRaster),
+                                     ('rastmisc', icons["rastMisc"],
+                                      self.parent.OnAddRasterMisc),
+                                     ('addvect', icons["addVect"],
+                                      self.parent.OnAddVector),
+                                     ('vectmisc', icons["vectMisc"],
+                                      self.parent.OnAddVectorMisc),
+                                     ('addgrp',  icons["addGroup"],
+                                      self.parent.OnAddGroup),
+                                     ('addovl',  icons["addOverlay"],
+                                      self.parent.OnAddOverlay),
+                                     ('delcmd',  icons["delCmd"],
+                                      self.parent.OnDeleteLayer),
+                                     ))
+
+class LMToolsToolbar(BaseToolbar):
+    """!Layer Manager `tools` toolbar
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['layerManager']
+        return self._getToolbarData((('importMap', icons["import"],
+                                      self.parent.OnImportMenu),
+                                     (None, ),
+                                     ('mapCalc', icons["mapcalc"],
+                                      self.parent.OnMapCalculator),
+                                     ('georect', Icons["georectify"]["georectify"],
+                                      self.parent.OnGCPManager),
+                                     ('modeler', icons["modeler"],
+                                      self.parent.OnGModeler),
+                                     ('mapOutput', icons['mapOutput'],
+                                      self.parent.OnPsMap)
+                                     ))
+
+class LMMiscToolbar(BaseToolbar):
+    """!Layer Manager `misc` toolbar
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['layerManager']
+        return self._getToolbarData((('settings', icons["settings"],
+                                      self.parent.OnPreferences),
+                                     ('help', Icons["misc"]["help"],
+                                      self.parent.OnHelp),
+                                     ))
+
+class LMVectorToolbar(BaseToolbar):
+    """!Layer Manager `vector` toolbar
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['layerManager']
+        return self._getToolbarData((('vdigit', icons["vdigit"],
+                                      self.parent.OnVDigit),
+                                     ('attribute', icons["attrTable"],
+                                      self.parent.OnShowAttributeTable),
+                                     ))
+
+class LMNvizToolbar(BaseToolbar):
+    """!Nviz toolbar
+    """
+    def __init__(self, parent):
+        self.lmgr = parent
+        
+        BaseToolbar.__init__(self, parent)
+        
+        # only one dialog can be open
+        self.settingsDialog   = None
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['nviz']
+        return self._getToolbarData((("nvizCmd", icons['nvizCmd'],
+                                      self.OnNvizCmd),
+                                     (None, ),
+                                     ("settings", icons["settings"],
+                                      self.OnSettings),
+                                     ("help", icons["help"],
+                                      self.OnHelp))
+                                    )
+        
+    def OnNvizCmd(self, event):
+        """!Show m.nviz.image command"""
+        self.lmgr.GetLayerTree().GetMapDisplay().GetWindow().OnNvizCmd()
+        
+    def OnHelp(self, event):
+        """!Show 3D view mode help"""
+        if not self.lmgr:
+            RunCommand('g.manual',
+                       entry = 'wxGUI.Nviz')
+        else:
+            log = self.lmgr.GetLogWindow()
+            log.RunCmd(['g.manual',
+                        'entry=wxGUI.Nviz'])
+        
+    def OnSettings(self, event):
+        """!Show nviz notebook page"""
+        if not self.settingsDialog:
+            self.settingsDialog = NvizPreferencesDialog(parent = self.parent)
+        self.settingsDialog.Show()


Property changes on: grass/trunk/gui/wxpython/lmgr/toolbars.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/location_wizard/base.py
===================================================================
--- grass/trunk/gui/wxpython/location_wizard/base.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/location_wizard/base.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,45 @@
+"""!
+ at package location_wizard.base
+
+ at brief Location wizard - base classes
+
+Classes:
+ - BaseClass
+
+(C) 2007-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>   
+"""
+
+import wx
+
+class BaseClass(wx.Object):
+    """!Base class providing basic methods"""
+    def __init__(self):
+        pass
+
+    def MakeLabel(self, text = "", style = wx.ALIGN_LEFT, parent = None):
+        """!Make aligned label"""
+        if not parent:
+            parent = self
+        return wx.StaticText(parent = parent, id = wx.ID_ANY, label = text,
+                             style = style)
+
+    def MakeTextCtrl(self, text = '', size = (100,-1), style = 0, parent = None):
+        """!Generic text control"""
+        if not parent:
+            parent = self
+        return wx.TextCtrl(parent = parent, id = wx.ID_ANY, value = text,
+                           size = size, style = style)
+
+    def MakeButton(self, text, id = wx.ID_ANY, size = (-1,-1), parent = None):
+        """!Generic button"""
+        if not parent:
+            parent = self
+        return wx.Button(parent = parent, id = id, label = text,
+                         size = size)


Property changes on: grass/trunk/gui/wxpython/location_wizard/base.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/location_wizard/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/location_wizard/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/location_wizard/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,612 @@
+"""!
+ at package location_wizard.dialogs
+
+ at brief Location wizard - dialogs
+
+Classes:
+ - RegionDef
+ - TransList
+ - SelectTransformDialog
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>   
+"""
+import os
+import sys
+
+import wx
+import wx.lib.scrolledpanel as scrolled
+
+from core                 import globalvar
+from core.gcmd            import RunCommand
+from location_wizard.base import BaseClass
+
+from grass.script import core as grass
+
+class RegionDef(BaseClass, wx.Frame):
+    """!Page for setting default region extents and resolution
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 title = _("Set default region extent and resolution"), location = None):
+        wx.Frame.__init__(self, parent, id, title, size = (650,300))
+        panel = wx.Panel(self, id = wx.ID_ANY)
+        
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.parent = parent
+        self.location = location
+        
+        #
+        # default values
+        #
+        # 2D
+        self.north = 1.0
+        self.south = 0.0
+        self.east = 1.0
+        self.west = 0.0
+        self.nsres = 1.0
+        self.ewres = 1.0
+        # 3D
+        self.top = 1.0
+        self.bottom = 0.0
+        #         self.nsres3 = 1.0
+        #         self.ewres3 = 1.0
+        self.tbres  = 1.0
+        
+        #
+        # inputs
+        #
+        # 2D
+        self.tnorth = self.MakeTextCtrl(text = str(self.north), size = (150, -1), parent = panel)
+        self.tsouth = self.MakeTextCtrl(str(self.south), size = (150, -1), parent = panel)
+        self.twest = self.MakeTextCtrl(str(self.west), size = (150, -1), parent = panel)
+        self.teast = self.MakeTextCtrl(str(self.east), size = (150, -1), parent = panel)
+        self.tnsres = self.MakeTextCtrl(str(self.nsres), size = (150, -1), parent = panel)
+        self.tewres = self.MakeTextCtrl(str(self.ewres), size = (150, -1), parent = panel)
+        
+        #
+        # labels
+        #
+        self.lrows  = self.MakeLabel(parent = panel)
+        self.lcols  = self.MakeLabel(parent = panel)
+        self.lcells = self.MakeLabel(parent = panel)
+        
+        #
+        # buttons
+        #
+        self.bset = self.MakeButton(text = _("&Set region"), id = wx.ID_OK, parent = panel)
+        self.bcancel = wx.Button(panel, id = wx.ID_CANCEL)
+        self.bset.SetDefault()
+        
+        #
+        # image
+        #
+        self.img = wx.Image(os.path.join(globalvar.ETCIMGDIR, "qgis_world.png"),
+                            wx.BITMAP_TYPE_PNG).ConvertToBitmap()
+        
+        #
+        # set current working environment to PERMANENT mapset
+        # in selected location in order to set default region (WIND)
+        #
+        envval = {}
+        ret = RunCommand('g.gisenv',
+                         read = True)
+        if ret:
+            for line in ret.splitlines():
+                key, val = line.split('=')
+                envval[key] = val
+            self.currlocation = envval['LOCATION_NAME'].strip("';")
+            self.currmapset = envval['MAPSET'].strip("';")
+            if self.currlocation != self.location or self.currmapset != 'PERMANENT':
+                RunCommand('g.gisenv',
+                           set = 'LOCATION_NAME=%s' % self.location)
+                RunCommand('g.gisenv',
+                           set = 'MAPSET=PERMANENT')
+        else:
+            dlg = wx.MessageBox(parent = self,
+                                message = _('Invalid location selected.'),
+                                caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
+            return
+        
+        #
+        # get current region settings
+        #
+        region = {}
+        ret = RunCommand('g.region',
+                         read = True,
+                         flags = 'gp3')
+        if ret:
+            for line in ret.splitlines():
+                key, val = line.split('=')
+                region[key] = float(val)
+        else:
+            dlg = wx.MessageBox(parent = self,
+                                message = _("Invalid region"),
+                                caption = _("Error"), style = wx.ID_OK | wx.ICON_ERROR)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+        
+        #
+        # update values
+        # 2D
+        self.north = float(region['n'])
+        self.south = float(region['s'])
+        self.east = float(region['e'])
+        self.west = float(region['w'])
+        self.nsres = float(region['nsres'])
+        self.ewres = float(region['ewres'])
+        self.rows = int(region['rows'])
+        self.cols = int(region['cols'])
+        self.cells = int(region['cells'])
+        # 3D
+        self.top = float(region['t'])
+        self.bottom = float(region['b'])
+        #         self.nsres3 = float(region['nsres3'])
+        #         self.ewres3 = float(region['ewres3'])
+        self.tbres = float(region['tbres'])
+        self.depth = int(region['depths'])
+        self.cells3 = int(region['cells3'])
+        
+        #
+        # 3D box collapsable
+        #
+        self.infoCollapseLabelExp = _("Click here to show 3D settings")
+        self.infoCollapseLabelCol = _("Click here to hide 3D settings")
+        self.settings3D = wx.CollapsiblePane(parent = panel,
+                                             label = self.infoCollapseLabelExp,
+                                             style = wx.CP_DEFAULT_STYLE |
+                                             wx.CP_NO_TLW_RESIZE | wx.EXPAND)
+        self.MakeSettings3DPaneContent(self.settings3D.GetPane())
+        self.settings3D.Collapse(False) # FIXME
+        self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnSettings3DPaneChanged, self.settings3D)
+        
+        #
+        # set current region settings
+        #
+        self.tnorth.SetValue(str(self.north))
+        self.tsouth.SetValue(str(self.south))
+        self.twest.SetValue(str(self.west))
+        self.teast.SetValue(str(self.east))
+        self.tnsres.SetValue(str(self.nsres))
+        self.tewres.SetValue(str(self.ewres))
+        self.ttop.SetValue(str(self.top))
+        self.tbottom.SetValue(str(self.bottom))
+        #         self.tnsres3.SetValue(str(self.nsres3))
+        #         self.tewres3.SetValue(str(self.ewres3))
+        self.ttbres.SetValue(str(self.tbres))
+        self.lrows.SetLabel(_("Rows: %d") % self.rows)
+        self.lcols.SetLabel(_("Cols: %d") % self.cols)
+        self.lcells.SetLabel(_("Cells: %d") % self.cells)
+        
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
+        self.tnorth.Bind(wx.EVT_TEXT,   self.OnValue)
+        self.tsouth.Bind(wx.EVT_TEXT,   self.OnValue)
+        self.teast.Bind(wx.EVT_TEXT,    self.OnValue)
+        self.twest.Bind(wx.EVT_TEXT,    self.OnValue)
+        self.tnsres.Bind(wx.EVT_TEXT,   self.OnValue)
+        self.tewres.Bind(wx.EVT_TEXT,   self.OnValue)
+        self.ttop.Bind(wx.EVT_TEXT,     self.OnValue)
+        self.tbottom.Bind(wx.EVT_TEXT,  self.OnValue)
+        #         self.tnsres3.Bind(wx.EVT_TEXT,  self.OnValue)
+        #         self.tewres3.Bind(wx.EVT_TEXT,  self.OnValue)
+        self.ttbres.Bind(wx.EVT_TEXT,   self.OnValue)
+        
+        self.__DoLayout(panel)
+        self.SetMinSize(self.GetBestSize())
+        self.minWindowSize = self.GetMinSize()
+    
+    def MakeSettings3DPaneContent(self, pane):
+        """!Create 3D region settings pane"""
+        border = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
+
+        # inputs
+        self.ttop = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.top),
+                                size = (150, -1))
+        self.tbottom = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.bottom),
+                                size = (150, -1))
+        self.ttbres = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.tbres),
+                                size = (150, -1))
+        #         self.tnsres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.nsres3),
+        #                                    size = (150, -1))
+        #         self.tewres3  =  wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.ewres3),
+        #                                    size = (150, -1))
+
+        #labels
+        self.ldepth = wx.StaticText(parent = pane, label = _("Depth: %d") % self.depth)
+        self.lcells3  =  wx.StaticText(parent = pane, label = _("3D Cells: %d") % self.cells3)
+
+        # top
+        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Top")),
+                      flag = wx.ALIGN_CENTER |
+                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
+                      pos = (0, 1))
+        gridSizer.Add(item = self.ttop,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALL, border = 5, pos = (1, 1))
+        # bottom
+        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("Bottom")),
+                      flag = wx.ALIGN_CENTER |
+                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
+                      pos = (0, 2))
+        gridSizer.Add(item = self.tbottom,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALL, border = 5, pos = (1, 2))
+        # tbres
+        gridSizer.Add(item = wx.StaticText(parent = pane, label = _("T-B resolution")),
+                      flag = wx.ALIGN_CENTER | 
+                      wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
+                      pos = (0, 3))
+        gridSizer.Add(item = self.ttbres,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALL, border = 5, pos = (1, 3))
+
+        # res
+        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D N-S resolution")),
+        #                       flag = wx.ALIGN_CENTER |
+        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
+        #                       pos = (2, 1))
+        #         gridSizer.Add(item = self.tnsres3,
+        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
+        #                       wx.ALL, border = 5, pos = (3, 1))
+        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D E-W resolution")),
+        #                       flag = wx.ALIGN_CENTER |
+        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
+        #                       pos = (2, 3))
+        #         gridSizer.Add(item = self.tewres3,
+        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
+        #                       wx.ALL, border = 5, pos = (3, 3))
+
+        # rows/cols/cells
+        gridSizer.Add(item = self.ldepth,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.ALL, border = 5, pos = (2, 1))
+
+        gridSizer.Add(item = self.lcells3,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.ALL, border = 5, pos = (2, 2))
+
+        border.Add(item = gridSizer, proportion = 1,
+                   flag = wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border = 5)
+
+        pane.SetSizer(border)
+        border.Fit(pane)
+
+    def OnSettings3DPaneChanged(self, event):
+        """!Collapse 3D settings box"""
+
+        if self.settings3D.IsExpanded():
+            self.settings3D.SetLabel(self.infoCollapseLabelCol)
+            self.Layout()
+            self.SetSize(self.GetBestSize())
+            self.SetMinSize(self.GetSize())
+        else:
+            self.settings3D.SetLabel(self.infoCollapseLabelExp)
+            self.Layout()
+            self.SetSize(self.minWindowSize)
+            self.SetMinSize(self.minWindowSize)
+
+        self.SendSizeEvent()
+
+    def __DoLayout(self, panel):
+        """!Window layout"""
+        frameSizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 0, hgap = 0)
+        settings3DSizer = wx.BoxSizer(wx.VERTICAL)
+        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        # north
+        gridSizer.Add(item = self.MakeLabel(text = _("North"), parent = panel),
+                      flag = wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (0, 2))
+        gridSizer.Add(item = self.tnorth,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5, pos = (1, 2))
+        # west
+        gridSizer.Add(item = self.MakeLabel(text = _("West"), parent = panel),
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.LEFT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 0))
+        gridSizer.Add(item = self.twest,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5,  pos = (2, 1))
+
+        gridSizer.Add(item = wx.StaticBitmap(panel, wx.ID_ANY, self.img, (-1, -1),
+                                           (self.img.GetWidth(), self.img.GetHeight())),
+                      flag = wx.ALIGN_CENTER |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5, pos = (2, 2))
+
+        # east
+        gridSizer.Add(item = self.teast,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5,  pos = (2, 3))
+        gridSizer.Add(item = self.MakeLabel(text = _("East"), parent = panel),
+                      flag = wx.ALIGN_LEFT |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.RIGHT | wx.TOP | wx.BOTTOM, border = 5, pos = (2, 4))
+        # south
+        gridSizer.Add(item = self.tsouth,
+                      flag = wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5, pos = (3, 2))
+        gridSizer.Add(item = self.MakeLabel(text = _("South"), parent = panel),
+                      flag = wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
+                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5, pos = (4, 2))
+        # ns-res
+        gridSizer.Add(item = self.MakeLabel(text = _("N-S resolution"), parent = panel),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 1))
+        gridSizer.Add(item = self.tnsres,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5,  pos = (6, 1))
+        # ew-res
+        gridSizer.Add(item = self.MakeLabel(text = _("E-W resolution"), parent = panel),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.TOP | wx.LEFT | wx.RIGHT, border = 5, pos = (5, 3))
+        gridSizer.Add(item = self.tewres,
+                      flag = wx.ALIGN_RIGHT |
+                      wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALL, border = 5,  pos = (6, 3))
+        # rows/cols/cells
+        gridSizer.Add(item = self.lrows,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.ALL, border = 5, pos = (7, 1))
+
+        gridSizer.Add(item = self.lcells,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.ALL, border = 5, pos = (7, 2))
+
+        gridSizer.Add(item = self.lcols,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
+                      wx.ALL, border = 5, pos = (7, 3))
+
+        # 3D
+        settings3DSizer.Add(item = self.settings3D,
+                            flag = wx.ALL,
+                            border = 5)
+
+        # buttons
+        buttonSizer.Add(item = self.bcancel, proportion = 1,
+                        flag = wx.ALIGN_RIGHT |
+                        wx.ALIGN_CENTER_VERTICAL |
+                        wx.ALL, border = 10)
+        buttonSizer.Add(item = self.bset, proportion = 1,
+                        flag = wx.ALIGN_CENTER |
+                        wx.ALIGN_CENTER_VERTICAL |
+                        wx.ALL, border = 10)
+
+        frameSizer.Add(item = gridSizer, proportion = 1,
+                       flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
+        frameSizer.Add(item = settings3DSizer, proportion = 0,
+                       flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
+        frameSizer.Add(item = buttonSizer, proportion = 0,
+                       flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
+
+        self.SetAutoLayout(True)
+        panel.SetSizer(frameSizer)
+        frameSizer.Fit(panel)
+        self.Layout()
+
+    def OnValue(self, event):
+        """!Set given value"""
+        try:
+            if event.GetId() == self.tnorth.GetId():
+                self.north = float(event.GetString())
+            elif event.GetId() == self.tsouth.GetId():
+                self.south = float(event.GetString())
+            elif event.GetId() == self.teast.GetId():
+                self.east = float(event.GetString())
+            elif event.GetId() == self.twest.GetId():
+                self.west = float(event.GetString())
+            elif event.GetId() == self.tnsres.GetId():
+                self.nsres = float(event.GetString())
+            elif event.GetId() == self.tewres.GetId():
+                self.ewres = float(event.GetString())
+            elif event.GetId() == self.ttop.GetId():
+                self.top = float(event.GetString())
+            elif event.GetId() == self.tbottom.GetId():
+                self.bottom = float(event.GetString())
+            #             elif event.GetId() == self.tnsres3.GetId():
+            #                 self.nsres3 = float(event.GetString())
+            #             elif event.GetId() == self.tewres3.GetId():
+            #                 self.ewres3 = float(event.GetString())
+            elif event.GetId() == self.ttbres.GetId():
+                self.tbres = float(event.GetString())
+
+            self.__UpdateInfo()
+
+        except ValueError, e:
+            if len(event.GetString()) > 0 and event.GetString() != '-':
+                dlg = wx.MessageBox(parent = self,
+                                    message = _("Invalid value: %s") % e,
+                                    caption = _("Error"),
+                                    style = wx.OK | wx.ICON_ERROR)
+                # reset values
+                self.tnorth.SetValue(str(self.north))
+                self.tsouth.SetValue(str(self.south))
+                self.teast.SetValue(str(self.east))
+                self.twest.SetValue(str(self.west))
+                self.tnsres.SetValue(str(self.nsres))
+                self.tewres.SetValue(str(self.ewres))
+                self.ttop.SetValue(str(self.top))
+                self.tbottom.SetValue(str(self.bottom))
+                self.ttbres.SetValue(str(self.tbres))
+                # self.tnsres3.SetValue(str(self.nsres3))
+                # self.tewres3.SetValue(str(self.ewres3))
+
+        event.Skip()
+
+    def __UpdateInfo(self):
+        """!Update number of rows/cols/cells"""
+        self.rows = int((self.north - self.south) / self.nsres)
+        self.cols = int((self.east - self.west) / self.ewres)
+        self.cells = self.rows * self.cols
+
+        self.depth = int((self.top - self.bottom) / self.tbres)
+        self.cells3 = self.rows * self.cols * self.depth
+
+        # 2D
+        self.lrows.SetLabel(_("Rows: %d") % self.rows)
+        self.lcols.SetLabel(_("Cols: %d") % self.cols)
+        self.lcells.SetLabel(_("Cells: %d") % self.cells)
+        # 3D
+        self.ldepth.SetLabel(_("Depth: %d" % self.depth))
+        self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))
+
+    def OnSetButton(self, event = None):
+        """!Set default region"""
+        ret = RunCommand('g.region',
+                         flags = 'sgpa',
+                         n = self.north,
+                         s = self.south,
+                         e = self.east,
+                         w = self.west,
+                         nsres = self.nsres,
+                         ewres = self.ewres,
+                         t = self.top,
+                         b = self.bottom,
+                         tbres = self.tbres)
+        if ret == 0:
+            self.Destroy()
+
+    def OnCancel(self, event):
+        self.Destroy()
+
+class TransList(wx.VListBox):
+    """!Creates a multiline listbox for selecting datum transforms"""
+        
+    def OnDrawItem(self, dc, rect, n):
+        if self.GetSelection() == n:
+            c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+        else:
+            c = self.GetForegroundColour()
+        dc.SetFont(self.GetFont())
+        dc.SetTextForeground(c)
+        dc.DrawLabel(self._getItemText(n), rect,
+                     wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+
+    def OnMeasureItem(self, n):
+        height = 0
+        if self._getItemText(n) == None:
+            return
+        for line in self._getItemText(n).splitlines():
+            w, h = self.GetTextExtent(line)
+            height += h
+        return height + 5
+
+    def _getItemText(self, item):
+        global transformlist
+        transitem = transformlist[item]
+        if transitem.strip() !='':
+            return transitem
+
+class SelectTransformDialog(wx.Dialog):
+    """!Dialog for selecting datum transformations"""
+    def __init__(self, parent, transforms, title = _("Select datum transformation"),
+                 pos = wx.DefaultPosition, size = wx.DefaultSize, 
+                 style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
+
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
+
+        global transformlist
+        self.CentreOnParent()
+        
+        # default transform number
+        self.transnum = 0
+        
+        panel = scrolled.ScrolledPanel(self, wx.ID_ANY)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        #
+        # set panel sizer
+        #
+        panel.SetSizer(sizer)
+        panel.SetupScrolling()
+
+        #
+        # dialog body
+        #
+        bodyBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                               label = " %s " % _("Select from list of datum transformations"))
+        bodySizer = wx.StaticBoxSizer(bodyBox)       
+        
+        # add no transform option
+        transforms = '---\n\n0\nDo not apply any datum transformations\n\n' + transforms
+        
+        transformlist = transforms.split('---')
+        tlistlen = len(transformlist)
+        
+        # calculate size for transform list
+        height = 0
+        width = 0
+        for line in transforms.splitlines():
+            w, h = self.GetTextExtent(line)
+            height += h
+            width = max(width, w)
+            
+        height = height + 5
+        if height > 400: height = 400
+        width = width + 5
+        if width > 400: width = 400
+
+        #
+        # VListBox for displaying and selecting transformations
+        #
+        self.translist = TransList(panel, id = -1, size = (width, height), style = wx.SUNKEN_BORDER)
+        self.translist.SetItemCount(tlistlen)
+        self.translist.SetSelection(2)
+        self.translist.SetFocus()
+        
+        self.Bind(wx.EVT_LISTBOX, self.ClickTrans, self.translist)
+
+        bodySizer.Add(item = self.translist, proportion = 1, flag = wx.ALIGN_CENTER|wx.ALL|wx.EXPAND)
+
+        #
+        # buttons
+        #
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(parent = panel, id = wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(parent = panel, id = wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        sizer.Add(item = bodySizer, proportion = 1,
+                  flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        sizer.Add(item = btnsizer, proportion = 0,
+                  flag =  wx.ALL | wx.ALIGN_RIGHT, border = 5)
+
+        sizer.Fit(panel)
+
+        self.SetSize(self.GetBestSize())
+        self.Layout()
+        
+    def ClickTrans(self, event):
+        """!Get the number of the datum transform to use in g.proj"""
+        self.transnum = event.GetSelection()
+        self.transnum = self.transnum - 1
+    
+    def GetTransform(self):
+        """!Get the number of the datum transform to use in g.proj"""
+        self.transnum = self.translist.GetSelection()
+        self.transnum = self.transnum - 1
+        return self.transnum


Property changes on: grass/trunk/gui/wxpython/location_wizard/dialogs.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/location_wizard/wizard.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/location_wizard.py)
===================================================================
--- grass/trunk/gui/wxpython/location_wizard/wizard.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/location_wizard/wizard.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2049 @@
+"""!
+ at package location_wizard.wizard
+
+ at brief Location wizard - creates a new GRASS Location. User can choose
+from multiple methods.
+
+Classes:
+ - TitledPage
+ - DatabasePage
+ - CoordinateSystemPage
+ - ProjectionsPage
+ - ItemList
+ - ProjParamsPage
+ - DatumPage
+ - EllipsePage
+ - GeoreferencedFilePage
+ - EPSGPage
+ - CustomPage
+ - SummaryPage
+ - LocationWizard
+
+(C) 2007-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>   
+"""
+import os
+import locale
+
+import wx
+import wx.lib.mixins.listctrl as listmix
+import wx.wizard as wiz
+import wx.lib.scrolledpanel as scrolled
+
+from core                    import globalvar
+from core                    import utils
+from core.gcmd               import RunCommand, GError, GMessage, GWarning
+from location_wizard.base    import BaseClass
+from location_wizard.dialogs import RegionDef, SelectTransformDialog
+
+from grass.script import core as grass
+
+global coordsys
+global north
+global south
+global east
+global west
+global resolution
+global wizerror
+global translist
+
+class TitledPage(BaseClass, wiz.WizardPageSimple):
+    """!Class to make wizard pages. Generic methods to make labels,
+    text entries, and buttons.
+    """
+    def __init__(self, parent, title):
+
+        self.page = wiz.WizardPageSimple.__init__(self, parent)
+
+        # page title
+        self.title = wx.StaticText(parent = self, id = wx.ID_ANY, label = title)
+        self.title.SetFont(wx.Font(13, wx.SWISS, wx.NORMAL, wx.BOLD))
+
+        # main sizers
+        self.pagesizer = wx.BoxSizer(wx.VERTICAL)
+        self.sizer = wx.GridBagSizer(vgap = 0, hgap = 0)
+        
+    def DoLayout(self):
+        """!Do page layout"""
+        self.pagesizer.Add(item = self.title, proportion = 0,
+                           flag = wx.ALIGN_CENTRE | wx.ALL,
+                           border = 5)
+        self.pagesizer.Add(item = wx.StaticLine(self, -1), proportion = 0,
+                           flag = wx.EXPAND | wx.ALL,
+                           border = 0)
+        self.pagesizer.Add(item = self.sizer, proportion = 1,
+                           flag = wx.EXPAND)
+        
+        self.SetAutoLayout(True)
+        self.SetSizer(self.pagesizer)
+        self.Layout()
+
+class DatabasePage(TitledPage):
+    """!Wizard page for setting GIS data directory and location name"""
+    def __init__(self, wizard, parent, grassdatabase):
+        TitledPage.__init__(self, wizard, _("Define GRASS Database and Location Name"))
+
+        self.grassdatabase  = grassdatabase
+        self.location       = ''
+        self.locTitle       = ''
+        
+        # buttons
+        self.bbrowse = self.MakeButton(_("Browse"))
+
+        # text controls
+        self.tgisdbase = self.MakeTextCtrl(grassdatabase, size = (300, -1))
+        self.tlocation = self.MakeTextCtrl("newLocation", size = (300, -1))
+        self.tlocTitle = self.MakeTextCtrl(size = (400, -1))
+        
+        # layout
+        self.sizer.AddGrowableCol(3)
+        self.sizer.Add(item = self.MakeLabel(_("GIS Data Directory:")),
+                       flag = wx.ALIGN_RIGHT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (1, 1))
+        self.sizer.Add(item = self.tgisdbase,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (1, 2))
+        self.sizer.Add(item = self.bbrowse,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (1, 3))
+        
+        self.sizer.Add(item = self.MakeLabel("%s:" % _("Project Location")),
+                       flag = wx.ALIGN_RIGHT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (2, 1))
+        self.sizer.Add(item = self.tlocation,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (2, 2))
+
+        self.sizer.Add(item = self.MakeLabel("%s:" % _("Location Title")),
+                       flag = wx.ALIGN_RIGHT |
+                       wx.ALIGN_TOP | wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (3, 1))
+        self.sizer.Add(item = self.tlocTitle,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5,
+                       pos = (3, 2), span  =  (1, 2))
+        
+        # bindings
+        self.Bind(wx.EVT_BUTTON,                self.OnBrowse, self.bbrowse)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.tgisdbase.Bind(wx.EVT_TEXT,        self.OnChangeName)
+        self.tlocation.Bind(wx.EVT_TEXT,        self.OnChangeName)
+        
+    def OnChangeName(self, event):
+        """!Name for new location was changed"""
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(event.GetString()) > 0:
+            if not nextButton.IsEnabled():
+                nextButton.Enable()
+        else:
+            nextButton.Disable()
+
+        event.Skip()
+
+    def OnBrowse(self, event):
+        """!Choose GRASS data directory"""
+        dlg = wx.DirDialog(self, _("Choose GRASS data directory:"),
+                           os.getcwd(), wx.DD_DEFAULT_STYLE)
+        if dlg.ShowModal() == wx.ID_OK:
+            self.grassdatabase = dlg.GetPath()
+            self.tgisdbase.SetValue(self.grassdatabase)
+            
+        dlg.Destroy()
+
+    def OnPageChanging(self, event = None):
+        error = None
+        if os.path.isdir(os.path.join(self.tgisdbase.GetValue(), self.tlocation.GetValue())):
+            error = _("Location already exists in GRASS Database.")
+
+        if error:
+            GError(parent = self,
+                   message="%s <%s>.%s%s" % (_("Unable to create location"),
+                                             str(self.tlocation.GetValue()),
+                                             os.linesep,
+                                             error))
+            event.Veto()
+            return
+
+        self.location      = self.tlocation.GetValue()
+        self.grassdatabase = self.tgisdbase.GetValue()
+        self.locTitle      = self.tlocTitle.GetValue()
+        if os.linesep in self.locTitle or \
+                len(self.locTitle) > 255:
+            GWarning(parent = self,
+                     message = _("Title of the location is limited only to one line and "
+                                 "256 characters. The rest of the text will be ignored."))
+            self.locTitle = self.locTitle.split(os.linesep)[0][:255]
+            
+class CoordinateSystemPage(TitledPage):
+    """!Wizard page for choosing method for location creation"""
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Choose method for creating a new location"))
+        
+        self.parent = parent
+        global coordsys
+        
+        # toggles
+        self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Select coordinate system parameters from a list"),
+                                     style  =  wx.RB_GROUP)
+        self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Select EPSG code of spatial reference system"))
+        self.radio3 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Read projection and datum terms from a "
+                                             "georeferenced data file"))
+        self.radio4 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Read projection and datum terms from a "
+                                             "WKT or PRJ file"))
+        self.radio5 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Specify projection and datum terms using custom "
+                                             "PROJ.4 parameters"))
+        self.radio6 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Create an arbitrary non-earth coordinate system (XY)"))
+        
+        # layout
+        self.sizer.AddGrowableCol(1)
+        self.sizer.SetVGap(10)
+        self.sizer.Add(item = self.radio1,
+                       flag = wx.ALIGN_LEFT, pos = (1, 1))
+        self.sizer.Add(item = self.radio2,
+                       flag = wx.ALIGN_LEFT, pos = (2, 1))
+        self.sizer.Add(item = self.radio3,
+                       flag = wx.ALIGN_LEFT, pos = (3, 1))
+        self.sizer.Add(item = self.radio4,
+                       flag = wx.ALIGN_LEFT, pos = (4, 1))
+        self.sizer.Add(item = self.radio5,
+                       flag = wx.ALIGN_LEFT, pos = (5, 1))
+        self.sizer.Add(item = self.radio6,
+                       flag = wx.ALIGN_LEFT, pos = (6, 1))
+
+        # bindings
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio3.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio4.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio5.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio6.GetId())
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
+        
+    def OnEnterPage(self, event):
+        global coordsys
+        
+        if not coordsys:
+            coordsys = "proj"
+            self.radio1.SetValue(True)
+        else:
+            if coordsys == 'proj':
+                self.radio1.SetValue(True)
+            if coordsys == "epsg":
+                self.radio2.SetValue(True)
+            if coordsys == "file":
+                self.radio3.SetValue(True)
+            if coordsys == "wkt":
+                self.radio4.SetValue(True)
+            if coordsys == "custom":
+                self.radio5.SetValue(True)
+            if coordsys == "xy":
+                self.radio6.SetValue(True)
+        
+        if event.GetDirection():
+            if coordsys == 'proj':
+                self.SetNext(self.parent.projpage)
+                self.parent.sumpage.SetPrev(self.parent.datumpage)
+            if coordsys == "epsg":
+                self.SetNext(self.parent.epsgpage)
+                self.parent.sumpage.SetPrev(self.parent.epsgpage)
+            if coordsys == "file":
+                self.SetNext(self.parent.filepage)
+                self.parent.sumpage.SetPrev(self.parent.filepage)
+            if coordsys == "wkt":
+                self.SetNext(self.parent.wktpage)
+                self.parent.sumpage.SetPrev(self.parent.wktpage)
+            if coordsys == "custom":
+                self.SetNext(self.parent.custompage)
+                self.parent.sumpage.SetPrev(self.parent.custompage)
+            if coordsys == "xy":
+                self.SetNext(self.parent.sumpage)
+                self.parent.sumpage.SetPrev(self.parent.csystemspage)
+        
+        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
+            wx.FindWindowById(wx.ID_FORWARD).Enable()
+    
+    def SetVal(self, event):
+        """!Choose method"""
+        global coordsys
+        if event.GetId() == self.radio1.GetId():
+            coordsys = "proj"
+            self.SetNext(self.parent.projpage)
+            self.parent.sumpage.SetPrev(self.parent.datumpage)
+        elif event.GetId() == self.radio2.GetId():
+            coordsys = "epsg"
+            self.SetNext(self.parent.epsgpage)
+            self.parent.sumpage.SetPrev(self.parent.epsgpage)
+        elif event.GetId() == self.radio3.GetId():
+            coordsys = "file"
+            self.SetNext(self.parent.filepage)
+            self.parent.sumpage.SetPrev(self.parent.filepage)
+        elif event.GetId() == self.radio4.GetId():
+            coordsys = "wkt"
+            self.SetNext(self.parent.wktpage)
+            self.parent.sumpage.SetPrev(self.parent.wktpage)
+        elif event.GetId() == self.radio5.GetId():
+            coordsys = "custom"
+            self.SetNext(self.parent.custompage)
+            self.parent.sumpage.SetPrev(self.parent.custompage)
+        elif event.GetId() == self.radio6.GetId():
+            coordsys = "xy"
+            self.SetNext(self.parent.sumpage)
+            self.parent.sumpage.SetPrev(self.parent.csystemspage)
+
+class ProjectionsPage(TitledPage):
+    """!Wizard page for selecting projection (select coordinate system option)"""
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Choose projection"))
+
+        self.parent = parent
+        self.proj = ''
+        self.projdesc = ''
+        self.p4proj = ''
+
+        # text input
+        self.tproj = self.MakeTextCtrl("", size = (200,-1))
+        
+        # search box
+        self.searchb = wx.SearchCtrl(self, size = (200,-1),
+                                     style = wx.TE_PROCESS_ENTER)
+
+        # projection list
+        self.projlist = ItemList(self, data = self.parent.projdesc.items(),
+                                 columns = [_('Code'), _('Description')])
+        self.projlist.resizeLastColumn(30) 
+
+        # layout
+        self.sizer.AddGrowableCol(3)
+        self.sizer.Add(item = self.MakeLabel(_("Projection code:")),
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.tproj,
+                       flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
+                       border = 5, pos = (1, 2))
+
+        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
+                       flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
+                       border = 5, pos = (2, 1))
+        self.sizer.Add(item = self.searchb,
+                       flag = wx.ALIGN_RIGHT | wx.EXPAND | wx.ALL,
+                       border = 5, pos = (2, 2))
+        
+        self.sizer.AddGrowableRow(3)
+        self.sizer.Add(item = self.projlist,
+                       flag = wx.EXPAND |
+                       wx.ALIGN_LEFT |
+                       wx.ALL, border = 5, pos = (3, 1), span = (1, 3))
+
+        # events
+        self.tproj.Bind(wx.EVT_TEXT, self.OnText)
+        self.tproj.Bind(wx.EVT_TEXT_ENTER, self.OnText)
+        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
+        self.projlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED,  self.OnEnterPage)
+        
+    def OnPageChanging(self,event):
+        if event.GetDirection() and self.proj not in self.parent.projections.keys():
+            event.Veto()
+
+    def OnText(self, event):
+        """!Projection name changed"""
+        self.proj = event.GetString().lower()
+        self.p4proj = ''
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if self.proj not in self.parent.projections.keys() and nextButton.IsEnabled():
+            nextButton.Enable(False)
+        
+        if self.proj in self.parent.projections.keys():
+            if self.proj == 'stp':
+                wx.MessageBox('Currently State Plane projections must be selected using the '
+                              'text-based setup (g.setproj), or entered by EPSG code or '
+                              'custom PROJ.4 terms.',
+                              'Warning', wx.ICON_WARNING)
+                self.proj = ''
+                self.tproj.SetValue(self.proj)
+                nextButton.Enable(False)
+                return
+            elif self.proj.lower() == 'll':
+                self.p4proj = '+proj=longlat'
+            else:
+                self.p4proj = '+proj=' + self.proj.lower()
+            self.projdesc = self.parent.projections[self.proj][0]
+            nextButton.Enable()
+
+    def OnEnterPage(self, event):
+        if len(self.proj) == 0:
+            # disable 'next' button by default
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        event.Skip()
+    
+    def OnSearch(self, event):
+        """!Search projection by desc"""
+        str = event.GetString()
+        try:
+            self.proj, self.projdesc = self.projlist.Search(index = [0,1], pattern = event.GetString())
+        except:
+            self.proj = self.projdesc = ''
+            
+        event.Skip()
+
+    def OnItemSelected(self, event):
+        """!Projection selected"""
+        index = event.m_itemIndex
+
+        # set values
+        self.proj = self.projlist.GetItem(index, 0).GetText().lower()
+        self.tproj.SetValue(self.proj)
+        
+        event.Skip()
+
+class ItemList(wx.ListCtrl,
+               listmix.ListCtrlAutoWidthMixin,
+               listmix.ColumnSorterMixin):
+    """!Generic list (for projections, ellipsoids, etc.)"""
+
+    def __init__(self, parent, columns, data = None):
+        wx.ListCtrl.__init__(self, parent = parent, id = wx.ID_ANY,
+                             style = wx.LC_REPORT |
+                             wx.LC_VIRTUAL | 
+                             wx.LC_HRULES |
+                             wx.LC_VRULES |
+                             wx.LC_SINGLE_SEL |
+                             wx.LC_SORT_ASCENDING, size = (550, 125))
+
+        # original data or None
+        self.sourceData = data
+        
+        #
+        # insert columns
+        #
+        i = 0
+        for column in columns:
+            self.InsertColumn(i, column)
+            i += 1
+
+        if self.sourceData:
+            self.Populate()
+        
+        for i in range(self.GetColumnCount()):
+            self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
+            if self.GetColumnWidth(i) < 80:
+                self.SetColumnWidth(i, 80)
+        
+        #
+        # listmix
+        #
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
+            
+        #
+        # add some attributes
+        #
+        self.attr1 = wx.ListItemAttr()
+        self.attr1.SetBackgroundColour(wx.Colour(238,238,238))
+        self.attr2 = wx.ListItemAttr()
+        self.attr2.SetBackgroundColour("white")
+        self.il = wx.ImageList(16, 16)
+        self.sm_up = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_UP,   wx.ART_TOOLBAR,
+                                                          (16,16)))
+        self.sm_dn = self.il.Add(wx.ArtProvider_GetBitmap(wx.ART_GO_DOWN, wx.ART_TOOLBAR,
+                                                          (16,16)))
+        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
+
+        #
+        # sort by first column
+        #
+        if self.sourceData:
+            self.SortListItems(col = 0, ascending = True)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColumnClick)
+
+    def Populate(self, data = None, update = False):
+        """!Populate list"""
+        self.itemDataMap  = {}
+        self.itemIndexMap = []
+        
+        if data is None:
+            data = self.sourceData
+        elif update:
+            self.sourceData = data
+
+        try:
+            data.sort()
+            self.DeleteAllItems()
+            row = 0
+            for value in data:
+                self.itemDataMap[row] = [value[0]]
+                for i in range(1, len(value)):
+                     self.itemDataMap[row].append(value[i])
+                self.itemIndexMap.append(row)
+                row += 1
+
+            self.SetItemCount(row)
+            
+            # set column width
+            self.SetColumnWidth(0, 80)
+            self.SetColumnWidth(1, 300)
+            
+            self.SendSizeEvent()
+            
+        except StandardError, e:
+            wx.MessageBox(parent = self,
+                          message = _("Unable to read list: %s") % e,
+                          caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
+
+    def OnColumnClick(self, event):
+        """!Sort by column"""
+        self._col = event.GetColumn()
+
+        # remove duplicated arrow symbol from column header
+        # FIXME: should be done automatically
+        info = wx.ListItem()
+        info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE
+        info.m_image = -1
+        for column in range(self.GetColumnCount()):
+            info.m_text = self.GetColumn(column).GetText()
+            self.SetColumn(column, info)
+
+        event.Skip()
+
+    def GetSortImages(self):
+        """!Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py"""
+        return (self.sm_dn, self.sm_up)
+
+    def OnGetItemText(self, item, col):
+        """!Get item text"""
+        index = self.itemIndexMap[item]
+        s = str(self.itemDataMap[index][col])
+        return s
+
+    def OnGetItemAttr(self, item):
+        """!Get item attributes"""
+        index = self.itemIndexMap[item]
+        if ( index % 2) == 0:
+            return self.attr2
+        else:
+            return self.attr1
+
+    def SortItems(self, sorter = cmp):
+        """!Sort items"""
+        items = list(self.itemDataMap.keys())
+        items.sort(self.Sorter)
+        self.itemIndexMap = items
+
+        # redraw the list
+        self.Refresh()
+        
+    def Sorter(self, key1, key2):
+        colName = self.GetColumn(self._col).GetText()
+        ascending = self._colSortFlag[self._col]
+        # convert always string
+        item1 = self.itemDataMap[key1][self._col]
+        item2 = self.itemDataMap[key2][self._col]
+
+        if type(item1) == type('') or type(item2) == type(''):
+            cmpVal = locale.strcoll(str(item1), str(item2))
+        else:
+            cmpVal = cmp(item1, item2)
+
+
+        # If the items are equal then pick something else to make the sort value unique
+        if cmpVal == 0:
+            cmpVal = apply(cmp, self.GetSecondarySortValues(self._col, key1, key2))
+
+        if ascending:
+            return cmpVal
+        else:
+            return -cmpVal
+
+    def GetListCtrl(self):
+        """!Used by listmix.ColumnSorterMixin"""
+        return self
+
+    def Search (self, index, pattern):
+        """!Search projection by description
+        Return first found item or None
+        """
+        if pattern == '':
+            self.Populate(self.sourceData)
+            return []
+
+        data = []
+        pattern = pattern.lower()
+        for i in range(len(self.sourceData)):
+            for idx in index:
+                try:
+                    value = str(self.sourceData[i][idx]).lower()
+                    if pattern in value:
+                        data.append(self.sourceData[i])
+                        break
+                except UnicodeDecodeError:
+                    # osgeo4w problem (should be fixed)
+                    pass
+
+        self.Populate(data)
+        if len(data) > 0:
+            return data[0]
+        else:
+            return []
+
+class ProjParamsPage(TitledPage):
+    """!Wizard page for selecting method of setting coordinate system
+    parameters (select coordinate system option)
+    """
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Choose projection parameters"))
+        global coordsys
+        
+        self.parent = parent
+        self.panel = None
+        self.prjParamSizer = None
+        
+        self.pparam = dict()
+        
+        self.p4projparams = ''
+        self.projdesc = ''
+
+        self.sizer.AddGrowableCol(1)
+        self.sizer.AddGrowableRow(1)
+
+        radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                 label = " %s " % _("Select datum or ellipsoid (next page)"))
+        radioSBSizer = wx.StaticBoxSizer(radioSBox)
+        self.sizer.Add(item = radioSBSizer, pos = (0, 1),
+                       flag = wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border = 10)
+        
+        self.radio1 = wx.RadioButton(parent = self, id = wx.ID_ANY, 
+                                     label = _("Datum with associated ellipsoid"),
+                                     style  =  wx.RB_GROUP)
+        self.radio2 = wx.RadioButton(parent = self, id = wx.ID_ANY,
+                                     label = _("Ellipsoid only"))   
+        
+        # default button setting
+        if self.radio1.GetValue() == False and self.radio2.GetValue() == False:
+            self.radio1.SetValue(True)
+            self.SetNext(self.parent.datumpage)
+            #            self.parent.sumpage.SetPrev(self.parent.datumpage)  
+        
+        radioSBSizer.Add(item = self.radio1,
+                         flag = wx.ALIGN_LEFT | wx.RIGHT, border = 20)
+        radioSBSizer.Add(item = self.radio2,
+                         flag = wx.ALIGN_LEFT)
+        
+        # bindings
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio1.GetId())
+        self.Bind(wx.EVT_RADIOBUTTON, self.SetVal, id = self.radio2.GetId())
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChange)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        
+    def OnParamEntry(self, event):
+        """!Parameter value changed"""
+        id  = event.GetId()
+        val = event.GetString()
+        
+        if id not in self.pparam:
+            event.Skip()
+            return
+
+        param = self.pparam[id]
+        win = self.FindWindowById(id)
+        if param['type'] == 'zone':
+            val = event.GetInt()
+            if val < 1:
+                win.SetValue(1)
+            elif val > 60:
+                    win.SetValue(60)
+        
+        if param['type'] == 'bool':
+            param['value'] = event.GetSelection()
+        else:
+            param['value'] = val
+        
+        event.Skip()
+        
+    def OnPageChange(self,event=None):
+        """!Go to next page"""
+        if event.GetDirection():
+            self.p4projparams = ''
+            for id, param in self.pparam.iteritems():
+                if param['type'] == 'bool':
+                    if param['value'] == False:
+                        continue
+                    else:
+                        self.p4projparams += (' +' + param['proj4'])
+                else:
+                    if param['value'] is None:
+                        wx.MessageBox(parent = self,
+                                      message = _('You must enter a value for %s') % param['desc'],
+                                      caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
+                        event.Veto()
+                    else:
+                        self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
+
+    def OnEnterPage(self,event):
+        """!Page entered"""
+        self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
+        if self.prjParamSizer is None:
+            # entering page for the first time
+            self.paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                                     label = _(" Enter parameters for %s projection ") % self.projdesc)
+            paramSBSizer = wx.StaticBoxSizer(self.paramSBox)
+            
+            self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
+            self.panel.SetupScrolling()
+            
+            self.prjParamSizer = wx.GridBagSizer(vgap = 0, hgap = 0) 
+            
+            self.sizer.Add(item = paramSBSizer, pos = (1, 1),
+                           flag = wx.EXPAND)
+            paramSBSizer.Add(item = self.panel, proportion = 1, 
+                             flag = wx.ALIGN_CENTER | wx.EXPAND)
+            
+            paramSBSizer.Fit(self.panel)
+            self.panel.SetSizer(self.prjParamSizer)
+                    
+        if event.GetDirection(): 
+            self.prjParamSizer.Clear(True)
+            self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
+            self.pparam = dict()
+            row = 0
+            for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
+                # get parameters
+                id = wx.NewId()
+                param = self.pparam[id] = { 'type' : self.parent.paramdesc[paramgrp[0]][0],
+                                            'proj4': self.parent.paramdesc[paramgrp[0]][1],
+                                            'desc' : self.parent.paramdesc[paramgrp[0]][2] }
+                
+                # default values
+                if param['type'] == 'bool':
+                    param['value'] = 0
+                elif param['type'] == 'zone': 
+                    param['value'] = 30 
+                    param['desc'] += ' (1-60)'
+                else:
+                    param['value'] = paramgrp[2]
+                
+                label = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = param['desc'], 
+                                      style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
+                if param['type'] == 'bool':
+                    win = wx.Choice(parent = self.panel, id = id, size = (100,-1), 
+                                    choices = [_('No'), _('Yes')])  
+                    win.SetSelection(param['value'])
+                    win.Bind(wx.EVT_CHOICE, self.OnParamEntry)
+                elif param['type'] == 'zone':
+                    win = wx.SpinCtrl(parent = self.panel, id = id,
+                                      size = (100, -1), 
+                                      style = wx.SP_ARROW_KEYS | wx.SP_WRAP,
+                                      min = 1, max = 60)
+                    win.SetValue(param['value'])
+                    win.Bind(wx.EVT_SPINCTRL, self.OnParamEntry)
+                    win.Bind(wx.EVT_TEXT, self.OnParamEntry)
+                else:
+                    win = wx.TextCtrl(parent = self.panel, id = id,
+                                      value = param['value'],
+                                      size=(100, -1))
+                    win.Bind(wx.EVT_TEXT, self.OnParamEntry)
+                    if paramgrp[1] == 'noask':
+                        win.Enable(False)
+                    
+                self.prjParamSizer.Add(item = label, pos = (row, 1),
+                                       flag = wx.ALIGN_RIGHT | 
+                                       wx.ALIGN_CENTER_VERTICAL |
+                                       wx.RIGHT, border = 5)
+                self.prjParamSizer.Add(item = win, pos = (row, 2),
+                                       flag = wx.ALIGN_LEFT | 
+                                       wx.ALIGN_CENTER_VERTICAL |
+                                       wx.LEFT, border = 5)           
+                row += 1
+        
+        self.panel.SetSize(self.panel.GetBestSize())
+        self.panel.Layout()
+        self.Layout()
+        self.Update()
+        
+        if not wx.FindWindowById(wx.ID_FORWARD).IsEnabled():
+            wx.FindWindowById(wx.ID_FORWARD).Enable()
+        
+        event.Skip()
+
+    def SetVal(self, event):
+        """!Set value"""
+        if event.GetId() == self.radio1.GetId():
+            self.SetNext(self.parent.datumpage)
+            self.parent.sumpage.SetPrev(self.parent.datumpage)
+        elif event.GetId() == self.radio2.GetId():
+            self.SetNext(self.parent.ellipsepage)
+            self.parent.sumpage.SetPrev(self.parent.ellipsepage)
+    
+class DatumPage(TitledPage):
+    """!Wizard page for selecting datum (with associated ellipsoid)
+    and datum transformation parameters (select coordinate system option)
+    """
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Specify geodetic datum"))
+
+        self.parent = parent
+        self.datum = ''
+        self.datumdesc = ''
+        self.ellipse = ''
+        self.datumparams = ''
+        self.proj4params = ''
+
+        # text input
+        self.tdatum = self.MakeTextCtrl("", size = (200,-1))
+
+        # search box
+        self.searchb = wx.SearchCtrl(self, size = (200,-1),
+                                     style = wx.TE_PROCESS_ENTER)
+
+        # create list control for datum/elipsoid list
+        data = []
+        for key in self.parent.datums.keys():
+            data.append([key, self.parent.datums[key][0], self.parent.datums[key][1]])
+        self.datumlist = ItemList(self,
+                                  data = data,
+                                  columns = [_('Code'), _('Ellipsoid'), _('Description')])
+        self.datumlist.resizeLastColumn(10) 
+        
+        # layout
+        self.sizer.AddGrowableCol(4)
+        self.sizer.Add(item = self.MakeLabel(_("Datum code:")),
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.tdatum,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 2))
+
+        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 1))
+        self.sizer.Add(item = self.searchb,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 2))
+
+        self.sizer.AddGrowableRow(3)
+        self.sizer.Add(item = self.datumlist,
+                       flag = wx.EXPAND |
+                       wx.ALIGN_LEFT |
+                       wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
+
+        # events
+        self.datumlist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnDatumSelected)
+        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnDSearch)
+        self.tdatum.Bind(wx.EVT_TEXT, self.OnDText)
+        self.tdatum.Bind(wx.EVT_TEXT_ENTER, self.OnDText)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+
+        # do page layout
+        # self.DoLayout()
+
+    def OnPageChanging(self, event):
+        self.proj4params = ''
+        proj = self.parent.projpage.p4proj
+                
+        if event.GetDirection():
+            if self.datum not in self.parent.datums:
+                event.Veto()
+            else:
+                # check for datum tranforms            
+#                proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
+                ret = RunCommand('g.proj',
+                                 read = True,
+                                 proj4 = '%s +datum=%s' % (proj, self.datum), 
+                                 datumtrans = '-1')
+                if ret != '':
+                    dtrans = ''
+                    # open a dialog to select datum transform number
+                    dlg = SelectTransformDialog(self.parent.parent, transforms=ret)
+                    
+                    if dlg.ShowModal() == wx.ID_OK:
+                        dtrans = dlg.GetTransform()
+                        if dtrans == '':
+                            dlg.Destroy()
+                            event.Veto()
+                            return 'Datum transform is required.'
+                    else:
+                        dlg.Destroy()
+                        event.Veto()
+                        return 'Datum transform is required.'
+                    
+                    self.parent.datumtrans = dtrans
+                
+            self.GetNext().SetPrev(self)
+            self.parent.ellipsepage.ellipse = self.ellipse
+            self.parent.ellipsepage.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
+
+    def OnEnterPage(self,event):
+        self.parent.datumtrans = None
+        if event.GetDirection():
+            if len(self.datum) == 0:
+                # disable 'next' button by default when entering from previous page
+                wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+            else:
+                wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        event.Skip()
+
+    def OnDText(self, event):
+        """!Datum code changed"""
+        self.datum = event.GetString()
+
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(self.datum) == 0 or self.datum not in self.parent.datums:
+            nextButton.Enable(False)
+        else:
+            self.ellipse = self.parent.datums[self.datum][0]
+            self.datumdesc = self.parent.datums[self.datum][1]
+            self.datumparams = self.parent.datums[self.datum][2]
+            try:
+                self.datumparams.remove('dx=0.0')
+            except:
+                pass
+            try:
+                self.datumparams.remove('dy=0.0')
+            except:
+                pass
+            try:
+                self.datumparams.remove('dz=0.0')
+            except:
+                pass
+            
+            nextButton.Enable(True)
+            
+        self.Update()    
+        event.Skip()
+
+    def OnDSearch(self, event):
+        """!Search geodetic datum by desc"""
+        str =  self.searchb.GetValue()
+        try:
+            self.datum, self.ellipsoid, self.datumdesc = self.datumlist.Search(index = [0,1,2], pattern = str)
+        except:
+            self.datum = self.datumdesc = self.ellipsoid = ''
+
+        event.Skip()
+
+    def OnDatumSelected(self, event):
+        """!Datum selected"""
+        index = event.m_itemIndex
+        item = event.GetItem()
+
+        self.datum = self.datumlist.GetItem(index, 0).GetText()
+        self.tdatum.SetValue(self.datum)
+        
+        event.Skip()
+
+class EllipsePage(TitledPage):
+    """!Wizard page for selecting ellipsoid (select coordinate system option)"""
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Specify ellipsoid"))
+
+        self.parent = parent
+        
+        self.ellipse = ''
+        self.ellipsedesc = ''
+        self.ellipseparams = ''
+        self.proj4params = ''
+
+        # text input
+        self.tellipse = self.MakeTextCtrl("", size = (200,-1))
+
+        # search box
+        self.searchb = wx.SearchCtrl(self, size = (200,-1),
+                                     style = wx.TE_PROCESS_ENTER)
+
+        # create list control for ellipse list
+        data = []
+        # extract code, desc
+        for key in self.parent.ellipsoids.keys():
+            data.append([key, self.parent.ellipsoids[key][0]])
+
+        self.ellipselist = ItemList(self, data = data,
+                                    columns = [_('Code'), _('Description')])
+        self.ellipselist.resizeLastColumn(30)                             
+
+        # layout
+        self.sizer.AddGrowableCol(4)
+        self.sizer.Add(item = self.MakeLabel(_("Ellipsoid code:")),
+                       flag = wx.ALIGN_RIGHT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.tellipse,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 2))
+        self.sizer.Add(item = self.MakeLabel(_("Search in description:")),
+                       flag = wx.ALIGN_RIGHT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 1))
+        self.sizer.Add(item = self.searchb,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 2))
+
+        self.sizer.AddGrowableRow(3)
+        self.sizer.Add(item = self.ellipselist,
+                       flag = wx.EXPAND |
+                       wx.ALIGN_LEFT |
+                       wx.ALL, border = 5, pos = (3, 1), span = (1, 4))
+
+        # events
+        self.ellipselist.Bind(wx.EVT_LIST_ITEM_SELECTED,    self.OnItemSelected)
+        self.tellipse.Bind(wx.EVT_TEXT, self.OnText)
+        self.tellipse.Bind(wx.EVT_TEXT_ENTER, self.OnText)
+        self.searchb.Bind(wx.EVT_TEXT_ENTER,    self.OnSearch)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+
+    def OnEnterPage(self,event):
+        if len(self.ellipse) == 0:
+            # disable 'next' button by default
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        if event.GetDirection() and self.ellipse not in self.parent.ellipsoids:
+            event.Veto()
+
+        self.proj4params = ''
+        self.GetNext().SetPrev(self)
+        self.parent.datumpage.datumparams = ''
+        # self.GetNext().SetPrev(self) (???)
+
+    def OnText(self, event):
+        """!Ellipspoid code changed"""
+        self.ellipse = event.GetString()
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(self.ellipse) == 0 or self.ellipse not in self.parent.ellipsoids:
+            nextButton.Enable(False)
+            self.ellipsedesc = ''
+            self.ellipseparams = ''
+            self.proj4params = ''
+        elif self.ellipse in self.parent.ellipsoids:
+            self.ellipsedesc = self.parent.ellipsoids[self.ellipse][0]
+            self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
+            nextButton.Enable(True)
+
+    def OnSearch(self, event):
+        """!Search ellipsoid by desc"""
+        try:
+            self.ellipse, self.ellipsedesc = \
+                self.ellipselist.Search(index=[0,1], pattern=event.GetString())
+            self.ellipseparams = self.parent.ellipsoids[self.ellipse][1]
+        except:
+            self.ellipse = self.ellipsedesc = self.ellipseparams = ''
+
+        event.Skip()
+
+    def OnItemSelected(self,event):
+        """!Ellipsoid selected"""
+        index = event.m_itemIndex
+        item = event.GetItem()
+
+        self.ellipse = self.ellipselist.GetItem(index, 0).GetText()
+        self.tellipse.SetValue(self.ellipse)
+        
+        event.Skip()
+
+class GeoreferencedFilePage(TitledPage):
+    """!Wizard page for selecting georeferenced file to use
+    for setting coordinate system parameters"""
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Select georeferenced file"))
+
+        self.georeffile = ''
+
+        # create controls
+        self.lfile= self.MakeLabel(_("Georeferenced file:"))
+        self.tfile = self.MakeTextCtrl(size = (300,-1))
+        self.bbrowse = self.MakeButton(_("Browse"))
+
+        # do layout
+        self.sizer.AddGrowableCol(3)
+        self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTRE_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTRE_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 2))
+        self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
+                       wx.ALL, border = 5, pos = (1, 3))
+
+        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
+        self.tfile.Bind(wx.EVT_TEXT, self.OnText)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+
+        # do page layout
+        # self.DoLayout()
+
+    def OnEnterPage(self, event):
+        if len(self.georeffile) == 0:
+            # disable 'next' button by default
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        if event.GetDirection() and not os.path.isfile(self.georeffile):
+            event.Veto()
+        self.GetNext().SetPrev(self)
+
+        event.Skip()
+
+    def OnText(self, event):
+        """!File changed"""
+        self.georeffile = event.GetString()
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(self.georeffile) > 0 and os.path.isfile(self.georeffile):
+            if not nextButton.IsEnabled():
+                nextButton.Enable(True)
+        else:
+            if nextButton.IsEnabled():
+                nextButton.Enable(False)
+
+        event.Skip()
+
+    def OnBrowse(self, event):
+        """!Choose file"""
+        dlg = wx.FileDialog(self,
+                            _("Select georeferenced file"),
+                            os.getcwd(), "", "*.*", wx.OPEN)
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            self.tfile.SetValue(path)
+        dlg.Destroy()
+
+        event.Skip()
+
+class WKTPage(TitledPage):
+    """!Wizard page for selecting WKT file to use
+    for setting coordinate system parameters"""
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Select WKT file"))
+
+        self.wktfile = ''
+
+        # create controls
+        self.lfile= self.MakeLabel(_("WKT file:"))
+        self.tfile = self.MakeTextCtrl(size = (300,-1))
+        self.bbrowse = self.MakeButton(_("Browse"))
+
+        # do layout
+        self.sizer.AddGrowableCol(3)
+        self.sizer.Add(item = self.lfile, flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTRE_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.tfile, flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTRE_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 2))
+        self.sizer.Add(item = self.bbrowse, flag = wx.ALIGN_LEFT |
+                       wx.ALL, border = 5, pos = (1, 3))
+
+        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
+        self.tfile.Bind(wx.EVT_TEXT, self.OnText)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+
+    def OnEnterPage(self, event):
+        if len(self.wktfile) == 0:
+            # disable 'next' button by default
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        if event.GetDirection() and not os.path.isfile(self.wktfile):
+            event.Veto()
+        self.GetNext().SetPrev(self)
+
+        event.Skip()
+
+    def OnText(self, event):
+        """!File changed"""
+        self.wktfile = event.GetString()
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(self.wktfile) > 0 and os.path.isfile(self.wktfile):
+            if not nextButton.IsEnabled():
+                nextButton.Enable(True)
+        else:
+            if nextButton.IsEnabled():
+                nextButton.Enable(False)
+
+        event.Skip()
+
+    def OnBrowse(self, event):
+        """!Choose file"""
+        dlg = wx.FileDialog(self,
+                            _("Select WKT file"),
+                            os.getcwd(), "", "*.*", wx.OPEN)
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            self.tfile.SetValue(path)
+        dlg.Destroy()
+
+        event.Skip()
+
+class EPSGPage(TitledPage):
+    """!Wizard page for selecting EPSG code for
+    setting coordinate system parameters"""
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Choose EPSG Code"))
+        self.parent = parent
+        self.epsgCodeDict = {}
+        self.epsgcode = None
+        self.epsgdesc = ''
+        self.epsgparams = ''
+
+        # labels
+        self.lfile = self.MakeLabel(_("Path to the EPSG-codes file:"),
+                                    style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        self.lcode = self.MakeLabel(_("EPSG code:"),
+                                    style = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        # text input
+        epsgdir = utils.PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
+        self.tfile = self.MakeTextCtrl(text = epsgdir, size = (200,-1),
+                                       style = wx.TE_PROCESS_ENTER)
+        self.tcode = self.MakeTextCtrl(size = (200,-1))
+
+        # buttons
+        self.bbrowse = self.MakeButton(_("Browse"))
+        
+        # search box
+        self.searchb = wx.SearchCtrl(self, size = (200,-1),
+                                     style = wx.TE_PROCESS_ENTER)
+
+        self.epsglist = ItemList(self, data = None,
+                                 columns = [_('Code'), _('Description'), _('Parameters')])
+
+        # layout
+        self.sizer.AddGrowableCol(3)
+        self.sizer.Add(item = self.lfile,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 1), span = (1, 2))
+        self.sizer.Add(item = self.tfile,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 3))
+        self.sizer.Add(item = self.bbrowse,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (1, 4))
+        self.sizer.Add(item = self.lcode,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 1), span = (1, 2))
+        self.sizer.Add(item = self.tcode,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (2, 3))
+        self.sizer.Add(item = self.searchb,
+                       flag = wx.ALIGN_LEFT |
+                       wx.ALIGN_CENTER_VERTICAL |
+                       wx.ALL, border = 5, pos = (3, 3))
+        
+        self.sizer.AddGrowableRow(4)
+        self.sizer.Add(item = self.epsglist,
+                       flag = wx.ALIGN_LEFT | wx.EXPAND, pos = (4, 1),
+                       span = (1, 4))
+
+        # events
+        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
+        self.tfile.Bind(wx.EVT_TEXT_ENTER, self.OnBrowseCodes)
+        self.tcode.Bind(wx.EVT_TEXT, self.OnText)
+        self.tcode.Bind(wx.EVT_TEXT_ENTER, self.OnText)
+        self.epsglist.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+        self.searchb.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+
+    def OnEnterPage(self, event):
+        self.parent.datumtrans = None
+        if event.GetDirection():
+            if not self.epsgcode:
+                # disable 'next' button by default
+                wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+            else:
+                wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+        # load default epsg database file
+        self.OnBrowseCodes(None)
+        
+        event.Skip()
+
+    def OnPageChanging(self, event):
+        if event.GetDirection():
+            if not self.epsgcode:
+                event.Veto()
+                return
+            else:              
+                # check for datum transforms
+                ret = RunCommand('g.proj',
+                                 read = True,
+                                 epsg = self.epsgcode,
+                                 datumtrans = '-1')
+                
+                if ret != '':
+                    dtrans = ''
+                    # open a dialog to select datum transform number
+                    dlg = SelectTransformDialog(self.parent.parent, transforms = ret)
+                    
+                    if dlg.ShowModal() == wx.ID_OK:
+                        dtrans = dlg.GetTransform()
+                        if dtrans == '':
+                            dlg.Destroy()
+                            event.Veto()
+                            return 'Datum transform is required.'
+                    else:
+                        dlg.Destroy()
+                        event.Veto()
+                        return 'Datum transform is required.'
+                    
+                    self.parent.datumtrans = dtrans
+            self.GetNext().SetPrev(self)
+
+    def OnText(self, event):
+        self.epsgcode = event.GetString()
+        try:
+            self.epsgcode = int(self.epsgcode)
+        except:
+            self.epsgcode = None
+            
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+
+        if self.epsgcode and self.epsgcode in self.epsgCodeDict.keys():
+            self.epsgdesc = self.epsgCodeDict[self.epsgcode][0]
+            self.epsgparams = self.epsgCodeDict[self.epsgcode][1]
+            if not nextButton.IsEnabled():
+                nextButton.Enable(True)
+        else:
+            self.epsgcode = None # not found
+            if nextButton.IsEnabled():
+                nextButton.Enable(False)
+            self.epsgdesc = self.epsgparams = ''
+        
+    def OnSearch(self, event):
+        value =  self.searchb.GetValue()
+        
+        if value == '':
+            self.epsgcode = None
+            self.epsgdesc = self.epsgparams = ''
+            self.tcode.SetValue('')
+            self.searchb.SetValue('')
+            self.OnBrowseCodes(None)
+        else:    
+            try:
+                self.epsgcode, self.epsgdesc, self.epsgparams = \
+                        self.epsglist.Search(index=[0,1,2], pattern=value)
+            except (IndexError, ValueError): # -> no item found
+                self.epsgcode = None
+                self.epsgdesc = self.epsgparams = ''
+                self.tcode.SetValue('')
+                self.searchb.SetValue('')
+
+        event.Skip()
+        
+    def OnBrowse(self, event):
+        """!Define path for EPSG code file"""
+        path = os.path.dirname(self.tfile.GetValue())
+        if not path:
+            path = os.getcwd()
+        
+        dlg = wx.FileDialog(parent = self, message = _("Choose EPSG codes file"),
+                            defaultDir = path, defaultFile = "", wildcard = "*", style = wx.OPEN)
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            self.tfile.SetValue(path)
+            self.OnBrowseCodes(None)
+        
+        dlg.Destroy()
+
+        event.Skip()
+
+    def OnItemSelected(self, event):
+        """!EPSG code selected from the list"""
+        index = event.m_itemIndex
+        item = event.GetItem()
+
+        self.epsgcode = int(self.epsglist.GetItem(index, 0).GetText())
+        self.epsgdesc = self.epsglist.GetItem(index, 1).GetText()
+        self.tcode.SetValue(str(self.epsgcode))
+
+        event.Skip()
+        
+    def OnBrowseCodes(self, event, search = None):
+        """!Browse EPSG codes"""
+        self.epsgCodeDict = utils.ReadEpsgCodes(self.tfile.GetValue())
+
+        if type(self.epsgCodeDict) != dict:
+            wx.MessageBox(parent = self,
+                          message = _("Unable to read EPGS codes: %s") % self.epsgCodeDict,
+                          caption = _("Error"),  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+            self.epsglist.Populate(list(), update = True)
+            return
+        
+        data = list()
+        for code, val in self.epsgCodeDict.iteritems():
+            if code is not None:
+                data.append((code, val[0], val[1]))
+        
+        self.epsglist.Populate(data, update = True)
+        
+class CustomPage(TitledPage):
+    """!Wizard page for entering custom PROJ.4 string
+    for setting coordinate system parameters"""
+
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard,
+                            _("Choose method of specifying georeferencing parameters"))
+        global coordsys
+        self.customstring = ''
+        self.parent = parent
+
+        # widgets
+        self.text_proj4string = self.MakeTextCtrl(size = (400, 200),
+                                                  style = wx.TE_MULTILINE)
+        self.label_proj4string = self.MakeLabel(_("Enter PROJ.4 parameters string:"))
+
+        # layout
+        self.sizer.AddGrowableCol(2)
+        self.sizer.Add(self.label_proj4string,
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (1, 1))
+        self.sizer.AddGrowableRow(2)
+        self.sizer.Add(self.text_proj4string,
+                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, 
+                       border = 5, pos = (2, 1), span = (1, 2))
+
+        self.text_proj4string.Bind(wx.EVT_TEXT, self.GetProjstring)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+
+    def OnEnterPage(self, event):
+        if len(self.customstring) == 0:
+            # disable 'next' button by default
+            wx.FindWindowById(wx.ID_FORWARD).Enable(False)
+        else:
+            wx.FindWindowById(wx.ID_FORWARD).Enable(True)
+
+    def OnPageChanging(self, event):
+        if event.GetDirection():
+        # check for datum tranforms            
+            ret, out, err = RunCommand('g.proj',
+                                       read = True, getErrorMsg = True,
+                                       proj4 = self.customstring, 
+                                       datumtrans = '-1')
+            if ret != 0:
+                wx.MessageBox(parent = self,
+                              message = err,
+                              caption = _("Error"),
+                              style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                event.Veto()
+                return
+            
+            if out:
+                dtrans = ''
+                # open a dialog to select datum transform number
+                dlg = SelectTransformDialog(self.parent.parent, transforms = out)
+                
+                if dlg.ShowModal() == wx.ID_OK:
+                    dtrans = dlg.GetTransform()
+                    if len(dtrans) == 0:
+                        dlg.Destroy()
+                        event.Veto()
+                        return _('Datum transform is required.')
+                else:
+                    dlg.Destroy()
+                    event.Veto()
+                    return _('Datum transform is required.')
+                
+                self.parent.datumtrans = dtrans
+        
+        self.GetNext().SetPrev(self)
+            
+    def GetProjstring(self, event):
+        """!Change proj string"""
+        # TODO: check PROJ.4 syntax
+        self.customstring = event.GetString()
+        nextButton = wx.FindWindowById(wx.ID_FORWARD)
+        if len(self.customstring) == 0:
+            if nextButton.IsEnabled():
+                nextButton.Enable(False)
+        else:
+            if not nextButton.IsEnabled():
+                nextButton.Enable()
+
+class SummaryPage(TitledPage):
+    """!Shows summary result of choosing coordinate system parameters
+    prior to creating location"""
+    def __init__(self, wizard, parent):
+        TitledPage.__init__(self, wizard, _("Summary"))
+        self.parent = parent
+
+        self.panelTitle = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
+        self.panelProj4string = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
+        self.panelProj = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
+
+        # labels
+        self.ldatabase    = self.MakeLabel()
+        self.llocation    = self.MakeLabel()
+        self.llocTitle    = self.MakeLabel(parent = self.panelTitle)
+        self.lprojection  = self.MakeLabel(parent = self.panelProj)
+        self.lproj4string = self.MakeLabel(parent = self.panelProj4string)
+        
+        self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
+        
+        # do sub-page layout
+        self._doLayout()
+        
+    def _doLayout(self):
+        """!Do page layout"""
+        self.sizer.AddGrowableCol(1)
+        self.sizer.AddGrowableRow(3, 1)
+        self.sizer.AddGrowableRow(4, 1)
+        self.sizer.AddGrowableRow(5, 5)
+
+        titleSizer = wx.BoxSizer(wx.VERTICAL)
+        titleSizer.Add(item = self.llocTitle, proportion = 1,
+                       flag = wx.EXPAND | wx.ALL, border = 5)
+        self.panelTitle.SetSizer(titleSizer)        
+        
+        projSizer = wx.BoxSizer(wx.VERTICAL)
+        projSizer.Add(item = self.lprojection, proportion = 1,
+                       flag = wx.EXPAND | wx.ALL, border = 5)
+        self.panelProj.SetSizer(projSizer)        
+        
+        proj4stringSizer = wx.BoxSizer(wx.VERTICAL)
+        proj4stringSizer.Add(item = self.lproj4string, proportion = 1,
+                       flag = wx.EXPAND | wx.ALL, border = 5)
+        self.panelProj4string.SetSizer(proj4stringSizer)
+
+        self.panelProj4string.SetupScrolling()
+        self.panelProj.SetupScrolling(scroll_y = False)
+        self.panelTitle.SetupScrolling(scroll_y = False)
+
+        self.sizer.Add(item = self.MakeLabel(_("GRASS Database:")),
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (1, 0))
+        self.sizer.Add(item = self.ldatabase, 
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (1, 1))
+        self.sizer.Add(item = self.MakeLabel(_("Location Name:")),
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (2, 0))
+        self.sizer.Add(item = self.llocation,
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (2, 1))
+        self.sizer.Add(item = self.MakeLabel(_("Location Title:")),
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (3, 0))
+        self.sizer.Add(item = self.panelTitle,
+                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
+                       border = 0, pos = (3, 1))
+        self.sizer.Add(item = self.MakeLabel(_("Projection:")),
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (4, 0))
+        self.sizer.Add(item = self.panelProj,
+                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
+                       border = 0, pos = (4, 1))
+        self.sizer.Add(item = self.MakeLabel(_("PROJ.4 definition:")),
+                       flag = wx.ALIGN_LEFT | wx.ALL,
+                       border = 5, pos = (5, 0))
+        self.sizer.Add(item = self.panelProj4string,
+                       flag = wx.ALIGN_LEFT | wx.ALL | wx.EXPAND,
+                       border = 0, pos = (5, 1))
+   
+    def OnEnterPage(self, event):
+        """!Insert values into text controls for summary of location
+        creation options
+        """
+        database = self.parent.startpage.grassdatabase
+        location = self.parent.startpage.location
+        proj4string = self.parent.CreateProj4String()
+        epsgcode = self.parent.epsgpage.epsgcode
+        dtrans = self.parent.datumtrans
+        
+        global coordsys
+        if coordsys in ('proj', 'epsg'):
+            if coordsys == 'proj':
+                ret, projlabel, err = RunCommand('g.proj',
+                                                 flags = 'jf',
+                                                 proj4 = proj4string,
+                                                 datumtrans = dtrans,
+                                                 location = location,
+                                                 getErrorMsg = True,
+                                                 read = True)
+            elif coordsys == 'epsg':
+                ret, projlabel, err = RunCommand('g.proj',
+                                                 flags = 'jf',
+                                                 epsg = epsgcode,
+                                                 datumtrans = dtrans,
+                                                 location = location,
+                                                 getErrorMsg = True,
+                                                 read = True)
+
+            finishButton = wx.FindWindowById(wx.ID_FORWARD)
+            if ret == 0:
+                self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
+                finishButton.Enable(True)
+            else:
+                GError(err, parent = self)
+                self.lproj4string.SetLabel('')
+                finishButton.Enable(False)
+        
+        projdesc = self.parent.projpage.projdesc
+        ellipsedesc = self.parent.ellipsepage.ellipsedesc
+        datumdesc = self.parent.datumpage.datumdesc
+        self.ldatabase.SetLabel(database)
+        self.llocation.SetLabel(location)
+        self.llocTitle.SetLabel(self.parent.startpage.locTitle)
+        
+        label = ''
+        if coordsys == 'epsg':
+            label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
+        elif coordsys == 'file':
+            label = 'matches file %s' % self.parent.filepage.georeffile
+            self.lproj4string.SetLabel("")
+        elif coordsys == 'wkt':
+            label = 'matches file %s' % self.parent.wktpage.wktfile
+            self.lproj4string.SetLabel("")
+        elif coordsys == 'proj':
+            label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
+        elif coordsys == 'xy':
+            label = ('XY coordinate system (not projected).')
+            self.lproj4string.SetLabel("")
+        elif coordsys == 'custom':
+            label = _("custom")
+            self.lproj4string.SetLabel(('%s' % self.parent.custompage.customstring.replace(' ', os.linesep)))
+        self.lprojection.SetLabel(label)
+        
+    def OnFinish(self, event):
+        dlg = wx.MessageDialog(parent = self.wizard,
+                               message = _("Do you want to create GRASS location <%s>?") % location,
+                               caption = _("Create new location?"),
+                               style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+        
+        if dlg.ShowModal() == wx.ID_NO:
+            dlg.Destroy()
+            event.Veto()
+        else:
+            dlg.Destroy()
+            event.Skip()
+
+class LocationWizard(wx.Object):
+    """!Start wizard here and finish wizard here
+    """
+    def __init__(self, parent, grassdatabase):
+        self.__cleanUp()
+        
+        global coordsys
+        self.parent = parent
+        
+        #
+        # define wizard image
+        #
+        imagePath = os.path.join(globalvar.ETCIMGDIR, "loc_wizard_qgis.png")
+        wizbmp = wx.Image(imagePath, wx.BITMAP_TYPE_PNG)
+        wizbmp = wizbmp.ConvertToBitmap()
+        
+        #
+        # get georeferencing information from tables in $GISBASE/etc
+        #
+        self.__readData()
+        
+        #
+        # datum transform number and list of datum transforms
+        #
+        self.datumtrans = None
+        self.proj4string = ''
+        
+        #
+        # define wizard pages
+        #
+        self.wizard = wiz.Wizard(parent, id = wx.ID_ANY, title = _("Define new GRASS Location"),
+                                 bitmap = wizbmp, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+        self.startpage = DatabasePage(self.wizard, self, grassdatabase)
+        self.csystemspage = CoordinateSystemPage(self.wizard, self)
+        self.projpage = ProjectionsPage(self.wizard, self)
+        self.datumpage = DatumPage(self.wizard, self)
+        self.paramspage = ProjParamsPage(self.wizard,self)
+        self.epsgpage = EPSGPage(self.wizard, self)
+        self.filepage = GeoreferencedFilePage(self.wizard, self)
+        self.wktpage = WKTPage(self.wizard, self)
+        self.ellipsepage = EllipsePage(self.wizard, self)
+        self.custompage = CustomPage(self.wizard, self)
+        self.sumpage = SummaryPage(self.wizard, self)
+
+        #
+        # set the initial order of the pages
+        # (should follow the epsg line)
+        #
+        self.startpage.SetNext(self.csystemspage)
+
+        self.csystemspage.SetPrev(self.startpage)
+        self.csystemspage.SetNext(self.sumpage)
+
+        self.projpage.SetPrev(self.csystemspage)
+        self.projpage.SetNext(self.paramspage)
+
+        self.paramspage.SetPrev(self.projpage)
+        self.paramspage.SetNext(self.datumpage)
+
+        self.datumpage.SetPrev(self.paramspage)
+        self.datumpage.SetNext(self.sumpage)
+
+        self.ellipsepage.SetPrev(self.paramspage)
+        self.ellipsepage.SetNext(self.sumpage)
+
+        self.epsgpage.SetPrev(self.csystemspage)
+        self.epsgpage.SetNext(self.sumpage)
+
+        self.filepage.SetPrev(self.csystemspage)
+        self.filepage.SetNext(self.sumpage)
+
+        self.wktpage.SetPrev(self.csystemspage)
+        self.wktpage.SetNext(self.sumpage)
+
+        self.custompage.SetPrev(self.csystemspage)
+        self.custompage.SetNext(self.sumpage)
+
+        self.sumpage.SetPrev(self.csystemspage)
+        
+        #
+        # do pages layout
+        #
+        self.startpage.DoLayout()
+        self.csystemspage.DoLayout()
+        self.projpage.DoLayout()
+        self.datumpage.DoLayout()
+        self.paramspage.DoLayout()
+        self.epsgpage.DoLayout()
+        self.filepage.DoLayout()
+        self.wktpage.DoLayout()
+        self.ellipsepage.DoLayout()
+        self.custompage.DoLayout()
+        self.sumpage.DoLayout()
+        self.wizard.FitToPage(self.datumpage)
+        size = self.wizard.GetPageSize()
+        self.wizard.SetPageSize((size[0], size[1] + 75))
+        
+        # new location created?
+        self.location = None 
+        success = False
+        
+        # location created in different GIS database?
+        self.altdb = False
+
+        #
+        # run wizard...
+        #
+        if self.wizard.RunWizard(self.startpage):
+            msg = self.OnWizFinished()
+            if not msg:
+                self.wizard.Destroy()
+                self.location = self.startpage.location
+                
+                if self.altdb == False: 
+                    dlg = wx.MessageDialog(parent = self.parent,
+                                           message = _("Do you want to set the default "
+                                                     "region extents and resolution now?"),
+                                           caption = _("Location <%s> created") % self.location,
+                                           style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+                    dlg.CenterOnScreen()
+                    if dlg.ShowModal() == wx.ID_YES:
+                        dlg.Destroy()
+                        defineRegion = RegionDef(self.parent, location = self.location)
+                        defineRegion.CenterOnScreen()
+                        defineRegion.Show()
+                    else:
+                        dlg.Destroy()
+            else: # -> error
+                self.wizard.Destroy()
+                GError(parent = self.parent,
+                       message = "%s" % _("Unable to create new location. "
+                                          "Location <%(loc)s> not created.\n\n"
+                                          "Details: %(err)s") % \
+                           { 'loc' : self.startpage.location,
+                             'err' : msg })
+        else: # -> cancelled
+            self.wizard.Destroy()
+            GMessage(parent = self.parent,
+                     message = _("Location wizard canceled. "
+                                 "Location not created."))
+            
+        self.__cleanUp()
+        
+    def __cleanUp(self):
+        global coordsys
+        global north
+        global south
+        global east
+        global west
+        global resolution
+        global wizerror
+        global translist
+        
+        coordsys = None
+        north = None
+        south = None
+        east = None
+        west = None
+        resolution = None
+        transformlist = list()
+
+    def __readData(self):
+        """!Get georeferencing information from tables in $GISBASE/etc"""
+
+        # read projection and parameters
+        f = open(os.path.join(globalvar.ETCDIR, "proj-parms.table"), "r")
+        self.projections = {}
+        self.projdesc = {}
+        for line in f.readlines():
+            line = line.strip()
+            try:
+                proj, projdesc, params = line.split(':')
+                paramslist = params.split(';')
+                plist = []
+                for p in paramslist:
+                    if p == '': continue
+                    p1, pdefault = p.split(',')
+                    pterm, pask = p1.split('=')
+                    p = [pterm.strip(), pask.strip(), pdefault.strip()]
+                    plist.append(p)
+                self.projections[proj.lower().strip()] = (projdesc.strip(), plist)
+                self.projdesc[proj.lower().strip()] = projdesc.strip()
+            except:
+                continue
+        f.close()
+
+        # read datum definitions
+        f = open(os.path.join(globalvar.ETCDIR, "datum.table"), "r")
+        self.datums = {}
+        paramslist = []
+        for line in f.readlines():
+            line = line.expandtabs(1)
+            line = line.strip()
+            if line == '' or line[0] == "#":
+                continue
+            datum, info = line.split(" ", 1)
+            info = info.strip()
+            datumdesc, params = info.split(" ", 1)
+            datumdesc = datumdesc.strip('"')
+            paramlist = params.split()
+            ellipsoid = paramlist.pop(0)
+            self.datums[datum] = (ellipsoid, datumdesc.replace('_', ' '), paramlist)
+        f.close()
+
+        # read ellipsiod definitions
+        f = open(os.path.join(globalvar.ETCDIR, "ellipse.table"), "r")
+        self.ellipsoids = {}
+        for line in f.readlines():
+            line = line.expandtabs(1)
+            line = line.strip()
+            if line == '' or line[0] == "#":
+                continue
+            ellipse, rest = line.split(" ", 1)
+            rest = rest.strip('" ')
+            desc, params = rest.split('"', 1)
+            desc = desc.strip('" ')
+            paramslist = params.split()
+            self.ellipsoids[ellipse] = (desc, paramslist)
+        f.close()
+        
+        # read projection parameter description and parsing table
+        f = open(os.path.join(globalvar.ETCDIR, "proj-desc.table"), "r")
+        self.paramdesc = {}
+        for line in f.readlines():
+            line = line.strip()
+            try:
+                pparam, datatype, proj4term, desc = line.split(':')
+                self.paramdesc[pparam] = (datatype, proj4term, desc)
+            except:
+                continue
+        f.close()
+
+    def OnWizFinished(self):
+        """!Wizard finished, create new location
+
+        @return error message on error
+        @return None on success
+        """
+        database = self.startpage.grassdatabase
+        location = self.startpage.location
+        
+        # location already exists?
+        if os.path.isdir(os.path.join(database,location)):
+            GError(parent = self.wizard,
+                   message = "%s <%s>: %s" % \
+                       (_("Unable to create new location"),
+                        os.path.join(database, location),
+                        _("Location already exists in GRASS Database.")))
+            return None
+        
+        # current GISDbase or a new one?
+        current_gdb = grass.gisenv()['GISDBASE']
+        if current_gdb != database:
+            # change to new GISDbase or create new one
+            if os.path.isdir(database) != True:
+                # create new directory
+                os.mkdir(database)
+            
+            # change to new GISDbase directory
+            RunCommand('g.gisenv',
+                       parent = self.wizard,
+                       set = 'GISDBASE=%s' % database)
+            
+            wx.MessageBox(parent = self.wizard,
+                          message = _("Location <%(loc)s> will be created "
+                                    "in GIS data directory <%(dir)s>. "
+                                    "You will need to change the default GIS "
+                                    "data directory in the GRASS startup screen.") % \
+                              { 'loc' : location, 'dir' : database},
+                          caption = _("New GIS data directory"), 
+                          style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            
+            # location created in alternate GISDbase
+            self.altdb = True
+        
+        global coordsys
+        try:
+            if coordsys == "xy":
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      desc = self.startpage.locTitle)
+            elif coordsys == "proj":
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      proj4 = self.CreateProj4String(),
+                                      datum = self.datumtrans,
+                                      desc = self.startpage.locTitle)
+            elif coordsys == 'custom':
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      proj4 = self.custompage.customstring,
+                                      desc = self.startpage.locTitle)
+            elif coordsys == "epsg":
+                if not self.epsgpage.epsgcode:
+                    return _('EPSG code missing.')
+                
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      epsg = self.epsgpage.epsgcode,
+                                      datum = self.datumtrans,
+                                      desc = self.startpage.locTitle)
+            elif coordsys == "file":
+                if not self.filepage.georeffile or \
+                        not os.path.isfile(self.filepage.georeffile):
+                    return _("File <%s> not found." % self.filepage.georeffile)
+                
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      filename = self.filepage.georeffile,
+                                      desc = self.startpage.locTitle)
+            elif coordsys == "wkt":
+                if not self.wktpage.wktfile or \
+                        not os.path.isfile(self.wktpage.wktfile):
+                    return _("File <%s> not found." % self.wktpage.wktfile)
+                
+                grass.create_location(dbase = self.startpage.grassdatabase,
+                                      location = self.startpage.location,
+                                      wkt = self.wktpage.wktfile,
+                                      desc = self.startpage.locTitle)
+        
+        except grass.ScriptError, e:
+            return e.value
+        
+        return None
+    
+    def CreateProj4String(self):
+        """!Constract PROJ.4 string"""
+        location = self.startpage.location
+        proj = self.projpage.p4proj
+        projdesc = self.projpage.projdesc
+        proj4params = self.paramspage.p4projparams
+                
+        datum = self.datumpage.datum
+        if self.datumpage.datumdesc:
+            datumdesc = self.datumpage.datumdesc +' - ' + self.datumpage.ellipse
+        else:
+            datumdesc = ''
+        datumparams = self.datumpage.datumparams        
+        ellipse = self.ellipsepage.ellipse
+        ellipsedesc = self.ellipsepage.ellipsedesc
+        ellipseparams = self.ellipsepage.ellipseparams
+                
+        #
+        # creating PROJ.4 string
+        #
+        proj4string = '%s %s' % (proj, proj4params)
+                            
+        # set ellipsoid parameters
+        if ellipse != '':
+            proj4string = '%s +ellps=%s' % (proj4string, ellipse)
+        for item in ellipseparams:
+            if item[:4] == 'f=1/':
+                item = ' +rf=' + item[4:]
+            else:
+                item = ' +' + item
+            proj4string = '%s %s' % (proj4string, item)
+            
+        # set datum and transform parameters if relevant
+        if datum != '':
+            proj4string = '%s +datum=%s' % (proj4string, datum)
+        if datumparams:
+            for item in datumparams:
+                proj4string = '%s +%s' % (proj4string,item)
+
+        proj4string = '%s +no_defs' % proj4string
+        
+        return proj4string

Copied: grass/trunk/gui/wxpython/mapdisp/frame.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/mapdisp.py)
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1505 @@
+"""!
+ at package mapdisp.frame
+
+ at brief Map display with toolbar for various display management
+functions, and additional toolbars (vector digitizer, 3d view).
+
+Can be used either from Layer Manager or as d.mon backend.
+
+Classes:
+ - MapFrame
+ - MapApp
+
+Usage:
+python mapdisp.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
+
+(C) 2006-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
+ at author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
+"""
+
+import os
+import sys
+import math
+import copy
+
+from core import globalvar
+import wx
+import wx.aui
+
+sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
+sys.path.append(os.path.join(globalvar.ETCDIR,   "python"))
+
+from core               import globalvar
+from core.render        import EVT_UPDATE_PRGBAR, Map
+from vdigit.toolbars    import VDigitToolbar
+from mapdisp.toolbars   import MapToolbar
+from mapdisp.gprint     import PrintOptions
+from core.gcmd          import GError, GMessage, RunCommand
+from dbm.dialogs        import DisplayAttributesDialog
+from core.utils         import ListOfCatsToRange, GetLayerNameFromCmd
+from gui_core.dialogs   import GetImageHandlers, ImageSizeDialog, DecorationDialog, TextLayerDialog
+from core.debug         import Debug
+from icon               import Icons
+from core.settings      import UserSettings
+from gui_core.mapdisp   import MapFrameBase
+from mapdisp.window     import BufferedWindow
+from modules.histogram  import HistFrame
+from wxplot.histogram   import HistFrame as HistFramePyPlot
+from wxplot.profile     import ProfileFrame
+from wxplot.scatter     import ScatterFrame
+
+from mapdisp import statusbar as sb
+
+from grass.script import core as grass
+
+# for standalone app
+monFile = { 'cmd' : None,
+            'map' : None,
+            'env' : None,
+            }
+monName = None
+monSize = list(globalvar.MAP_WINDOW_SIZE)
+
+haveCtypes = False
+
+class MapFrame(MapFrameBase):
+    """!Main frame for map display window. Drawing takes place in
+    child double buffered drawing window.
+    """
+    def __init__(self, parent = None, title = _("GRASS GIS - Map display"),
+                 toolbars = ["map"], tree = None, notebook = None, lmgr = None,
+                 page = None, Map = None, auimgr = None, name = 'MapWindow', **kwargs):
+        """!Main map display window with toolbars, statusbar and
+        BufferedWindow (map canvas)
+        
+        @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 name frame name
+        @param kwargs wx.Frame attributes
+        """
+        MapFrameBase.__init__(self, parent = parent, title = title, toolbars = toolbars,
+                              Map = Map, auimgr = auimgr, name = name, **kwargs)
+        
+        self._layerManager = lmgr   # Layer Manager object
+        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
+        #
+        # Add toolbars
+        #
+        for toolb in toolbars:
+            self.AddToolbar(toolb)
+        
+        #
+        # Add statusbar
+        #
+        
+        # items for choice
+        self.statusbarItems = [sb.SbCoordinates,
+                               sb.SbRegionExtent,
+                               sb.SbCompRegionExtent,
+                               sb.SbShowRegion,
+                               sb.SbAlignExtent,
+                               sb.SbResolution,
+                               sb.SbDisplayGeometry,
+                               sb.SbMapScale,
+                               sb.SbGoTo,
+                               sb.SbProjection]
+                            
+        self.statusbarItemsHiddenInNviz = (sb.SbAlignExtent,
+                                           sb.SbDisplayGeometry,
+                                           sb.SbShowRegion,
+                                           sb.SbResolution,
+                                           sb.SbMapScale)
+        
+        # create statusbar and its manager
+        statusbar = self.CreateStatusBar(number = 4, style = 0)
+        statusbar.SetStatusWidths([-5, -2, -1, -1])
+        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
+        
+        # fill statusbar manager
+        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
+        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
+        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
+        
+        self.statusbarManager.Update()
+
+        #
+        # Init map display (buffered DC & set default cursor)
+        #
+        self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
+                                          Map = self.Map, tree = self.tree, lmgr = self._layerManager)
+        # default is 2D display mode
+        self.MapWindow = self.MapWindow2D
+        self.MapWindow.SetCursor(self.cursors["default"])
+        # used by vector digitizer
+        self.MapWindowVDigit = None
+        # used by Nviz (3D display mode)
+        self.MapWindow3D = None 
+
+        #
+        # initialize region values
+        #
+        self._initMap(map = self.Map) 
+
+        #
+        # Bind various events
+        #
+        self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
+        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
+        self.Bind(EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
+        
+        #
+        # Update fancy gui style
+        #
+        self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
+                          Dockable(False).BestSize((-1,-1)).Name('2d').
+                          CloseButton(False).DestroyOnClose(True).
+                          Layer(0))
+        self._mgr.Update()
+
+        #
+        # Init print module and classes
+        #
+        self.printopt = PrintOptions(self, self.MapWindow)
+        
+        #
+        # 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 _addToolbarVDigit(self):
+        """!Add vector digitizer toolbar
+        """
+        from vdigit import haveVDigit
+        
+        if not haveVDigit:
+            from vdigit import errorMsg
+            msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
+                    "TCL/TK digitizer (v.digit) instead?\n\n"
+                    "Details: %s" % errorMsg)
+            
+            self.toolbars['map'].combo.SetValue(_("2D view"))
+            dlg = wx.MessageDialog(parent = self,
+                                   message = msg,
+                                   caption=_("Vector digitizer failed"),
+                                   style = wx.YES_NO | wx.CENTRE)
+            if dlg.ShowModal() == wx.ID_YES:
+                mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetName()
+                self._layerManager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
+                                                  switchPage = False)
+            dlg.Destroy()
+            
+            self.toolbars['map'].combo.SetValue(_("2D view"))
+            return
+        
+        if self._layerManager:
+            log = self._layerManager.goutput
+        else:
+            log = None
+        
+        if not self.MapWindowVDigit:
+            from mapdisp_vdigit import VDigitWindow
+            self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
+                                                Map = self.Map, tree = self.tree,
+                                                lmgr = self._layerManager)
+            self.MapWindowVDigit.Show()
+            self._mgr.AddPane(self.MapWindowVDigit, wx.aui.AuiPaneInfo().CentrePane().
+                          Dockable(False).BestSize((-1,-1)).Name('vdigit').
+                          CloseButton(False).DestroyOnClose(True).
+                          Layer(0))
+        
+        self.MapWindow = self.MapWindowVDigit
+        
+        if self._mgr.GetPane('2d').IsShown():
+            self._mgr.GetPane('2d').Hide()
+        elif self._mgr.GetPane('3d').IsShown():
+            self._mgr.GetPane('3d').Hide()
+        self._mgr.GetPane('vdigit').Show()
+        self.toolbars['vdigit'] = VDigitToolbar(parent = self, MapWindow = self.MapWindow,
+                                                layerTree = self.tree,
+                                                log = log)
+        self.MapWindowVDigit.SetToolbar(self.toolbars['vdigit'])
+        
+        self._mgr.AddPane(self.toolbars['vdigit'],
+                          wx.aui.AuiPaneInfo().
+                          Name("vdigittoolbar").Caption(_("Vector Digitizer Toolbar")).
+                          ToolbarPane().Top().Row(1).
+                          LeftDockable(False).RightDockable(False).
+                          BottomDockable(False).TopDockable(True).
+                          CloseButton(False).Layer(2).
+                          BestSize((self.toolbars['vdigit'].GetBestSize())))
+        # change mouse to draw digitized line
+        self.MapWindow.mouse['box'] = "point"
+        self.MapWindow.zoomtype     = 0
+        self.MapWindow.pen          = wx.Pen(colour = 'red',   width = 2, style = wx.SOLID)
+        self.MapWindow.polypen      = wx.Pen(colour = 'green', width = 2, style = wx.SOLID)
+
+    def AddNviz(self):
+        """!Add 3D view mode window
+        """
+        import nviz
+        
+        # check for GLCanvas and OpenGL
+        if not nviz.haveNviz:
+            self.toolbars['map'].combo.SetValue(_("2D view"))
+            GError(parent = self,
+                   message = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
+                               "was not found or loaded properly.\n"
+                               "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg))
+            return
+        
+        # disable 3D mode for other displays
+        for page in range(0, self._layerManager.gm_cb.GetPageCount()):
+            if self._layerManager.gm_cb.GetPage(page) != self._layerManager.curr_page:
+                if '3D' in self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.GetString(1):
+                    self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.Delete(1)
+        self.toolbars['map'].Enable2D(False)
+        # add rotate tool to map toolbar
+        self.toolbars['map'].InsertTool((('rotate', Icons['nviz']['rotate'],
+                                          self.OnRotate, wx.ITEM_CHECK, 7),)) # 7 is position
+        self.toolbars['map'].InsertTool((('flyThrough', Icons['nviz']['flyThrough'],
+                                          self.OnFlyThrough, wx.ITEM_CHECK, 8),)) 
+        self.toolbars['map'].ChangeToolsDesc(mode2d = False)
+        # update status bar
+        
+        self.statusbarManager.HideStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
+        self.statusbarManager.SetMode(0)
+        
+        # erase map window
+        self.MapWindow.EraseMap()
+        
+        self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."),
+                                               switchPage = False)
+        self.SetStatusText(_("Please wait, loading data..."), 0)
+        
+        # create GL window
+        if not self.MapWindow3D:
+            self.MapWindow3D = nviz.GLWindow(self, id = wx.ID_ANY,
+                                             Map = self.Map, tree = self.tree, lmgr = self._layerManager)
+            self.MapWindow = self.MapWindow3D
+            self.MapWindow.SetCursor(self.cursors["default"])
+            
+            # add Nviz notebookpage
+            self._layerManager.AddNvizTools()
+            
+            # switch from MapWindow to MapWindowGL
+            self._mgr.GetPane('2d').Hide()
+            self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
+                              Dockable(False).BestSize((-1,-1)).Name('3d').
+                              CloseButton(False).DestroyOnClose(True).
+                              Layer(0))
+            
+            self.MapWindow3D.OnPaint(None) # -> LoadData
+            self.MapWindow3D.Show()
+            self.MapWindow3D.ResetViewHistory()            
+            self.MapWindow3D.UpdateView(None)
+        else:
+            self.MapWindow = self.MapWindow3D
+            os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
+            self.MapWindow3D.GetDisplay().Init()
+            del os.environ['GRASS_REGION']
+            
+            # switch from MapWindow to MapWindowGL
+            self._mgr.GetPane('2d').Hide()
+            self._mgr.GetPane('3d').Show()
+            
+            # add Nviz notebookpage
+            self._layerManager.AddNvizTools()
+            self.MapWindow3D.ResetViewHistory()
+            for page in ('view', 'light', 'fringe', 'constant', 'cplane', 'animation'):
+                self._layerManager.nviz.UpdatePage(page)
+                
+        self.MapWindow3D.overlays = self.MapWindow2D.overlays
+        self.MapWindow3D.textdict = self.MapWindow2D.textdict
+        # update overlays needs to be called after because getClientSize
+        # is called during update and it must give reasonable values
+        wx.CallAfter(self.MapWindow3D.UpdateOverlays)
+        
+        self.SetStatusText("", 0)
+        self._mgr.Update()
+    
+    def RemoveNviz(self):
+        """!Restore 2D view"""
+        self.toolbars['map'].RemoveTool(self.toolbars['map'].rotate)
+        self.toolbars['map'].RemoveTool(self.toolbars['map'].flyThrough)
+        # update status bar
+        self.statusbarManager.ShowStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
+        self.statusbarManager.SetMode(UserSettings.Get(group = 'display',
+                                                       key = 'statusbarMode',
+                                                       subkey = 'selection'))
+        self.SetStatusText(_("Please wait, unloading data..."), 0)
+        self._layerManager.goutput.WriteCmdLog(_("Switching back to 2D view mode..."),
+                                               switchPage = False)
+        self.MapWindow3D.OnClose(event = None)
+        # switch from MapWindowGL to MapWindow
+        self._mgr.GetPane('2d').Show()
+        self._mgr.GetPane('3d').Hide()
+
+        self.MapWindow = self.MapWindow2D
+        # remove nviz notebook page
+        self._layerManager.RemoveNvizTools()
+        
+        self.MapWindow2D.overlays = self.MapWindow3D.overlays
+        self.MapWindow2D.textdict = self.MapWindow3D.textdict
+        self.MapWindow.UpdateMap()
+        self._mgr.Update()
+        
+    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
+        """
+        # default toolbar
+        if name == "map":
+            self.toolbars['map'] = MapToolbar(self, self.Map)
+            
+            self._mgr.AddPane(self.toolbars['map'],
+                              wx.aui.AuiPaneInfo().
+                              Name("maptoolbar").Caption(_("Map Toolbar")).
+                              ToolbarPane().Top().Name('mapToolbar').
+                              LeftDockable(False).RightDockable(False).
+                              BottomDockable(False).TopDockable(True).
+                              CloseButton(False).Layer(2).
+                              BestSize((self.toolbars['map'].GetBestSize())))
+            
+        # vector digitizer
+        elif name == "vdigit":
+            self._addToolbarVDigit()
+        
+        self._mgr.Update()
+        
+    def RemoveToolbar (self, name):
+        """!Removes defined toolbar from the window
+
+        @todo Only hide, activate by calling AddToolbar()
+        """
+        # cannot hide main toolbar
+        if name == "map":
+            return
+        
+        self._mgr.DetachPane(self.toolbars[name])
+        self.toolbars[name].Destroy()
+        self.toolbars.pop(name)
+        
+        if name == 'vdigit':
+            self._mgr.GetPane('vdigit').Hide()
+            self._mgr.GetPane('2d').Show()
+            self.MapWindow = self.MapWindow2D
+            
+        self.toolbars['map'].combo.SetValue(_("2D view"))
+        self.toolbars['map'].Enable2D(True)
+        
+        self._mgr.Update()
+    
+    def IsPaneShown(self, name):
+        """!Check if pane (toolbar, mapWindow ...) of given name is currently shown"""
+        if self._mgr.GetPane(name).IsOk():
+            return self._mgr.GetPane(name).IsShown()
+        return False
+        
+    def OnUpdateProgress(self, event):
+        """!Update progress bar info
+        """
+        self.GetProgressBar().SetValue(event.value)
+        
+        event.Skip()
+        
+    def OnFocus(self, event):
+        """!Change choicebook page to match display.
+        """
+        # change bookcontrol page to page associated with display
+        if self.page:
+            pgnum = self.layerbook.GetPageIndex(self.page)
+            if pgnum > -1:
+                self.layerbook.SetSelection(pgnum)
+                self._layerManager.curr_page = self.layerbook.GetCurrentPage()
+        
+        event.Skip()
+        
+    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)
+        
+        # delete tmp lines
+        if self.MapWindow.mouse["use"] in ("measure",
+                                           "profile"):
+            self.MapWindow.polycoords = []
+            self.MapWindow.ClearLines()
+        
+        # deselect features in vdigit
+        if self.GetToolbar('vdigit'):
+            self.MapWindow.digit.GetDisplay().SetSelected([])
+            self.MapWindow.UpdateMap(render = True, renderVector = True)
+        else:
+            self.MapWindow.UpdateMap(render = True)
+        
+        # update statusbar
+        self.StatusbarUpdate()
+
+    def OnPointer(self, event):
+        """!Pointer button clicked
+        """
+        if self.GetMapToolbar():
+            if event:
+                self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "pointer"
+        self.MapWindow.mouse['box'] = "point"
+
+        # change the cursor
+        if self.GetToolbar('vdigit'):
+            # digitization tool activated
+            self.MapWindow.SetCursor(self.cursors["cross"])
+
+            # reset mouse['box'] if needed
+            if self.toolbars['vdigit'].GetAction() in ['addLine']:
+                if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
+                    self.MapWindow.mouse['box'] = 'point'
+                else: # line, boundary
+                    self.MapWindow.mouse['box'] = 'line'
+            elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
+                                                         'editLine', 'displayCats', 'queryMap',
+                                                         'copyCats']:
+                self.MapWindow.mouse['box'] = 'point'
+            else: # moveLine, deleteLine
+                self.MapWindow.mouse['box'] = 'box'
+        
+        else:
+            self.MapWindow.SetCursor(self.cursors["default"])
+
+    def OnRotate(self, event):
+        """!Rotate 3D view
+        """
+        if self.GetMapToolbar():
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "rotate"
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["hand"])
+
+    def OnFlyThrough(self, event):
+        """!Fly-through mode
+        """
+        if self.GetMapToolbar():
+            self.toolbars['map'].OnTool(event)
+            self.toolbars['map'].action['desc'] = ''
+        
+        self.MapWindow.mouse['use'] = "fly"
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["hand"])
+        self.MapWindow.SetFocus()
+        
+    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 SaveToFile(self, event):
+        """!Save map to image
+        """
+        if self.IsPaneShown('3d'):
+            filetype = "PPM file (*.ppm)|*.ppm|TIF file (*.tif)|*.tif"
+            ltype = [{ 'ext' : 'ppm', 'type' : 'ppm' },
+                     { 'ext' : 'tif', 'type' : 'tif' }]
+        else:
+            img = self.MapWindow.img
+            if not img:
+                GMessage(parent = self,
+                         message = _("Nothing to render (empty map). Operation canceled."))
+                return
+            filetype, ltype = GetImageHandlers(img)
+        
+        # get size
+        dlg = ImageSizeDialog(self)
+        dlg.CentreOnParent()
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        width, height = dlg.GetValues()
+        dlg.Destroy()
+        
+        # get filename
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to save the image "
+                                        "(no need to add extension)"),
+                            wildcard = filetype,
+                            style = wx.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 OnCloseWindow(self, event):
+        """!Window closed.
+        Also close associated layer tree page
+        """
+        pgnum = None
+        self.Map.Clean()
+        
+        # close edited map and 3D tools properly
+        if self.GetToolbar('vdigit'):
+            maplayer = self.toolbars['vdigit'].GetLayer()
+            if maplayer:
+                self.toolbars['vdigit'].OnExit()
+        if self.IsPaneShown('3d'):
+            self.RemoveNviz()
+        
+        if not self._layerManager:
+            self.Destroy()
+        elif self.page:
+            pgnum = self.layerbook.GetPageIndex(self.page)
+            if pgnum > -1:
+                self.layerbook.DeletePage(pgnum)
+    
+    
+    def QueryMap(self, x, y):
+        """!Query raster or vector map layers by r/v.what
+        
+        @param x,y coordinates
+        """
+        # set query snap distance for v.what at map unit equivalent of 10 pixels
+        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
+        east, north = self.MapWindow.Pixel2Cell((x, y))
+        
+        if not self.IsStandalone():
+            num = 0
+            for layer in self.tree.GetSelections():
+                ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
+                if ltype in ('raster', 'rgb', 'his',
+                             'vector', 'thememap', 'themechart'):
+                    num += 1
+            
+            if num < 1:
+                GMessage(parent = self,
+                         message = _('No raster or vector map layer selected for querying.'))
+                return
+        
+        rast = list()
+        vect = list()
+        rcmd = ['r.what', '--v']
+        vcmd = ['v.what', '--v']
+        
+        if self.IsStandalone():
+            pass
+        else:
+            for layer in self.tree.GetSelections():
+                ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
+                dcmd = self.tree.GetPyData(layer)[0]['cmd']
+                name, found = GetLayerNameFromCmd(dcmd)
+                
+                if not found:
+                    continue
+                if ltype == 'raster':
+                    rast.append(name)
+                elif ltype in ('rgb', 'his'):
+                    for iname in name.split('\n'):
+                        rast.append(iname)
+                elif ltype in ('vector', 'thememap', 'themechart'):
+                    vect.append(name)
+        # rasters are not queried this way in 3D, we don't want them now
+        if self.IsPaneShown('3d'):
+            rast = list()
+        # use display region settings instead of computation region settings
+        self.tmpreg = os.getenv("GRASS_REGION")
+        os.environ["GRASS_REGION"] = self.Map.SetRegion(windres = False)
+        
+        # build query commands for any selected rasters and vectors
+        if rast:
+            rcmd.append('-f')
+            rcmd.append('-n')
+            rcmd.append('input=%s' % ','.join(rast))
+            rcmd.append('east_north=%f,%f' % (float(east), float(north)))
+        
+        if vect:
+            # check for vector maps open to be edited
+            digitToolbar = self.toolbars['vdigit']
+            if digitToolbar:
+                lmap = digitToolbar.GetLayer().GetName()
+                for name in vect:
+                    if lmap == name:
+                        self._layerManager.goutput.WriteWarning(_("Vector map <%s> "
+                                                                  "opened for editing - skipped.") % map)
+                        vect.remove(name)
+            
+            if len(vect) < 1:
+                self._layerManager.goutput.WriteCmdLog(_("Nothing to query."))
+                return
+            
+            vcmd.append('-a')
+            vcmd.append('map=%s' % ','.join(vect))
+            vcmd.append('layer=%s' % ','.join(['-1'] * len(vect)))
+            vcmd.append('east_north=%f,%f' % (float(east), float(north)))
+            vcmd.append('distance=%f' % float(qdist))
+        
+        Debug.msg(1, "QueryMap(): raster=%s vector=%s" % (','.join(rast),
+                                                          ','.join(vect)))
+        # parse query command(s)
+        if not self.IsStandalone():
+            if rast:
+                self._layerManager.goutput.RunCmd(rcmd,
+                                                  compReg = False,
+                                                  onDone  =  self._QueryMapDone)
+            if vect:
+                self._layerManager.goutput.RunCmd(vcmd,
+                                                  onDone = self._QueryMapDone)
+        else:
+            if rast:
+                RunCommand(rcmd)
+            if vect:
+                RunCommand(vcmd)
+        
+    def _QueryMapDone(self, cmd, returncode):
+        """!Restore settings after querying (restore GRASS_REGION)
+        
+        @param returncode command return code
+        """
+        if hasattr(self, "tmpreg"):
+            if self.tmpreg:
+                os.environ["GRASS_REGION"] = self.tmpreg
+            elif 'GRASS_REGION' in os.environ:
+                del os.environ["GRASS_REGION"]
+        elif 'GRASS_REGION' in os.environ:
+            del os.environ["GRASS_REGION"]
+        
+        if hasattr(self, "tmpreg"):
+            del self.tmpreg
+        
+    def QueryVector(self, x, y):
+        """!Query vector map layer features
+
+        Attribute data of selected vector object are displayed in GUI dialog.
+        Data can be modified (On Submit)
+        """
+        if not self.tree.layer_selected or \
+                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
+            GMessage(parent = self,
+                     message = _("No map layer selected for querying."))
+            return
+        
+        posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
+                                         y + self.MapWindow.dialogOffset))
+        
+        qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) /
+                        self.Map.width)
+        
+        east, north = self.MapWindow.Pixel2Cell((x, y))
+        
+        mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
+        
+        if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
+                grass.gisenv()['MAPSET']:
+            mode = 'display'
+        else:
+            mode = 'update'
+        
+        if self.dialogs['attributes'] is None:
+            dlg = DisplayAttributesDialog(parent = self.MapWindow,
+                                                      map = mapName,
+                                                      query = ((east, north), qdist),
+                                                      pos = posWindow,
+                                                      action = mode)
+            self.dialogs['attributes'] = dlg
+        
+        else:
+            # selection changed?
+            if not self.dialogs['attributes'].mapDBInfo or \
+                    self.dialogs['attributes'].mapDBInfo.map != mapName:
+                self.dialogs['attributes'].UpdateDialog(map = mapName, query = ((east, north), qdist),
+                                                        action = mode)
+            else:
+                self.dialogs['attributes'].UpdateDialog(query = ((east, north), qdist),
+                                                        action = mode)
+        if not self.dialogs['attributes'].IsFound():
+            self._layerManager.goutput.WriteLog(_('Nothing found.'))
+        
+        cats = self.dialogs['attributes'].GetCats()
+        
+        qlayer = None
+        if not self.IsPaneShown('3d'):
+            try:
+                qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)[0]
+            except IndexError:
+                pass
+        
+        if self.dialogs['attributes'].mapDBInfo and cats:
+            if not self.IsPaneShown('3d'):
+                # highlight feature & re-draw map
+                if qlayer:
+                    qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
+                                                            useId = False,
+                                                            addLayer = False))
+                else:
+                    qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId = False)
+                
+                # set opacity based on queried layer
+                opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float = True)
+                qlayer.SetOpacity(opacity)
+                
+                self.MapWindow.UpdateMap(render = False, renderVector = False)
+            if not self.dialogs['attributes'].IsShown():
+                self.dialogs['attributes'].Show()
+        else:
+            if qlayer:
+                self.Map.DeleteLayer(qlayer)
+                self.MapWindow.UpdateMap(render = False, renderVector = False)
+            if self.dialogs['attributes'].IsShown():
+                self.dialogs['attributes'].Hide()
+        
+    def OnQuery(self, event):
+        """!Query tools menu"""
+        if self.GetMapToolbar():
+            self.toolbars['map'].OnTool(event)
+            action = self.toolbars['map'].GetAction()
+            
+        self.toolbars['map'].action['desc'] = 'queryMap'
+        self.MapWindow.mouse['use'] = "query"
+        
+        if not self.IsStandalone():
+            # switch to output console to show query results
+            self._layerManager.notebook.SetSelectionByName('output')
+        
+        self.MapWindow.mouse['box'] = "point"
+        self.MapWindow.zoomtype = 0
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["cross"])
+        
+    def AddTmpVectorMapLayer(self, name, cats, useId = False, addLayer = True):
+        """!Add temporal vector map layer to map composition
+
+        @param name name of map layer
+        @param useId use feature id instead of category 
+        """
+        # color settings from ATM
+        color = UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'color')
+        colorStr = str(color[0]) + ":" + \
+            str(color[1]) + ":" + \
+            str(color[2])
+
+        # icon used in vector display and its size
+        icon = ''
+        size = 0
+        vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
+        for p in vparam:
+            if '=' in p:
+                parg,pval = p.split('=')
+                if parg == 'icon': icon = pval
+                elif parg == 'size': size = int(pval)
+
+        pattern = ["d.vect",
+                   "map=%s" % name,
+                   "color=%s" % colorStr,
+                   "fcolor=%s" % colorStr,
+                   "width=%d"  % UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'width')]
+        if icon != '':
+            pattern.append('icon=%s' % icon)
+        if size > 0:
+            pattern.append('size=%i' % size)
+        
+        if useId:
+            cmd = pattern
+            cmd.append('-i')
+            cmd.append('cats=%s' % str(cats))
+        else:
+            cmd = []
+            for layer in cats.keys():
+                cmd.append(copy.copy(pattern))
+                lcats = cats[layer]
+                cmd[-1].append("layer=%d" % layer)
+                cmd[-1].append("cats=%s" % ListOfCatsToRange(lcats))
+        
+        if addLayer:
+            if useId:
+                return self.Map.AddLayer(type = 'vector', name = globalvar.QUERYLAYER, command = cmd,
+                                         l_active = True, l_hidden = True, l_opacity = 1.0)
+            else:
+                return self.Map.AddLayer(type = 'command', name = globalvar.QUERYLAYER, command = cmd,
+                                         l_active = True, l_hidden = True, l_opacity = 1.0)
+        else:
+            return cmd
+
+    def OnAnalyze(self, event):
+        """!Analysis tools menu
+        """
+        point = wx.GetMousePosition()
+        toolsmenu = wx.Menu()
+        icons = Icons['displayWindow']
+        
+        # Add items to the menu
+        measure = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["measure"].GetLabel())
+        measure.SetBitmap(icons["measure"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(measure)
+        self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
+        
+        profile = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["profile"].GetLabel())
+        profile.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(profile)
+        self.Bind(wx.EVT_MENU, self.OnProfile, profile)
+
+        scatterplot = wx.MenuItem(toolsmenu, wx.ID_ANY, _("Create bivariate scatterplot of raster maps"))
+        scatterplot.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(scatterplot)
+        self.Bind(wx.EVT_MENU, self.OnScatterplot, scatterplot)
+
+        histogram2 = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
+        histogram2.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(histogram2)
+        self.Bind(wx.EVT_MENU, self.OnHistogramPyPlot, histogram2)
+
+        histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, _("Create histogram with d.histogram"))
+        histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
+        toolsmenu.AppendItem(histogram)
+        self.Bind(wx.EVT_MENU, self.OnHistogram, histogram)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(toolsmenu)
+        toolsmenu.Destroy()
+
+    def OnMeasure(self, event):
+        """!Init measurement routine that calculates map distance
+        along transect drawn on map display
+        """
+        self.totaldist = 0.0 # total measured distance
+        
+        # switch Layer Manager to output console to show measure results
+        self._layerManager.notebook.SetSelectionByName('output')
+        
+        # change mouse to draw line for measurement
+        self.MapWindow.mouse['use'] = "measure"
+        self.MapWindow.mouse['box'] = "line"
+        self.MapWindow.zoomtype = 0
+        self.MapWindow.pen     = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
+        self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
+        
+        # change the cursor
+        self.MapWindow.SetCursor(self.cursors["pencil"])
+        
+        # initiating output
+        style = self._layerManager.goutput.cmd_output.StyleWarning
+        self._layerManager.goutput.WriteLog(_('Click and drag with left mouse button '
+                                              'to measure.%s'
+                                              'Double click with left button to clear.') % \
+                                                (os.linesep), style)
+        if self.Map.projinfo['proj'] != 'xy':
+            units = self.Map.projinfo['units']
+            self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
+                                                   + units + '):')
+        else:
+            self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
+        
+        if self.Map.projinfo['proj'] == 'll':
+            try:
+                import grass.lib.gis as gislib
+                global haveCtypes
+                haveCtypes = True
+
+                gislib.G_begin_distance_calculations()
+            except ImportError, e:
+                self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
+                                                          'supported by this tool.\n'
+                                                          'Reason: %s' % e))
+        
+    def MeasureDist(self, beginpt, endpt):
+        """!Calculate map distance from screen distance
+        and print to output window
+        """
+        self._layerManager.notebook.SetSelectionByName('output')
+        
+        dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
+        
+        dist = round(dist, 3)
+        d, dunits = self.FormatDist(dist)
+        
+        self.totaldist += dist
+        td, tdunits = self.FormatDist(self.totaldist)
+        
+        strdist = str(d)
+        strtotdist = str(td)
+        
+        if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
+            angle = int(math.degrees(math.atan2(north,east)) + 0.5)
+            angle = 180 - angle
+            if angle < 0:
+                angle = 360 + angle
+            
+            mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
+                % (_('segment'), strdist, dunits,
+                   _('total distance'), strtotdist, tdunits,
+                   _('bearing'), angle, _('deg'),
+                   '-' * 60)
+        else:
+            mstring = '%s = %s %s\n%s = %s %s\n%s' \
+                % (_('segment'), strdist, dunits,
+                   _('total distance'), strtotdist, tdunits,
+                   '-' * 60)
+        
+        self._layerManager.goutput.WriteLog(mstring)
+        
+        return dist
+
+    def OnProfile(self, event):
+        """!Init profile canvas and tools
+        """
+        raster = []
+        if self.tree.layer_selected and \
+                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
+            raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
+
+        self.profile = ProfileFrame(self,
+                                            id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
+                                            style = wx.DEFAULT_FRAME_STYLE, 
+                                            rasterList = raster)
+        self.profile.Show()
+        # Open raster select dialog to make sure that a raster (and the desired raster)
+        # is selected to be profiled
+        self.profile.OnSelectRaster(None)
+
+    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 and \
+                not haveCtypes:
+            if dist < 1:
+                outunits = 'min'
+                divisor = (1/60.0)
+            else:
+                outunits = 'deg'
+        else:
+            outunits = 'meters'
+        
+        # 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 OnHistogramPyPlot(self, event):
+        """!Init PyPlot histogram display canvas and tools
+        """
+        raster = []
+
+        for layer in self.tree.GetSelections():
+            if self.tree.GetPyData(layer)[0]['maplayer'].GetType() != 'raster':
+                continue
+            raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
+
+        self.histogramPyPlot = HistFramePyPlot(self, id = wx.ID_ANY, 
+                                                pos = wx.DefaultPosition, size = (700,300),
+                                                style = wx.DEFAULT_FRAME_STYLE, 
+                                                rasterList = raster)
+        self.histogramPyPlot.Show()
+        # Open raster select dialog to make sure that a raster (and the desired raster)
+        # is selected to be histogrammed
+        self.histogramPyPlot.OnSelectRaster(None)
+        
+    def OnScatterplot(self, event):
+        """!Init PyPlot scatterplot display canvas and tools
+        """
+        raster = []
+
+        for layer in self.tree.GetSelections():
+            if self.tree.GetPyData(layer)[0]['maplayer'].GetType() != 'raster':
+                continue
+            raster.append(self.tree.GetPyData(layer)[0]['maplayer'].GetName())
+
+        self.scatterplot = ScatterFrame(self, id = wx.ID_ANY, 
+                                                pos = wx.DefaultPosition, size = (700,300),
+                                                style = wx.DEFAULT_FRAME_STYLE, 
+                                                rasterList = raster)
+        self.scatterplot.Show()
+        # Open raster select dialog to make sure that at least 2 rasters (and the desired rasters)
+        # are selected to be plotted
+        self.scatterplot.OnSelectRaster(None)
+
+    def OnHistogram(self, event):
+        """!Init histogram display canvas and tools
+        """
+        self.histogram = HistFrame(parent = self, id = wx.ID_ANY, size = globalvar.HIST_WINDOW_SIZE,
+                                   style = wx.DEFAULT_FRAME_STYLE)
+        
+        # show new display
+        self.histogram.Show()
+        self.histogram.Refresh()
+        self.histogram.Update()
+       
+    def OnDecoration(self, event):
+        """!Decorations overlay menu
+        """
+        point = wx.GetMousePosition()
+        decmenu = wx.Menu()
+        icons = Icons['displayWindow']
+        
+        # Add items to the menu
+        AddScale = wx.MenuItem(decmenu, wx.ID_ANY, icons["addBarscale"].GetLabel())
+        AddScale.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddScale)
+        self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
+        # temporary
+        if self.IsPaneShown('3d'):
+            AddScale.Enable(False)
+            AddArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("Add north arrow"))
+            AddArrow.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
+            decmenu.AppendItem(AddArrow)
+            self.Bind(wx.EVT_MENU, self.OnAddArrow, AddArrow)
+        
+        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, icons["addLegend"].GetLabel())
+        AddLegend.SetBitmap(icons["addLegend"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddLegend)
+        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
+        
+        AddText = wx.MenuItem(decmenu, wx.ID_ANY, icons["addText"].GetLabel())
+        AddText.SetBitmap(icons["addText"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddText)
+        self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
+        
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(decmenu)
+        decmenu.Destroy()
+        
+    def OnAddBarscale(self, event):
+        """!Handler for scale/arrow map decoration menu selection.
+        """
+        if self.dialogs['barscale']:
+            return
+        
+        id = 0 # unique index for overlay layer
+
+        # If location is latlon, only display north arrow (scale won't work)
+        #        proj = self.Map.projinfo['proj']
+        #        if proj == 'll':
+        #            barcmd = 'd.barscale -n'
+        #        else:
+        #            barcmd = 'd.barscale'
+
+        # decoration overlay control dialog
+        self.dialogs['barscale'] = \
+            DecorationDialog(parent = self, title = _('Scale and North arrow'),
+                             size = (350, 200),
+                             style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
+                             cmd = ['d.barscale', 'at=0,95'],
+                             ovlId = id,
+                             name = 'barscale',
+                             checktxt = _("Show/hide scale and North arrow"),
+                             ctrltxt = _("scale object"))
+
+        self.dialogs['barscale'].CentreOnParent()
+        ### dialog cannot be show as modal - in the result d.barscale is not selectable
+        ### self.dialogs['barscale'].ShowModal()
+        self.dialogs['barscale'].Show()
+        self.MapWindow.mouse['use'] = 'pointer'
+
+    def OnAddLegend(self, event):
+        """!Handler for legend map decoration menu selection.
+        """
+        if self.dialogs['legend']:
+            return
+        
+        id = 1 # index for overlay layer in render
+        
+        cmd = ['d.legend', 'at=5,50,2,5']
+        
+        if self.tree and self.tree.layer_selected and \
+                self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
+            cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
+        
+        # Decoration overlay control dialog
+        self.dialogs['legend'] = \
+            DecorationDialog(parent = self, title = ('Legend'),
+                             size = (350, 200),
+                             style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
+                             cmd = cmd,
+                             ovlId = id,
+                             name = 'legend',
+                             checktxt = _("Show/hide legend"),
+                             ctrltxt = _("legend object")) 
+            
+        self.dialogs['legend'].CentreOnParent() 
+        ### dialog cannot be show as modal - in the result d.legend is not selectable
+        ### self.dialogs['legend'].ShowModal()
+        self.dialogs['legend'].Show()
+        self.MapWindow.mouse['use'] = 'pointer'
+        
+    def OnAddText(self, event):
+        """!Handler for text decoration menu selection.
+        """
+        if self.MapWindow.dragid > -1:
+            id = self.MapWindow.dragid
+            self.MapWindow.dragid = -1
+        else:
+            # index for overlay layer in render
+            if len(self.MapWindow.textdict.keys()) > 0:
+                id = max(self.MapWindow.textdict.keys()) + 1
+            else:
+                id = 101
+        
+        self.dialogs['text'] = TextLayerDialog(parent = self, ovlId = id, 
+                                               title = _('Add text layer'),
+                                               size = (400, 200))
+        self.dialogs['text'].CenterOnParent()
+
+        # If OK button pressed in decoration control dialog
+        if self.dialogs['text'].ShowModal() == wx.ID_OK:
+            text = self.dialogs['text'].GetValues()['text']
+            active = self.dialogs['text'].GetValues()['active']
+        
+            # delete object if it has no text or is not active
+            if text == '' or active == False:
+                try:
+                    self.MapWindow2D.pdc.ClearId(id)
+                    self.MapWindow2D.pdc.RemoveId(id)
+                    del self.MapWindow.textdict[id]
+                    if self.IsPaneShown('3d'):
+                        self.MapWindow3D.UpdateOverlays()
+                        self.MapWindow.UpdateMap()
+                    else:
+                        self.MapWindow2D.UpdateMap(render = False, renderVector = False)
+                except:
+                    pass
+                return
+
+            
+            self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
+            
+            if self.IsPaneShown('3d'):
+                self.MapWindow3D.UpdateOverlays()
+                self.MapWindow3D.UpdateMap()
+            else:
+                self.MapWindow2D.pdc.ClearId(id)
+                self.MapWindow2D.pdc.SetId(id)
+                self.MapWindow2D.UpdateMap(render = False, renderVector = False)
+            
+        self.MapWindow.mouse['use'] = 'pointer'
+    
+    def OnAddArrow(self, event):
+        """!Handler for north arrow menu selection.
+            Opens Appearance page of nviz notebook.
+        """
+        
+        self._layerManager.nviz.SetPage('decoration')
+        self.MapWindow3D.SetDrawArrow((70, 70))
+        
+    def GetOptData(self, dcmd, type, params, propwin):
+        """!Callback method for decoration overlay command generated by
+        dialog created in menuform.py
+        """
+        # Reset comand and rendering options in render.Map. Always render decoration.
+        # Showing/hiding handled by PseudoDC
+        self.Map.ChangeOverlay(ovltype = type, type = 'overlay', name = '', command = dcmd,
+                               l_active = True, l_render = False)
+        self.params[type] = params
+        self.propwin[type] = propwin
+
+    def OnZoomToMap(self, event):
+        """!Set display extents to match selected raster (including
+        NULLs) or vector map.
+        """
+        layers = None
+        if self.IsStandalone():
+            layers = self.MapWindow.GetMap().GetListOfLayers(l_active = False)
+        
+        self.MapWindow.ZoomToMap(layers = layers)
+
+    def OnZoomToRaster(self, event):
+        """!Set display extents to match selected raster map (ignore NULLs)
+        """
+        self.MapWindow.ZoomToMap(ignoreNulls = True)
+        
+    def OnZoomToSaved(self, event):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        self.MapWindow.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'))
+        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 extent'))
+        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, alignExtent = True):
+        """!Set properies of map display window"""
+        self.SetProperty('render', render)
+        self.statusbarManager.SetMode(mode)
+        self.StatusbarUpdate()
+        self.SetProperty('region', showCompExtent)
+        self.SetProperty('alignExtent', alignExtent)
+        self.SetProperty('resolution', constrainRes)
+        self.SetProperty('projection', projection)
+        
+    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
+    
+    def GetMapToolbar(self):
+        """!Returns toolbar with zooming tools"""
+        return self.toolbars['map']
+    
+class MapApp(wx.App):
+    def OnInit(self):
+        wx.InitAllImageHandlers()
+        if __name__ == "__main__":
+            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
+            Map = Map(cmdfile = monFile['cmd'], mapfile = monFile['map'],
+                      envfile = monFile['env'], monitor = monName)
+        else:
+            Map = None
+        
+        self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
+                               size = monSize)
+        # self.SetTopWindow(Map)
+        self.mapFrm.Show()
+        
+        if __name__ == "__main__":
+            self.timer = wx.PyTimer(self.watcher)
+            #check each 0.5s
+            global mtime
+            mtime = 500
+            self.timer.Start(mtime)
+            
+        return True
+    
+    def OnExit(self):
+        if __name__ == "__main__":
+            # stop the timer
+            # self.timer.Stop()
+            # terminate thread
+            for f in monFile.itervalues():
+                grass.try_remove(f)
+            
+    def watcher(self):
+        """!Redraw, if new layer appears (check's timestamp of
+        cmdfile)
+        """
+        # todo: events
+        if os.path.getmtime(monFile['cmd']) > self.cmdTimeStamp:
+            self.timer.Stop()
+            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
+            self.mapFrm.OnDraw(None)
+            self.mapFrm.GetMap().GetLayersFromCmdFile()
+            self.timer.Start(mtime)
+        
+if __name__ == "__main__":
+    # set command variable
+    if len(sys.argv) < 5:
+        print __doc__
+        sys.exit(1)
+    
+    monName = sys.argv[1]
+    monFile = { 'map' : sys.argv[2],
+                'cmd' : sys.argv[3],
+                'env' : sys.argv[4],
+                }
+    if len(sys.argv) >= 6:
+        try:
+            monSize[0] = int(sys.argv[5])
+        except ValueError:
+            pass
+    
+    if len(sys.argv) == 7:
+        try:
+            monSize[1] = int(sys.argv[6])
+        except ValueError:
+            pass
+    
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    grass.verbose(_("Starting map display <%s>...") % (monName))
+
+    RunCommand('g.gisenv',
+               set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
+    
+    gm_map = MapApp(0)
+    # set title
+    gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
+                             monName + 
+                             " - Location: " + grass.gisenv()["LOCATION_NAME"]))
+    
+    gm_map.MainLoop()
+    
+    grass.verbose(_("Stopping map display <%s>...") % (monName))
+
+    # clean up GRASS env variables
+    env = grass.gisenv()
+    env_name = 'MONITOR_%s' % monName
+    for key in env.keys():
+        if key.find(env_name) == 0:
+            RunCommand('g.gisenv',
+                       set = '%s=' % key)
+        if key == 'MONITOR' and env[key] == monName:
+            RunCommand('g.gisenv',
+                       set = '%s=' % key)
+    
+    sys.exit(0)

Copied: grass/trunk/gui/wxpython/mapdisp/gprint.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/disp_print.py)
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/gprint.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapdisp/gprint.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,156 @@
+"""!
+ at package mapdisp.gprint
+
+ at brief Print context and utility functions for printing
+contents of map display window.
+
+Classes:
+ - MapPrint
+ - PrintOptions
+
+(C) 2007 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 (Arizona State University)
+"""
+
+import  wx
+
+from core.gcmd import GMessage
+
+class MapPrint(wx.Printout):
+    def __init__(self, canvas):
+        wx.Printout.__init__(self)
+        self.canvas = canvas
+
+    def OnBeginDocument(self, start, end):
+        return super(MapPrint, self).OnBeginDocument(start, end)
+
+    def OnEndDocument(self):
+        super(MapPrint, self).OnEndDocument()
+
+    def OnBeginPrinting(self):
+        super(MapPrint, self).OnBeginPrinting()
+
+    def OnEndPrinting(self):
+        super(MapPrint, self).OnEndPrinting()
+
+    def OnPreparePrinting(self):
+        super(MapPrint, self).OnPreparePrinting()
+
+    def HasPage(self, page):
+        if page <= 2:
+            return True
+        else:
+            return False
+
+    def GetPageInfo(self):
+        return (1, 2, 1, 2)
+
+    def OnPrintPage(self, page):
+        dc = self.GetDC()
+
+        #-------------------------------------------
+        # One possible method of setting scaling factors...
+        maxX, maxY = self.canvas.GetSize()
+
+        # Let's have at least 50 device units margin
+        marginX = 10
+        marginY = 10
+
+        # Add the margin to the graphic size
+        maxX = maxX + (2 * marginX)
+        maxY = maxY + (2 * marginY)
+
+        # Get the size of the DC in pixels
+        (w, h) = dc.GetSizeTuple()
+
+        # Calculate a suitable scaling factor
+        scaleX = float(w) / maxX
+        scaleY = float(h) / maxY
+
+        # Use x or y scaling factor, whichever fits on the DC
+        actualScale = min(scaleX, scaleY)
+
+        # Calculate the position on the DC for centering the graphic
+        posX = (w - (self.canvas.GetSize()[0] * actualScale)) / 2.0
+        posY = (h - (self.canvas.GetSize()[1] * actualScale)) / 2.0
+
+        # Set the scale and origin
+        dc.SetUserScale(actualScale, actualScale)
+        dc.SetDeviceOrigin(int(posX), int(posY))
+
+        #-------------------------------------------
+
+        self.canvas.pdc.DrawToDC(dc)
+
+        # prints a page number on the page
+        # dc.DrawText("Page: %d" % page, marginX/2, maxY-marginY)
+
+        return True
+
+class PrintOptions(wx.Object):
+    def __init__(self, parent, mapwin):
+        self.mapframe = parent
+        self.mapwin = mapwin
+	#self.frame = frame
+
+	self.printData = None
+
+	#self.canvas = ScrolledWindow.MyCanvas(self)
+
+    def setup(self):
+	if self.printData:
+	    return
+        self.printData = wx.PrintData()
+        self.printData.SetPaperId(wx.PAPER_LETTER)
+        self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
+
+    def OnPageSetup(self, event):
+	self.setup()
+        psdd = wx.PageSetupDialogData(self.printData)
+        psdd.CalculatePaperSizeFromId()
+        dlg = wx.PageSetupDialog(self.mapwin, psdd)
+        dlg.ShowModal()
+
+        # this makes a copy of the wx.PrintData instead of just saving
+        # a reference to the one inside the PrintDialogData that will
+        # be destroyed when the dialog is destroyed
+        self.printData = wx.PrintData( dlg.GetPageSetupData().GetPrintData() )
+
+        dlg.Destroy()
+
+    def OnPrintPreview(self, event):
+	self.setup()
+        data = wx.PrintDialogData(self.printData)
+        printout = MapPrint(self.mapwin)
+        printout2 = MapPrint(self.mapwin)
+        self.preview = wx.PrintPreview(printout, printout2, data)
+
+        if not self.preview.Ok():
+            wx.MessageBox("There was a problem printing this display\n", wx.OK)
+            return
+
+        pfrm = wx.PreviewFrame(self.preview, self.mapframe, "Print preview")
+
+        pfrm.Initialize()
+        pfrm.SetPosition(self.mapframe.GetPosition())
+        pfrm.SetSize(self.mapframe.GetClientSize())
+        pfrm.Show(True)
+
+    def OnDoPrint(self, event):
+	self.setup()
+        pdd = wx.PrintDialogData(self.printData)
+        # set number of pages/copies
+        pdd.SetToPage(1)
+        printer = wx.Printer(pdd)
+        printout = MapPrint(self.mapwin)
+
+        if not printer.Print(self.mapframe, printout, True):
+            GMessage(_("There was a problem printing.\n"
+                       "Perhaps your current printer is not set correctly?"))
+        else:
+            self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
+        printout.Destroy()

Copied: grass/trunk/gui/wxpython/mapdisp/mapwindow.py (from rev 49282, grass/trunk/gui/wxpython/gui_modules/mapdisp_window.py)
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/mapwindow.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapdisp/mapwindow.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1691 @@
+"""!
+ at package mapdisp.mapwindow
+
+ at brief Map display canvas - buffered window.
+
+Classes:
+ - BufferedWindow
+
+(C) 2006-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton
+ at author Jachym Cepicky
+"""
+
+import os
+import time
+import math
+import sys
+
+import wx
+
+import grass.script as grass
+
+from gui_core.dialogs   import SavedRegion
+from core.gcmd          import RunCommand, GException, GError
+from core.debug         import Debug
+from core.settings      import UserSettings
+from gui_core.mapwindow import MapWindow
+try:
+    import grass.lib.gis as gislib
+    haveCtypes = True
+except ImportError:
+    haveCtypes = False
+
+class BufferedWindow(MapWindow, wx.Window):
+    """!A Buffered window class (2D view mode)
+
+    Superclass for VDigitWindow (vector digitizer).
+    
+    When the drawing needs to change, you app needs to call the
+    UpdateMap() method. Since the drawing is stored in a bitmap, you
+    can also save the drawing to file by calling the
+    SaveToFile() method.
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 Map = None, tree = None, lmgr = None,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+        MapWindow.__init__(self, parent, id, Map, tree, lmgr, **kwargs)
+        wx.Window.__init__(self, parent, id, style = style, **kwargs)
+        
+        # flags
+        self.resize = False # indicates whether or not a resize event has taken place
+        self.dragimg = None # initialize variable for map panning
+        
+        # variables for drawing on DC
+        self.pen = None      # pen for drawing zoom boxes, etc.
+        self.polypen = None  # pen for drawing polylines (measurements, profiles, etc)
+        # List of wx.Point tuples defining a polyline (geographical coordinates)
+        self.polycoords = []
+        # ID of rubber band line
+        self.lineid = None
+        # ID of poly line resulting from cumulative rubber band lines (e.g. measurement)
+        self.plineid = None
+        
+        # event bindings
+        self.Bind(wx.EVT_PAINT,        self.OnPaint)
+        self.Bind(wx.EVT_SIZE,         self.OnSize)
+        self.Bind(wx.EVT_IDLE,         self.OnIdle)
+        self._bindMouseEvents()
+        
+        self.processMouse = True
+        
+        # render output objects
+        self.mapfile = None   # image file to be rendered
+        self.img     = None   # wx.Image object (self.mapfile)
+        # decoration overlays
+        self.overlays = {}
+        # images and their PseudoDC ID's for painting and dragging
+        self.imagedict = {}   
+        self.select = {}      # selecting/unselecting decorations for dragging
+        self.textdict = {}    # text, font, and color indexed by id
+        self.currtxtid = None # PseudoDC id for currently selected text
+        
+        # zoom objects
+        self.zoomhistory  = [] # list of past zoom extents
+        self.currzoom     = 0  # current set of extents in zoom history being used
+        self.zoomtype     = 1  # 1 zoom in, 0 no zoom, -1 zoom out
+        self.hitradius    = 10 # distance for selecting map decorations
+        self.dialogOffset = 5  # offset for dialog (e.g. DisplayAttributesDialog)
+        
+        # OnSize called to make sure the buffer is initialized.
+        # This might result in OnSize getting called twice on some
+        # platforms at initialization, but little harm done.
+        ### self.OnSize(None)
+        
+        self._definePseudoDC()
+        # redraw all pdc's, pdcTmp layer is redrawn always (speed issue)
+        self.redrawAll = True
+        
+        # will store an off screen empty bitmap for saving to file
+        self._buffer = None
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
+        
+        # vars for handling mouse clicks
+        self.dragid   = -1
+        self.lastpos  = (0, 0)
+        
+    def _definePseudoDC(self):
+        """!Define PseudoDC objects to use
+        """
+        # create PseudoDC used for background map, map decorations like scales and legends
+        self.pdc = wx.PseudoDC()
+        # used for digitization tool
+        self.pdcVector = None
+        # decorations (region box, etc.)
+        self.pdcDec = wx.PseudoDC()
+        # pseudoDC for temporal objects (select box, measurement tool, etc.)
+        self.pdcTmp = wx.PseudoDC()
+        
+    def _bindMouseEvents(self):
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
+        self.Bind(wx.EVT_MOTION,       self.OnMotion)
+        
+    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0, 0, 0, 0]):
+        """!Draws map and overlay decorations
+        """
+        if drawid == None:
+            if pdctype == 'image' and img:
+                drawid = self.imagedict[img]
+            elif pdctype == 'clear':
+                drawid == None
+            else:
+                drawid = wx.NewId()
+        
+        if img and pdctype == 'image':
+            # self.imagedict[img]['coords'] = coords
+            self.select[self.imagedict[img]['id']] = False # ?
+        
+        pdc.BeginDrawing()
+        
+        if drawid != 99:
+            bg = wx.TRANSPARENT_BRUSH
+        else:
+            bg = wx.Brush(self.GetBackgroundColour())
+        
+        pdc.SetBackground(bg)
+        
+        Debug.msg (5, "BufferedWindow.Draw(): id=%s, pdctype = %s, coord=%s" % \
+                       (drawid, pdctype, coords))
+        
+        # set PseudoDC id
+        if drawid is not None:
+            pdc.SetId(drawid)
+            
+        if pdctype == 'clear': # erase the display
+            bg = wx.WHITE_BRUSH
+            # bg = wx.Brush(self.GetBackgroundColour())
+            pdc.SetBackground(bg)
+            pdc.RemoveAll()
+            pdc.Clear()
+            pdc.EndDrawing()
+            
+            self.Refresh()
+            return
+        
+        if pdctype == 'image': # draw selected image
+            bitmap = wx.BitmapFromImage(img)
+            w,h = bitmap.GetSize()
+            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
+            pdc.SetIdBounds(drawid, wx.Rect(coords[0],coords[1], w, h))
+        
+        elif pdctype == 'box': # draw a box on top of the map
+            if self.pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.pen)
+                x2 = max(coords[0],coords[2])
+                x1 = min(coords[0],coords[2])
+                y2 = max(coords[1],coords[3])
+                y1 = min(coords[1],coords[3])
+                rwidth = x2-x1
+                rheight = y2-y1
+                rect = wx.Rect(x1, y1, rwidth, rheight)
+                pdc.DrawRectangleRect(rect)
+                pdc.SetIdBounds(drawid, rect)
+                
+        elif pdctype == 'line': # draw a line on top of the map
+            if self.pen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.pen)
+                pdc.DrawLinePoint(wx.Point(coords[0], coords[1]),wx.Point(coords[2], coords[3]))
+                pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], coords[2], coords[3]))
+        
+        elif pdctype == 'polyline': # draw a polyline on top of the map
+            if self.polypen:
+                pdc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
+                pdc.SetPen(self.polypen)
+                if (len(coords) < 2):
+                    return
+                i = 1
+                while i < len(coords):
+                    pdc.DrawLinePoint(wx.Point(coords[i-1][0], coords[i-1][1]),
+                                      wx.Point(coords[i][0], coords[i][1]))
+                    i += 1
+                
+                # get bounding rectangle for polyline
+                xlist = []
+                ylist = []
+                if len(coords) > 0:
+                    for point in coords:
+                        x,y = point
+                        xlist.append(x)
+                        ylist.append(y)
+                    x1 = min(xlist)
+                    x2 = max(xlist)
+                    y1 = min(ylist)
+                    y2 = max(ylist)
+                    pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
+                    # self.ovlcoords[drawid] = [x1,y1,x2,y2]
+        
+        elif pdctype == 'point': # draw point
+            if self.pen:
+                pdc.SetPen(self.pen)
+                pdc.DrawPoint(coords[0], coords[1])
+                coordsBound = (coords[0] - 5,
+                               coords[1] - 5,
+                               coords[0] + 5,
+                               coords[1] + 5)
+                pdc.SetIdBounds(drawid, wx.Rect(coordsBound))
+        
+        elif pdctype == 'text': # draw text on top of map
+            if not img['active']:
+                return # only draw active text
+            if 'rotation' in img:
+                rotation = float(img['rotation'])
+            else:
+                rotation = 0.0
+            w, h = self.GetFullTextExtent(img['text'])[0:2]
+            pdc.SetFont(img['font'])
+            pdc.SetTextForeground(img['color'])
+            coords, bbox = self.TextBounds(img)
+            if rotation == 0:
+                pdc.DrawText(img['text'], coords[0], coords[1])
+            else:
+                pdc.DrawRotatedText(img['text'], coords[0], coords[1], rotation)
+            pdc.SetIdBounds(drawid, bbox)
+        
+        pdc.EndDrawing()
+        
+        self.Refresh()
+        
+        return drawid
+    
+    def TextBounds(self, textinfo, relcoords = False):
+        """!Return text boundary data
+        
+        @param textinfo text metadata (text, font, color, rotation)
+        @param coords reference point
+        
+        @return coords of nonrotated text bbox (TL corner)
+        @return bbox of rotated text bbox (wx.Rect)
+        @return relCoords are text coord inside bbox
+        """
+        if 'rotation' in textinfo:
+            rotation = float(textinfo['rotation'])
+        else:
+            rotation = 0.0
+        
+        coords = textinfo['coords']
+        bbox = wx.Rect(coords[0], coords[1], 0, 0)
+        relCoords = (0, 0)
+        Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
+                   (textinfo['text'], rotation))
+        
+        self.Update()
+        
+        self.SetFont(textinfo['font'])
+        
+        w, h = self.GetTextExtent(textinfo['text'])
+        
+        if rotation == 0:
+            bbox[2], bbox[3] = w, h
+            if relcoords:
+                return coords, bbox, relCoords
+            else:
+                return coords, bbox
+        
+        boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
+        boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
+        if rotation > 0 and rotation < 90:
+            bbox[1] -= boxh
+            relCoords = (0, boxh)
+        elif rotation >= 90 and rotation < 180:
+            bbox[0] -= boxw
+            bbox[1] -= boxh
+            relCoords = (boxw, boxh)
+        elif rotation >= 180 and rotation < 270:
+            bbox[0] -= boxw
+            relCoords = (boxw, 0)
+        bbox[2] = boxw
+        bbox[3] = boxh
+        bbox.Inflate(h,h)
+        if relcoords:
+            return coords, bbox, relCoords
+        else:
+            return coords, bbox
+
+    def OnPaint(self, event):
+        """!Draw PseudoDC's to buffered paint DC
+        
+        If self.redrawAll is False on self.pdcTmp content is re-drawn
+        """
+        Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
+        dc = wx.BufferedPaintDC(self, self.buffer)
+        dc.Clear()
+        
+        # use PrepareDC to set position correctly
+        self.PrepareDC(dc)
+        
+        # create a clipping rect from our position and size
+        # and update region
+        rgn = self.GetUpdateRegion().GetBox()
+        dc.SetClippingRect(rgn)
+        
+        switchDraw = False
+        if self.redrawAll is None:
+            self.redrawAll = True
+            switchDraw = True
+        
+        if self.redrawAll: # redraw pdc and pdcVector
+            # draw to the dc using the calculated clipping rect
+            self.pdc.DrawToDCClipped(dc, rgn)
+            
+            # draw vector map layer
+            if hasattr(self, "digit"):
+                # decorate with GDDC (transparency)
+                try:
+                    gcdc = wx.GCDC(dc)
+                    self.pdcVector.DrawToDCClipped(gcdc, rgn)
+                except NotImplementedError, e:
+                    print >> sys.stderr, e
+                    self.pdcVector.DrawToDCClipped(dc, rgn)
+            
+            self.bufferLast = None
+        else: # do not redraw pdc and pdcVector
+            if self.bufferLast is None:
+                # draw to the dc
+                self.pdc.DrawToDC(dc)
+                
+                if hasattr(self, "digit"):
+                    # decorate with GDDC (transparency)
+                    try:
+                        gcdc = wx.GCDC(dc)
+                        self.pdcVector.DrawToDC(gcdc)
+                    except NotImplementedError, e:
+                        print >> sys.stderr, e
+                        self.pdcVector.DrawToDC(dc)
+                
+                # store buffered image
+                # self.bufferLast = wx.BitmapFromImage(self.buffer.ConvertToImage())
+                self.bufferLast = dc.GetAsBitmap(wx.Rect(0, 0, self.Map.width, self.Map.height))
+            
+            self.pdc.DrawBitmap(self.bufferLast, 0, 0, False)
+            self.pdc.DrawToDC(dc)
+        
+        # draw decorations (e.g. region box)
+        try:
+            gcdc = wx.GCDC(dc)
+            self.pdcDec.DrawToDC(gcdc)
+        except NotImplementedError, e:
+            print >> sys.stderr, e
+            self.pdcDec.DrawToDC(dc)
+        
+        # draw temporary object on the foreground
+        ### self.pdcTmp.DrawToDCClipped(dc, rgn)
+        self.pdcTmp.DrawToDC(dc)
+        
+        if switchDraw:
+            self.redrawAll = False
+        
+    def OnSize(self, event):
+        """!Scale map image so that it is the same size as the Window
+        """
+        Debug.msg(3, "BufferedWindow.OnSize():")
+        
+        # set size of the input image
+        self.Map.ChangeMapSize(self.GetClientSize())
+        # align extent based on center point and display resolution
+        # this causes that image is not resized when display windows is resized
+        ### self.Map.AlignExtentFromDisplay()
+        
+        # Make new off screen bitmap: this bitmap will always have the
+        # current drawing in it, so it can be used to save the image to
+        # a file, or whatever.
+        self.buffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
+        
+        # get the image to be rendered
+        self.img = self.GetImage()
+        
+        # update map display
+        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
+            self.img = self.img.Scale(self.Map.width, self.Map.height)
+            if len(self.Map.GetListOfLayers()) > 0:
+                self.UpdateMap()
+        
+        # re-render image on idle
+        self.resize = True
+
+        # reposition checkbox in statusbar
+        self.parent.StatusbarReposition()
+        
+        # update statusbar
+        self.parent.StatusbarUpdate()
+        
+    def OnIdle(self, event):
+        """!Only re-render a composite map image from GRASS during
+        idle time instead of multiple times during resizing.
+        """
+        if self.resize:
+            self.UpdateMap(render = True)
+        
+        event.Skip()
+
+    def SaveToFile(self, FileName, FileType, width, height):
+        """!This draws the pseudo DC to a buffer that can be saved to
+        a file.
+        
+        @param FileName file name
+        @param FileType type of bitmap
+        @param width image width
+        @param height image height
+        """
+        busy = wx.BusyInfo(message = _("Please wait, exporting image..."),
+                           parent = self)
+        wx.Yield()
+        
+        self.Map.ChangeMapSize((width, height))
+        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
+        self.Map.Render(force = True, windres = True)
+        img = self.GetImage()
+        self.Draw(self.pdc, img, drawid = 99)
+        dc = wx.BufferedPaintDC(self, ibuffer)
+        dc.Clear()
+        self.PrepareDC(dc)
+        self.pdc.DrawToDC(dc)
+        if self.pdcVector:
+            self.pdcVector.DrawToDC(dc)
+        ibuffer.SaveFile(FileName, FileType)
+        
+        busy.Destroy()
+        
+        self.UpdateMap(render = True)
+        self.Refresh()
+        
+    def GetOverlay(self):
+        """!Converts rendered overlay files to wx.Image
+        
+        Updates self.imagedict
+        
+        @return list of images
+        """
+        imgs = []
+        for overlay in self.Map.GetListOfLayers(l_type = "overlay", l_active = True):
+            if os.path.isfile(overlay.mapfile) and os.path.getsize(overlay.mapfile):
+                img = wx.Image(overlay.mapfile, wx.BITMAP_TYPE_ANY)
+                self.imagedict[img] = { 'id' : overlay.id,
+                                        'layer' : overlay }
+                imgs.append(img)
+
+        return imgs
+    
+    def GetImage(self):
+        """!Converts redered map files to wx.Image
+        
+        Updates self.imagedict (id=99)
+        
+        @return wx.Image instance (map composition)
+        """
+        imgId = 99
+        if self.mapfile and self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
+                os.path.getsize(self.Map.mapfile):
+            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
+        else:
+            img = None
+        
+        self.imagedict[img] = { 'id': imgId }
+        
+        return img
+
+    def UpdateMap(self, render = True, renderVector = True):
+        """!Updates the canvas anytime there is a change to the
+        underlaying images or to the geometry of the canvas.
+        
+        @param render re-render map composition
+        @param renderVector re-render vector map layer enabled for editing (used for digitizer)
+        """
+        start = time.clock()
+        
+        self.resize = False
+        
+        if not self.Map.cmdfile and self.img is None:
+            render = True
+        
+        #
+        # initialize process bar (only on 'render')
+        #
+        if render or renderVector:
+            self.parent.GetProgressBar().Show()
+            if self.parent.GetProgressBar().GetRange() > 0:
+                self.parent.GetProgressBar().SetValue(1)
+        
+        #
+        # render background image if needed
+        #
+        # update layer dictionary if there has been a change in layers
+        if self.tree and self.tree.reorder:
+            self.tree.ReorderLayers()
+        
+        # reset flag for auto-rendering
+        if self.tree:
+            self.tree.rerender = False
+        
+        try:
+            if render:
+                # update display size
+                self.Map.ChangeMapSize(self.GetClientSize())
+                if self.parent.GetProperty('resolution'):
+                    # use computation region resolution for rendering
+                    windres = True
+                else:
+                    windres = False
+                
+                self.mapfile = self.Map.Render(force = True, mapWindow = self.parent,
+                                               windres = windres)
+            else:
+                self.mapfile = self.Map.Render(force = False, mapWindow = self.parent)
+            
+        except GException, e:
+            GError(message = e.value)
+            self.mapfile = None
+        
+        self.img = self.GetImage() # id=99
+        
+        #
+        # clear pseudoDcs
+        #
+        for pdc in (self.pdc,
+                    self.pdcDec,
+                    self.pdcTmp):
+            pdc.Clear()
+            pdc.RemoveAll()
+        
+        #
+        # draw background map image to PseudoDC
+        #
+        if not self.img:
+            self.Draw(self.pdc, pdctype = 'clear')
+        else:
+            try:
+                id = self.imagedict[self.img]['id']
+            except:
+                return False
+            
+            self.Draw(self.pdc, self.img, drawid = id)
+        
+        #
+        # render vector map layer
+        #
+        if renderVector and hasattr(self, "digit"):
+            self._updateMap()
+        #
+        # render overlays
+        #
+        for img in self.GetOverlay():
+            # draw any active and defined overlays
+            if self.imagedict[img]['layer'].IsActive():
+                id = self.imagedict[img]['id']
+                self.Draw(self.pdc, img = img, drawid = id,
+                          pdctype = self.overlays[id]['pdcType'], coords = self.overlays[id]['coords'])
+        
+        for id in self.textdict.keys():
+            self.Draw(self.pdc, img = self.textdict[id], drawid = id,
+                      pdctype = 'text', coords = [10, 10, 10, 10])
+        
+        # optionally draw computational extent box
+        self.DrawCompRegionExtent()
+        
+        #
+        # redraw pdcTmp if needed
+        #
+        if len(self.polycoords) > 0:
+            self.DrawLines(self.pdcTmp)
+            
+        if not self.parent.IsStandalone() and \
+                self.parent.GetLayerManager().gcpmanagement:
+            # -> georectifier (redraw GCPs)
+            if self.parent.GetMapToolbar():
+                if self == self.parent.TgtMapWindow:
+                    coordtype = 'target'
+                else:
+                    coordtype = 'source'
+
+                self.parent.DrawGCP(coordtype)
+
+        # 
+        # clear measurement
+        #
+        if self.mouse["use"] == "measure":
+            self.ClearLines(pdc = self.pdcTmp)
+            self.polycoords = []
+            self.mouse['use'] = 'pointer'
+            self.mouse['box'] = 'point'
+            self.mouse['end'] = [0, 0]
+            self.SetCursor(self.parent.cursors["default"])
+            
+        stop = time.clock()
+        
+        #
+        # hide process bar
+        #
+        self.parent.GetProgressBar().Hide()
+
+        #
+        # update statusbar 
+        #
+        ### self.Map.SetRegion()
+        self.parent.StatusbarUpdate()
+        
+        
+        Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
+                   (render, renderVector, (stop-start)))
+        
+        return True
+
+    def DrawCompRegionExtent(self):
+        """!Draw computational region extent in the display
+        
+        Display region is drawn as a blue box inside the computational region,
+        computational region inside a display region as a red box).
+        """
+        if hasattr(self, "regionCoords"):
+            compReg = self.Map.GetRegion()
+            dispReg = self.Map.GetCurrentRegion()
+            reg = None
+            if self.IsInRegion(dispReg, compReg):
+                self.polypen = wx.Pen(colour = wx.Colour(0, 0, 255, 128), width = 3, style = wx.SOLID)
+                reg = dispReg
+            else:
+                self.polypen = wx.Pen(colour = wx.Colour(255, 0, 0, 128),
+                                      width = 3, style = wx.SOLID)
+                reg = compReg
+            
+            self.regionCoords = []
+            self.regionCoords.append((reg['w'], reg['n']))
+            self.regionCoords.append((reg['e'], reg['n']))
+            self.regionCoords.append((reg['e'], reg['s']))
+            self.regionCoords.append((reg['w'], reg['s']))
+            self.regionCoords.append((reg['w'], reg['n']))
+            # draw region extent
+            self.DrawLines(pdc = self.pdcDec, polycoords = self.regionCoords)
+
+    def IsInRegion(self, region, refRegion):
+        """!
+        Test if 'region' is inside of 'refRegion'
+
+        @param region input region
+        @param refRegion reference region (e.g. computational region)
+
+        @return True if region is inside of refRegion
+        @return False 
+        """
+        if region['s'] >= refRegion['s'] and \
+                region['n'] <= refRegion['n'] and \
+                region['w'] >= refRegion['w'] and \
+                region['e'] <= refRegion['e']:
+            return True
+        
+        return False
+
+    def EraseMap(self):
+        """!Erase map canvas
+        """
+        self.Draw(self.pdc, pdctype = 'clear')
+        
+        if hasattr(self, "digit"):
+            self.Draw(self.pdcVector, pdctype = 'clear')
+        
+        self.Draw(self.pdcDec, pdctype = 'clear')
+        self.Draw(self.pdcTmp, pdctype = 'clear')
+        
+    def DragMap(self, moveto):
+        """!Drag the entire map image for panning.
+        
+        @param moveto dx,dy
+        """
+        dc = wx.BufferedDC(wx.ClientDC(self))
+        dc.SetBackground(wx.Brush("White"))
+        dc.Clear()
+        
+        self.dragimg = wx.DragImage(self.buffer)
+        self.dragimg.BeginDrag((0, 0), self)
+        self.dragimg.GetImageRect(moveto)
+        self.dragimg.Move(moveto)
+        
+        self.dragimg.DoDrawImage(dc, moveto)
+        self.dragimg.EndDrag()
+        
+    def DragItem(self, id, event):
+        """!Drag an overlay decoration item
+        """
+        if id == 99 or id == '' or id == None: return
+        Debug.msg (5, "BufferedWindow.DragItem(): id=%d" % id)
+        x, y = self.lastpos
+        dx = event.GetX() - x
+        dy = event.GetY() - y
+        self.pdc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+        r = self.pdc.GetIdBounds(id)
+        
+        if type(r) is list:
+            r = wx.Rect(r[0], r[1], r[2], r[3])
+        if id > 100: # text dragging
+            rtop = (r[0],r[1]-r[3],r[2],r[3])
+            r = r.Union(rtop)
+            rleft = (r[0]-r[2],r[1],r[2],r[3])
+            r = r.Union(rleft)
+        self.pdc.TranslateId(id, dx, dy)
+        
+        r2 = self.pdc.GetIdBounds(id)
+        if type(r2) is list:
+            r2 = wx.Rect(r[0], r[1], r[2], r[3])
+        if id > 100: # text
+            self.textdict[id]['bbox'] = r2
+            self.textdict[id]['coords'][0] += dx
+            self.textdict[id]['coords'][1] += dy
+        r = r.Union(r2)
+        r.Inflate(4,4)
+        self.RefreshRect(r, False)
+        self.lastpos = (event.GetX(), event.GetY())
+                
+    def MouseDraw(self, pdc = None, begin = None, end = None):
+        """!Mouse box or line from 'begin' to 'end'
+        
+        If not given from self.mouse['begin'] to self.mouse['end'].
+        """
+        if not pdc:
+            return
+        
+        if begin is None:
+            begin = self.mouse['begin']
+        if end is None:
+            end   = self.mouse['end']
+        
+        Debug.msg (5, "BufferedWindow.MouseDraw(): use=%s, box=%s, begin=%f,%f, end=%f,%f" % \
+                       (self.mouse['use'], self.mouse['box'],
+                        begin[0], begin[1], end[0], end[1]))
+        
+        if self.mouse['box'] == "box":
+            boxid = wx.ID_NEW
+            mousecoords = [begin[0], begin[1],
+                           end[0], end[1]]
+            r = pdc.GetIdBounds(boxid)
+            if type(r) is list:
+                r = wx.Rect(r[0], r[1], r[2], r[3])
+            r.Inflate(4, 4)
+            try:
+                pdc.ClearId(boxid)
+            except:
+                pass
+            self.RefreshRect(r, False)
+            pdc.SetId(boxid)
+            self.Draw(pdc, drawid = boxid, pdctype = 'box', coords = mousecoords)
+        
+        elif self.mouse['box'] == "line":
+            self.lineid = wx.ID_NEW
+            mousecoords = [begin[0], begin[1], \
+                           end[0], end[1]]
+            x1 = min(begin[0],end[0])
+            x2 = max(begin[0],end[0])
+            y1 = min(begin[1],end[1])
+            y2 = max(begin[1],end[1])
+            r = wx.Rect(x1,y1,x2-x1,y2-y1)
+            r.Inflate(4,4)
+            try:
+                pdc.ClearId(self.lineid)
+            except:
+                pass
+            self.RefreshRect(r, False)
+            pdc.SetId(self.lineid)
+            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = mousecoords)
+
+    def DrawLines(self, pdc = None, polycoords = None):
+        """!Draw polyline in PseudoDC
+        
+        Set self.pline to wx.NEW_ID + 1
+        
+        polycoords - list of polyline vertices, geographical coordinates
+        (if not given, self.polycoords is used)
+        """
+        if not pdc:
+            pdc = self.pdcTmp
+        
+        if not polycoords:
+            polycoords = self.polycoords
+        
+        if len(polycoords) > 0:
+            self.plineid = wx.ID_NEW + 1
+            # convert from EN to XY
+            coords = []
+            for p in polycoords:
+                coords.append(self.Cell2Pixel(p))
+
+            self.Draw(pdc, drawid = self.plineid, pdctype = 'polyline', coords = coords)
+            
+            Debug.msg (4, "BufferedWindow.DrawLines(): coords=%s, id=%s" % \
+                           (coords, self.plineid))
+            
+            return self.plineid
+        
+        return -1
+
+    def DrawCross(self, pdc, coords, size, rotation = 0,
+                  text = None, textAlign = 'lr', textOffset = (5, 5)):
+        """!Draw cross in PseudoDC
+
+        @todo implement rotation
+
+        @param pdc PseudoDC
+        @param coord center coordinates
+        @param rotation rotate symbol
+        @param text draw also text (text, font, color, rotation)
+        @param textAlign alignment (default 'lower-right')
+        @textOffset offset for text (from center point)
+        """
+        Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
+                  (pdc, coords, size))
+        coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
+                       (coords[0], coords[1] - size, coords[0], coords[1] + size))
+
+        self.lineid = wx.NewId()
+        for lineCoords in coordsCross:
+            self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = lineCoords)
+        
+        if not text:
+            return self.lineid
+        
+        if textAlign == 'ul':
+            coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
+        elif textAlign == 'ur':
+            coord = [coords[0] + textOffset[0], coords[1] - textOffset[1], 0, 0]
+        elif textAlign == 'lr':
+            coord = [coords[0] + textOffset[0], coords[1] + textOffset[1], 0, 0]
+        else:
+            coord = [coords[0] - textOffset[0], coords[1] + textOffset[1], 0, 0]
+        
+        self.Draw(pdc, img = text,
+                  pdctype = 'text', coords = coord)
+        
+        return self.lineid
+
+    def MouseActions(self, event):
+        """!Mouse motion and button click notifier
+        """
+        if not self.processMouse:
+            return
+        
+        # zoom with mouse wheel
+        if event.GetWheelRotation() != 0:
+            self.OnMouseWheel(event)
+            
+        # left mouse button pressed
+        elif event.LeftDown():
+            self.OnLeftDown(event)
+        
+        # left mouse button released
+        elif event.LeftUp():
+            self.OnLeftUp(event)
+        
+        # dragging
+        elif event.Dragging():
+            self.OnDragging(event)
+        
+        # double click
+        elif event.ButtonDClick():
+            self.OnButtonDClick(event)
+        
+        # middle mouse button pressed
+        elif event.MiddleDown():
+            self.OnMiddleDown(event)
+        
+        # middle mouse button relesed
+        elif event.MiddleUp():
+            self.OnMiddleUp(event)
+        
+        # right mouse button pressed
+        elif event.RightDown():
+            self.OnRightDown(event)
+        
+        # right mouse button released
+        elif event.RightUp():
+            self.OnRightUp(event)
+        
+        elif event.Entering():
+            self.OnMouseEnter(event)
+        
+        elif event.Moving():
+            self.OnMouseMoving(event)
+                
+    def OnMouseWheel(self, event):
+        """!Mouse wheel moved
+        """
+        self.processMouse = False
+        current  = event.GetPositionTuple()[:]
+        wheel = event.GetWheelRotation()
+        Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
+        # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
+        begin = (current[0] - self.Map.width / 4,
+                 current[1] - self.Map.height / 4)
+        end   = (current[0] + self.Map.width / 4,
+                 current[1] + self.Map.height / 4)
+        
+        if wheel > 0:
+            zoomtype = 1
+        else:
+            zoomtype = -1
+        
+        # zoom
+        self.Zoom(begin, end, zoomtype)
+        
+        # redraw map
+        self.UpdateMap()
+        
+        # update statusbar
+        self.parent.StatusbarUpdate()
+        
+        self.Refresh()
+        self.processMouse = True
+        
+    def OnDragging(self, event):
+        """!Mouse dragging
+        """
+        Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
+        current  = event.GetPositionTuple()[:]
+        previous = self.mouse['begin']
+        move = (current[0] - previous[0],
+                current[1] - previous[1])
+        
+        if hasattr(self, "digit"):
+            digitToolbar = self.toolbar
+        else:
+            digitToolbar = None
+        
+        # dragging or drawing box with left button
+        if self.mouse['use'] == 'pan' or \
+                event.MiddleIsDown():
+            self.DragMap(move)
+        
+        # dragging decoration overlay item
+        elif (self.mouse['use'] == 'pointer' and 
+                not digitToolbar and 
+                self.dragid != None):
+            self.DragItem(self.dragid, event)
+        
+        # dragging anything else - rubber band box or line
+        else:
+            if (self.mouse['use'] == 'pointer' and 
+                not digitToolbar):
+                return
+            
+            self.mouse['end'] = event.GetPositionTuple()[:]
+            if (event.LeftIsDown() and 
+                not (digitToolbar and 
+                    digitToolbar.GetAction() in ("moveLine",) and 
+                     self.digit.GetDisplay().GetSelected() > 0)):
+                self.MouseDraw(pdc = self.pdcTmp)
+        
+    def OnLeftDown(self, event):
+        """!Left mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftDown(): use=%s" % \
+                   self.mouse["use"])
+        
+        self.mouse['begin'] = event.GetPositionTuple()[:]
+        
+        if self.mouse["use"] in ["measure", "profile"]:
+            # measure or profile
+            if len(self.polycoords) == 0:
+                self.mouse['end'] = self.mouse['begin']
+                self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
+                self.ClearLines(pdc=self.pdcTmp)
+            else:
+                self.mouse['begin'] = self.mouse['end']
+        
+        elif self.mouse['use'] in ('zoom', 'legend'):
+            pass
+        
+        # vector digizer
+        elif self.mouse["use"] == "pointer" and \
+                hasattr(self, "digit"):
+            if event.ControlDown():
+                self.OnLeftDownUndo(event)
+            else:
+                self._onLeftDown(event)
+        
+        elif self.mouse['use'] == 'pointer':
+            # get decoration or text id
+            self.idlist = []
+            self.dragid = ''
+            self.lastpos = self.mouse['begin']
+            idlist = self.pdc.FindObjects(self.lastpos[0], self.lastpos[1],
+                                          self.hitradius)
+            if 99 in idlist:
+                idlist.remove(99)                             
+            if idlist != []:
+                self.dragid = idlist[0] #drag whatever is on top
+        else:
+            pass
+        
+        event.Skip()
+        
+    def OnLeftUp(self, event):
+        """!Left mouse button released
+        """
+        Debug.msg (5, "BufferedWindow.OnLeftUp(): use=%s" % \
+                       self.mouse["use"])
+        
+        self.mouse['end'] = event.GetPositionTuple()[:]
+        
+        if self.mouse['use'] in ["zoom", "pan"]:
+            # set region in zoom or pan
+            begin = self.mouse['begin']
+            end = self.mouse['end']
+            
+            if self.mouse['use'] == 'zoom':
+                # set region for click (zero-width box)
+                if begin[0] - end[0] == 0 or \
+                        begin[1] - end[1] == 0:
+                    # zoom 1/2 of the screen (TODO: settings)
+                    begin = (end[0] - self.Map.width / 4,
+                             end[1] - self.Map.height / 4)
+                    end   = (end[0] + self.Map.width / 4,
+                             end[1] + self.Map.height / 4)
+            
+            self.Zoom(begin, end, self.zoomtype)
+
+            # redraw map
+            self.UpdateMap(render = True)
+            
+            # update statusbar
+            self.parent.StatusbarUpdate()
+            
+        elif self.mouse["use"] == "query":
+            # querying
+            layers = self.GetSelectedLayer(multi = True)
+            isRaster = False
+            nVectors = 0
+            for l in layers:
+                if l.GetType() == 'raster':
+                    isRaster = True
+                    break
+                if l.GetType() == 'vector':
+                    nVectors += 1
+            
+            if isRaster or nVectors > 1:
+                self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
+            else:
+                self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
+                # clear temp canvas
+                self.UpdateMap(render = False, renderVector = False)
+            
+        elif self.mouse["use"] == "queryVector":
+            # editable mode for vector map layers
+            self.parent.QueryVector(self.mouse['begin'][0], self.mouse['begin'][1])
+            
+            # clear temp canvas
+            self.UpdateMap(render = False, renderVector = False)
+        
+        elif self.mouse["use"] in ["measure", "profile"]:
+            # measure or profile
+            if self.mouse["use"] == "measure":
+                self.parent.MeasureDist(self.mouse['begin'], self.mouse['end'])
+            
+            self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
+            self.ClearLines(pdc = self.pdcTmp)
+            self.DrawLines(pdc = self.pdcTmp)
+        
+        elif self.mouse["use"] == "pointer" and \
+                not self.parent.IsStandalone() and \
+                self.parent.GetLayerManager().gcpmanagement:
+            # -> GCP manager
+            if self.parent.GetToolbar('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 \
+                hasattr(self, "digit"):
+            self._onLeftUp(event)
+            
+        elif (self.mouse['use'] == 'pointer' and 
+                self.dragid >= 0):
+            # end drag of overlay decoration
+            
+            if self.dragid < 99 and self.dragid in self.overlays:
+                self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
+            elif self.dragid > 100 and self.dragid in self.textdict:
+                self.textdict[self.dragid]['bbox'] = self.pdc.GetIdBounds(self.dragid)
+            else:
+                pass
+            self.dragid = None
+            self.currtxtid = None
+            
+        elif self.mouse['use'] == 'legend':
+            self.ResizeLegend(self.mouse["begin"], self.mouse["end"])
+            self.parent.dialogs['legend'].FindWindowByName("resize").SetValue(False)
+            self.Map.GetOverlay(1).SetActive(True)
+            self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
+            self.parent.MapWindow.mouse['use'] = 'pointer'
+            
+            self.UpdateMap()
+            
+    def OnButtonDClick(self, event):
+        """!Mouse button double click
+        """
+        Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
+                   self.mouse["use"])
+        
+        if self.mouse["use"] == "measure":
+            # measure
+            self.ClearLines(pdc=self.pdcTmp)
+            self.polycoords = []
+            self.mouse['use'] = 'pointer'
+            self.mouse['box'] = 'point'
+            self.mouse['end'] = [0, 0]
+            self.Refresh()
+            self.SetCursor(self.parent.cursors["default"])
+        
+        elif self.mouse["use"] != "profile" or \
+                (self.mouse['use'] != 'pointer' and \
+                     hasattr(self, "digit")):
+               # select overlay decoration options dialog
+            clickposition = event.GetPositionTuple()[:]
+            idlist  = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
+            if idlist == []:
+                return
+            self.dragid = idlist[0]
+
+            # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
+            if self.dragid > 100:
+                self.currtxtid = self.dragid
+                self.parent.OnAddText(None)
+            elif self.dragid == 0:
+                self.parent.OnAddBarscale(None)
+            elif self.dragid == 1:
+                self.parent.OnAddLegend(None)
+        
+    def OnRightDown(self, event):
+        """!Right mouse button pressed
+        """
+        Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
+                   self.mouse["use"])
+        
+        if hasattr(self, "digit"):
+            self._onRightDown(event)
+        
+        event.Skip()
+        
+    def OnRightUp(self, event):
+        """!Right mouse button released
+        """
+        Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
+                   self.mouse["use"])
+        
+        if hasattr(self, "digit"):
+            self._onRightUp(event)
+        
+        self.redrawAll = True
+        self.Refresh()
+        
+        event.Skip()
+        
+    def OnMiddleDown(self, event):
+        """!Middle mouse button pressed
+        """
+        if not event:
+            return
+        
+        self.mouse['begin'] = event.GetPositionTuple()[:]
+        
+    def OnMiddleUp(self, event):
+        """!Middle mouse button released
+        """
+        self.mouse['end'] = event.GetPositionTuple()[:]
+        
+        # set region in zoom or pan
+        begin = self.mouse['begin']
+        end   = self.mouse['end']
+        
+        self.Zoom(begin, end, 0) # no zoom
+        
+        # redraw map
+        self.UpdateMap(render = True)
+        
+        # update statusbar
+        self.parent.StatusbarUpdate()
+        
+    def OnMouseEnter(self, event):
+        """!Mouse entered window and no mouse buttons were pressed
+        """
+        if not self.parent.IsStandalone() and \
+                self.parent.GetLayerManager().gcpmanagement:
+            if self.parent.GetToolbar('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
+        """
+        if self.mouse["use"] == "pointer" and \
+                hasattr(self, "digit"):
+            self._onMouseMoving(event)
+        
+        event.Skip()
+        
+    def ClearLines(self, pdc = None):
+        """!Clears temporary drawn lines from PseudoDC
+        """
+        if not pdc:
+            pdc = self.pdcTmp
+        try:
+            pdc.ClearId(self.lineid)
+            pdc.RemoveId(self.lineid)
+        except:
+            pass
+        
+        try:
+            pdc.ClearId(self.plineid)
+            pdc.RemoveId(self.plineid)
+        except:
+            pass
+        
+        Debug.msg(4, "BufferedWindow.ClearLines(): lineid=%s, plineid=%s" %
+                  (self.lineid, self.plineid))
+        
+        return True
+
+    def Pixel2Cell(self, (x, y)):
+        """!Convert image coordinates to real word coordinates
+        
+        @param x, y image coordinates
+        
+        @return easting, northing
+        @return None on error
+        """
+        try:
+            x = int(x)
+            y = int(y)
+        except:
+            return None
+        
+        if self.Map.region["ewres"] > self.Map.region["nsres"]:
+            res = self.Map.region["ewres"]
+        else:
+            res = self.Map.region["nsres"]
+        
+        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
+        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
+        
+        east  = w + x * res
+        north = n - y * res
+        
+        return (east, north)
+    
+    def Cell2Pixel(self, (east, north)):
+        """!Convert real word coordinates to image coordinates
+        """
+        try:
+            east  = float(east)
+            north = float(north)
+        except:
+            return None
+        
+        if self.Map.region["ewres"] > self.Map.region["nsres"]:
+            res = self.Map.region["ewres"]
+        else:
+            res = self.Map.region["nsres"]
+        
+        w = self.Map.region["center_easting"] - (self.Map.width / 2) * res
+        n = self.Map.region["center_northing"] + (self.Map.height / 2) * res
+        
+        x = (east  - w) / res
+        y = (n - north) / res
+        
+        return (x, y)
+    
+    def ResizeLegend(self, begin, end):
+        w = abs(begin[0] - end[0])
+        h = abs(begin[1] - end[1])
+        if begin[0] < end[0]:
+            x = begin[0]
+        else:
+            x = end[0]
+        if begin[1] < end[1]:
+            y = begin[1]
+        else:
+            y = end[1]
+        screenRect = wx.Rect(x, y, w, h)
+        screenSize = self.GetClientSizeTuple()
+        at = [(screenSize[1] - (y + h)) / float(screenSize[1]) * 100,
+              (screenSize[1] - y) / float(screenSize[1]) * 100,
+              x / float(screenSize[0]) * 100,
+              (x + w) / float(screenSize[0]) * 100]
+        for i, subcmd in enumerate(self.overlays[1]['cmd']):
+            if subcmd.startswith('at='):
+                self.overlays[1]['cmd'][i] = "at=%d,%d,%d,%d" % (at[0], at[1], at[2], at[3])
+        self.Map.ChangeOverlay(1, True, command = self.overlays[1]['cmd'])
+        self.overlays[1]['coords'] = (0,0)
+        
+    def Zoom(self, begin, end, zoomtype):
+        """!Calculates new region while (un)zoom/pan-ing
+        """
+        x1, y1 = begin
+        x2, y2 = end
+        newreg = {}
+        
+        # threshold - too small squares do not make sense
+        # can only zoom to windows of > 5x5 screen pixels
+        if abs(x2-x1) > 5 and abs(y2-y1) > 5 and zoomtype != 0:
+            if x1 > x2:
+                x1, x2 = x2, x1
+            if y1 > y2:
+                y1, y2 = y2, y1
+            
+            # zoom in
+            if zoomtype > 0:
+                newreg['w'], newreg['n'] = self.Pixel2Cell((x1, y1))
+                newreg['e'], newreg['s'] = self.Pixel2Cell((x2, y2))
+            
+            # zoom out
+            elif zoomtype < 0:
+                newreg['w'], newreg['n'] = self.Pixel2Cell((-x1 * 2, -y1 * 2))
+                newreg['e'], newreg['s'] = self.Pixel2Cell((self.Map.width  + 2 * \
+                                                                (self.Map.width  - x2),
+                                                            self.Map.height + 2 * \
+                                                                (self.Map.height - y2)))
+        # pan
+        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))
+        
+        # if new region has been calculated, set the values
+        if newreg != {}:
+            # LL locations
+            if self.Map.projinfo['proj'] == 'll':
+                self.Map.region['n'] = min(self.Map.region['n'], 90.0)
+                self.Map.region['s'] = max(self.Map.region['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
+            if not self.parent.HasProperty('alignExtent') or \
+                    self.parent.GetProperty('alignExtent'):
+                self.Map.AlignExtentFromDisplay()
+            else:
+                for k in ('n', 's', 'e', 'w'):
+                    self.Map.region[k] = newreg[k]
+            
+            if hasattr(self, "digit") and \
+                    hasattr(self, "moveInfo"):
+                self._zoom(None)
+            
+            self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                             self.Map.region['e'], self.Map.region['w'])
+        
+        if self.redrawAll is False:
+            self.redrawAll = True
+        
+    def ZoomBack(self):
+        """!Zoom to previous extents in zoomhistory list
+        """
+        zoom = list()
+        
+        if len(self.zoomhistory) > 1:
+            self.zoomhistory.pop()
+            zoom = self.zoomhistory[-1]
+        
+        # disable tool if stack is empty
+        if len(self.zoomhistory) < 2: # disable tool
+            toolbar = self.parent.GetMapToolbar()
+            toolbar.Enable('zoomback', enable = False)
+        
+        # zoom to selected region
+        self.Map.GetRegion(n = zoom[0], s = zoom[1],
+                           e = zoom[2], w = zoom[3],
+                           update = True)
+        # update map
+        self.UpdateMap()
+        
+        # update statusbar
+        self.parent.StatusbarUpdate()
+
+    def ZoomHistory(self, n, s, e, w):
+        """!Manages a list of last 10 zoom extents
+
+        @param n,s,e,w north, south, east, west
+
+        @return removed history item if exists (or None)
+        """
+        removed = None
+        self.zoomhistory.append((n,s,e,w))
+        
+        if len(self.zoomhistory) > 10:
+            removed = self.zoomhistory.pop(0)
+        
+        if removed:
+            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s, removed=%s" %
+                      (self.zoomhistory, removed))
+        else:
+            Debug.msg(4, "BufferedWindow.ZoomHistory(): hist=%s" %
+                      (self.zoomhistory))
+        
+        # update toolbar
+        if len(self.zoomhistory) > 1:
+            enable = True
+        else:
+            enable = False
+        
+        toolbar = self.parent.GetMapToolbar()
+        
+        toolbar.Enable('zoomback', enable)
+        
+        return removed
+
+    def ResetZoomHistory(self):
+        """!Reset zoom history"""
+        self.zoomhistory = list()
+                
+    def ZoomToMap(self, layers = None, ignoreNulls = False, render = True):
+        """!Set display extents to match selected raster
+        or vector map(s).
+
+        @param layers list of layers to be zoom to
+        @param ignoreNulls True to ignore null-values (valid only for rasters)
+        @param render True to re-render display
+        """
+        zoomreg = {}
+        
+        if not layers:
+            layers = self.GetSelectedLayer(multi = True)
+        
+        if not layers:
+            return
+        
+        rast = []
+        vect = []
+        updated = False
+        for l in layers:
+            # only raster/vector layers are currently supported
+            if l.type == 'raster':
+                rast.append(l.GetName())
+            elif l.type == 'vector':
+                if hasattr(self, "digit") and \
+                        self.toolbar.GetLayer() == l:
+                    w, s, b, e, n, t = self.digit.GetDisplay().GetMapBoundingBox()
+                    self.Map.GetRegion(n = n, s = s, w = w, e = e,
+                                       update = True)
+                    updated = True
+                else:
+                    vect.append(l.name)
+            elif l.type == 'rgb':
+                for rname in l.GetName().splitlines():
+                    rast.append(rname)
+            
+        if not updated:
+            self.Map.GetRegion(rast = rast,
+                               vect = vect,
+                               update = True)
+        
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        if render:
+            self.UpdateMap()
+        
+        self.parent.StatusbarUpdate()
+        
+    def ZoomToWind(self):
+        """!Set display geometry to match computational region
+        settings (set with g.region)
+        """
+        self.Map.region = self.Map.GetRegion()
+        
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        self.UpdateMap()
+        
+        self.parent.StatusbarUpdate()
+
+    def ZoomToDefault(self):
+        """!Set display geometry to match default region settings
+        """
+        self.Map.region = self.Map.GetRegion(default = True)
+        self.Map.AdjustRegion() # aling region extent to the display
+
+        self.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
+                         self.Map.region['e'], self.Map.region['w'])
+        
+        self.UpdateMap()
+        
+        self.parent.StatusbarUpdate()
+    
+    
+    def GoTo(self, e, n):
+        region = self.Map.GetCurrentRegion()
+
+        region['center_easting'], region['center_northing'] = e, n
+        
+        dn = (region['nsres'] * region['rows']) / 2.
+        region['n'] = region['center_northing'] + dn
+        region['s'] = region['center_northing'] - dn
+        de = (region['ewres'] * region['cols']) / 2.
+        region['e'] = region['center_easting'] + de
+        region['w'] = region['center_easting'] - de
+
+        self.Map.AdjustRegion()
+
+        # add to zoom history
+        self.ZoomHistory(region['n'], region['s'],
+                                   region['e'], region['w'])        
+        self.UpdateMap()
+    
+    def DisplayToWind(self):
+        """!Set computational region (WIND file) to match display
+        extents
+        """
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        # We ONLY want to set extents here. Don't mess with resolution. Leave that
+        # for user to set explicitly with g.region
+        new = self.Map.AlignResolution()
+        RunCommand('g.region',
+                   parent = self,
+                   overwrite = True,
+                   n = new['n'],
+                   s = new['s'],
+                   e = new['e'],
+                   w = new['w'],
+                   rows = int(new['rows']),
+                   cols = int(new['cols']))
+        
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+        
+    def ZoomToSaved(self):
+        """!Set display geometry to match extents in
+        saved region file
+        """
+        dlg = SavedRegion(parent = self,
+                          title = _("Zoom to saved region extents"),
+                          loadsave='load')
+        
+        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.wind:
+            dlg.Destroy()
+            return
+        
+        if not grass.find_file(name = dlg.wind, element = 'windows')['name']:
+            wx.MessageBox(parent = self,
+                          message = _("Region <%s> not found. Operation canceled.") % dlg.wind,
+                          caption = _("Error"), style = wx.ICON_ERROR | wx.OK | wx.CENTRE)
+            dlg.Destroy()
+            return
+        
+        self.Map.GetRegion(regionName = dlg.wind,
+                           update = True)
+        
+        dlg.Destroy()
+        
+        self.ZoomHistory(self.Map.region['n'],
+                         self.Map.region['s'],
+                         self.Map.region['e'],
+                         self.Map.region['w'])
+        
+        self.UpdateMap()
+                
+    def SaveDisplayRegion(self):
+        """!Save display extents to named region file.
+        """
+        dlg = SavedRegion(parent = self,
+                          title = _("Save display extents to region file"),
+                          loadsave='save')
+        
+        if dlg.ShowModal() == wx.ID_CANCEL or not dlg.wind:
+            dlg.Destroy()
+            return
+        
+        # test to see if it already exists and ask permission to overwrite
+        if grass.find_file(name = dlg.wind, element = 'windows')['name']:
+            overwrite = wx.MessageBox(parent = self,
+                                      message = _("Region file <%s> already exists. "
+                                                  "Do you want to overwrite it?") % (dlg.wind),
+                                      caption = _("Warning"), style = wx.YES_NO | wx.CENTRE)
+            if (overwrite == wx.YES):
+                self.SaveRegion(dlg.wind)
+        else:
+            self.SaveRegion(dlg.wind)
+        
+        dlg.Destroy()
+        
+    def SaveRegion(self, wind):
+        """!Save region settings
+        
+        @param wind region name
+        """
+        new = self.Map.GetCurrentRegion()
+        
+        tmpreg = os.getenv("GRASS_REGION")
+        if tmpreg:
+            del os.environ["GRASS_REGION"]
+        
+        RunCommand('g.region',
+                   overwrite = True,
+                   parent = self,
+                   flags = 'u',
+                   n = new['n'],
+                   s = new['s'],
+                   e = new['e'],
+                   w = new['w'],
+                   rows = int(new['rows']),
+                   cols = int(new['cols']),
+                   save = wind)
+        
+        if tmpreg:
+            os.environ["GRASS_REGION"] = tmpreg
+        
+    def Distance(self, beginpt, endpt, screen = True):
+        """!Calculete distance
+        
+        Ctypes required for LL-locations
+        
+        @param beginpt first point
+        @param endpt second point
+        @param screen True for screen coordinates otherwise EN
+        """
+        if screen:
+            e1, n1 = self.Pixel2Cell(beginpt)
+            e2, n2 = self.Pixel2Cell(endpt)
+        else:
+            e1, n1 = beginpt
+            e2, n2 = endpt
+            
+        dEast  = (e2 - e1)
+        dNorth = (n2 - n1)
+        
+        if self.parent.Map.projinfo['proj'] == 'll' and haveCtypes:
+            dist = gislib.G_distance(e1, n1, e2, n2)
+        else:
+            dist = math.sqrt(math.pow((dEast), 2) + math.pow((dNorth), 2))
+        
+        return (dist, (dEast, dNorth))
+
+    def GetMap(self):
+        """!Get render.Map() instance"""
+        return self.Map

Copied: grass/trunk/gui/wxpython/mapdisp/statusbar.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/mapdisp_statusbar.py)
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/statusbar.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapdisp/statusbar.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1059 @@
+"""!
+ at package mapdisp.statusbar
+
+ at brief Classes for statusbar management
+
+Classes:
+ - SbException
+ - SbManager
+ - SbItem
+ - SbRender
+ - SbShowRegion
+ - SbAlignExtent
+ - SbResolution
+ - SbMapScale
+ - SbGoTo
+ - SbProjection
+ - SbMask
+ - SbTextItem
+ - SbDisplayGeometry
+ - SbCoordinates
+ - SbRegionExtent
+ - SbCompRegionExtent
+ - SbProgress
+
+(C) 2006-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Vaclav Petras <wenzeslaus gmail.com>
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import wx
+
+from core          import utils
+from core.gcmd     import GMessage, RunCommand
+from core.settings import UserSettings
+
+from grass.script  import core as grass
+
+class SbException:
+    """! Exception class used in SbManager and SbItems"""
+    def __init__(self, message):
+        self.message = message
+    def __str__(self):
+        return self.message
+
+
+class SbManager:
+    """!Statusbar manager for wx.Statusbar and SbItems.
+    
+    Statusbar manager manages items added by AddStatusbarItem method.
+    Provides progress bar (SbProgress) and choice (wx.Choice).
+    Items with position 0 are shown according to choice selection.
+    Only one item of the same class is supposed to be in statusbar.
+    Manager user have to create statusbar on his own, add items to manager
+    and call Update method to show particular widgets.
+    User settings (group = 'display', key = 'statusbarMode', subkey = 'selection')
+    are taken into account.
+    
+    @todo generalize access to UserSettings (specify group, etc.) 
+    @todo add GetMode method using name instead of index
+    """
+    def __init__(self, mapframe, statusbar):
+        """!Connects manager to statusbar
+        
+        Creates choice and progress bar.
+        """
+        self.mapFrame = mapframe
+        self.statusbar = statusbar
+        
+        self.choice = wx.Choice(self.statusbar, wx.ID_ANY)
+        
+        self.choice.Bind(wx.EVT_CHOICE, self.OnToggleStatus)
+        
+        self.statusbarItems = dict()
+        
+        self._postInitialized = False
+        
+        self.progressbar = SbProgress(self.mapFrame, self.statusbar)
+        
+        self._hiddenItems = {}
+    
+    def SetProperty(self, name, value):
+        """!Sets property represented by one of contained SbItems
+            
+        @param name name of SbItem (from name attribute)
+        @param value value to be set
+        """
+        self.statusbarItems[name].SetValue(value)
+        
+    def GetProperty(self, name):
+        """!Returns property represented by one of contained SbItems
+        
+        @param name name of SbItem (from name attribute)
+        """
+        return self.statusbarItems[name].GetValue()
+        
+    def HasProperty(self, name):
+        """!Checks whether property is represented by one of contained SbItems
+        
+        @param name name of SbItem (from name attribute)
+        
+        @returns True if particular SbItem is contained, False otherwise
+        """
+        if name in self.statusbarItems:
+            return True
+        return False
+    
+    def AddStatusbarItem(self, item):
+        """!Adds item to statusbar
+        
+        If item position is 0, item is managed by choice.
+        
+        @see AddStatusbarItemsByClass
+        """
+        self.statusbarItems[item.name] = item
+        if item.GetPosition() == 0:
+            self.choice.Append(item.label, clientData = item) #attrError?
+            
+    def AddStatusbarItemsByClass(self, itemClasses, **kwargs):
+        """!Adds items to statusbar
+
+        @param itemClasses list of classes of items to be add
+        @param kwargs SbItem constructor parameters
+        
+        @see AddStatusbarItem
+        """
+        for Item in itemClasses:
+            item = Item(**kwargs)
+            self.AddStatusbarItem(item)
+                      
+    def HideStatusbarChoiceItemsByClass(self, itemClasses):
+        """!Hides items showed in choice
+        
+        Hides items with position 0 (items showed in choice) by removing
+        them from choice.
+        
+        @param itemClasses list of classes of items to be hided
+        
+        @see ShowStatusbarChoiceItemsByClass
+        @todo consider adding similar function which would take item names
+        """
+        index = []
+        for itemClass in itemClasses:
+            for i in range(0, self.choice.GetCount() - 1):
+                item = self.choice.GetClientData(i)
+                if item.__class__ == itemClass:
+                    index.append(i)
+                    self._hiddenItems[i] = item
+        # must be sorted in reverse order to be removed correctly
+        for i in sorted(index, reverse = True):
+            self.choice.Delete(i)
+        
+    def ShowStatusbarChoiceItemsByClass(self, itemClasses):
+        """!Shows items showed in choice
+        
+        Shows items with position 0 (items showed in choice) by adding
+        them to choice.
+        Items are restored in their old positions.
+        
+        @param itemClasses list of classes of items to be showed
+        
+        @see HideStatusbarChoiceItemsByClass
+        """
+        # must be sorted to be inserted correctly
+        for pos in sorted(self._hiddenItems.keys()):
+            item = self._hiddenItems[pos]
+            if item.__class__ in itemClasses:
+                self.choice.Insert(item.label, pos, item)
+        
+    def ShowItem(self, itemName):
+        """!Invokes showing of particular item
+        
+        @see Update
+        """
+        self.statusbarItems[itemName].Show()
+        
+    def _postInit(self):
+        """!Post-initialization method
+        
+        It sets internal user settings,
+        set choice's selection (from user settings) and does reposition.
+        It needs choice filled by items.
+        it is called automatically.
+        """
+        UserSettings.Set(group = 'display',
+                         key = 'statusbarMode',
+                         subkey = 'choices',
+                         value = self.choice.GetItems(),
+                         internal = True)
+        
+        self.choice.SetSelection(UserSettings.Get(group = 'display',
+                                                  key = 'statusbarMode',
+                                                  subkey = 'selection')) 
+        self.Reposition()
+        
+        self._postInitialized = True
+        
+    def Update(self):
+        """!Updates statusbar
+
+        It always updates mask.
+        """
+        if not self._postInitialized:
+            self._postInit()
+        
+        for item in self.statusbarItems.values():
+            if item.GetPosition() == 0:
+                item.Hide()
+            else:
+                item.Update() # mask, render
+        
+        if self.choice.GetCount() > 0:
+            item = self.choice.GetClientData(self.choice.GetSelection())
+            item.Update()
+        
+    def Reposition(self):
+        """!Reposition items in statusbar
+        
+        Set positions to all items managed by statusbar manager.
+        It should not be necessary to call it manually.
+        """
+        
+        widgets = []
+        for item in self.statusbarItems.values():
+            widgets.append((item.GetPosition(), item.GetWidget()))
+            
+        widgets.append((1, self.choice))
+        widgets.append((0, self.progressbar.GetWidget()))
+                
+        for idx, win in widgets:
+            if not win:
+                continue
+            rect = self.statusbar.GetFieldRect(idx)
+            if idx == 0: # show region / mapscale / process bar
+                # -> size
+                wWin, hWin = win.GetBestSize()
+                if win == self.progressbar.GetWidget():
+                    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 == 2: # mask
+                    x += 5
+                    y += 4
+                elif idx == 3: # render
+                    x += 5
+            win.SetPosition((x, y))
+            win.SetSize((w, h))
+        
+    def GetProgressBar(self):
+        """!Returns progress bar"""
+        return self.progressbar
+    
+    def OnToggleStatus(self, event):
+        """!Toggle status text
+        """
+        self.Update()
+        
+    def SetMode(self, modeIndex):
+        """!Sets current mode
+        
+        Mode is usually driven by user through choice.
+        """
+        self.choice.SetSelection(modeIndex)
+    
+    def GetMode(self):
+        """!Returns current mode"""
+        return self.choice.GetSelection()
+
+class SbItem:
+    """!Base class for statusbar items.
+    
+    Each item represents functionality (or action) controlled by statusbar
+    and related to MapFrame.
+    One item is usually connected with one widget but it is not necessary.
+    Item can represent property (depends on manager).
+    Items are not widgets but can provide interface to them.
+    Items usually has requirements to MapFrame instance
+    (specified as MapFrame.methodname or MapWindow.methodname).
+    
+    @todo consider externalizing position (see SbProgress use in SbManager)
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        """!
+        
+        @param mapframe instance of class with MapFrame interface
+        @param statusbar statusbar instance (wx.Statusbar)
+        @param position item position in statusbar
+        
+        @todo rewrite Update also in derived classes to take in account item position
+        """
+        self.mapFrame = mapframe
+        self.statusbar = statusbar
+        self.position = position
+    
+    def Show(self):
+        """!Invokes showing of underlying widget.
+        
+        In derived classes it can do what is appropriate for it,
+        e.g. showing text on statusbar (only).
+        """
+        self.widget.Show()
+        
+    def Hide(self):
+        self.widget.Hide()
+        
+    def SetValue(self, value):
+        self.widget.SetValue(value)
+    
+    def GetValue(self):
+        return self.widget.GetValue()
+        
+    def GetPosition(self):
+        return self.position
+    
+    def GetWidget(self):
+        """!Returns underlaying winget.
+        
+        @return widget or None if doesn't exist
+        """
+        return self.widget
+    
+    def _update(self, longHelp):
+        """!Default implementation for Update method.
+        
+        @param longHelp True to enable long help (help from toolbars)
+        """
+        self.statusbar.SetStatusText("", 0)
+        self.Show()
+        self.mapFrame.StatusbarEnableLongHelp(longHelp)
+        
+    def Update(self):
+        """!Called when statusbar action is activated (e.g. through wx.Choice).
+        """
+        self._update(longHelp = False)
+
+class SbRender(SbItem):
+    """!Checkbox to enable and disable auto-rendering.
+    
+    Requires MapFrame.OnRender method.
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'render'
+        
+        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
+                                  label = _("Render"))
+        
+        self.widget.SetValue(UserSettings.Get(group = 'display',
+                                              key = 'autoRendering',
+                                              subkey = 'enabled'))
+        self.widget.Hide()
+        self.widget.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
+                                            
+        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleRender)
+        
+    def OnToggleRender(self, event):
+        # (other items should call self.mapFrame.IsAutoRendered())
+        if self.GetValue():
+            self.mapFrame.OnRender(None)
+
+    def Update(self):
+        self.Show()
+        
+class SbShowRegion(SbItem):
+    """!Checkbox to enable and disable showing of computational region.
+    
+    Requires MapFrame.OnRender, MapFrame.IsAutoRendered, MapFrame.GetWindow.
+    Expects that instance returned by MapFrame.GetWindow will handle
+    regionCoords attribute. 
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'region'
+        self.label = _("Show comp. extent")
+        
+        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
+                                  label = _("Show computational extent"))
+        
+        self.widget.SetValue(False)
+        self.widget.Hide()
+        self.widget.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).")))
+                                            
+        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion)
+    
+    def OnToggleShowRegion(self, event):
+        """!Shows/Hides extent (comp. region) in map canvas.
+        
+        Shows or hides according to checkbox value.
+        """
+        if self.widget.GetValue():
+            # show extent
+            self.mapFrame.GetWindow().regionCoords = []
+        elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
+            del self.mapFrame.GetWindow().regionCoords
+
+        # redraw map if auto-rendering is enabled
+        if self.mapFrame.IsAutoRendered():
+            self.mapFrame.OnRender(None)
+
+    def SetValue(self, value):
+        SbItem.SetValue(self, value)
+        if value:
+            self.mapFrame.GetWindow().regionCoords = []
+        elif hasattr(self.mapFrame.GetWindow(), 'regionCoords'):
+            del self.mapFrame.GetWindow().regionCoords
+            
+class SbAlignExtent(SbItem):
+    """!Checkbox to select zoom behavior.
+    
+    Used by BufferedWindow (through MapFrame property).
+    See tooltip for explanation.
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'alignExtent'
+        self.label = _("Display mode")
+        
+        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
+                                  label = _("Align region extent based on display size"))
+        
+        self.widget.SetValue(UserSettings.Get(group = 'display', key = 'alignExtent', subkey = 'enabled'))
+        self.widget.Hide()
+        self.widget.SetToolTip(wx.ToolTip (_("Align region extent based on display "
+                                             "size from center point. "
+                                             "Default value for new map displays can "
+                                             "be set up in 'User GUI settings' dialog.")))      
+        
+class SbResolution(SbItem):
+    """!Checkbox to select used display resolution.
+    
+    Requires MapFrame.OnRender method. 
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'resolution'
+        self.label = _("Display resolution")
+        
+        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
+                                  label = _("Constrain display resolution to computational settings"))
+        
+        self.widget.SetValue(UserSettings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
+        self.widget.Hide()
+        self.widget.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.")))
+                                            
+        self.widget.Bind(wx.EVT_CHECKBOX, self.OnToggleUpdateMap)
+        
+    def OnToggleUpdateMap(self, event):
+        """!Update display when toggle display mode
+        """
+        # redraw map if auto-rendering is enabled
+        if self.mapFrame.IsAutoRendered():
+            self.mapFrame.OnRender(None)
+
+
+class SbMapScale(SbItem):
+    """!Editable combobox to get/set current map scale.
+    
+    Requires MapFrame.GetMapScale, MapFrame.SetMapScale
+    and MapFrame.GetWindow (and GetWindow().UpdateMap()).
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'mapscale'
+        self.label = _("Map scale")
+        
+        self.widget = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
+                                                    style = wx.TE_PROCESS_ENTER,
+                                                    size = (150, -1))
+        
+        self.widget.SetItems(['1:1000',
+                              '1:5000',
+                              '1:10000',
+                              '1:25000',
+                              '1:50000',
+                              '1:100000',
+                              '1:1000000'])
+        self.widget.Hide()
+        self.widget.SetToolTip(wx.ToolTip (_("As everyone's monitors and resolutions "
+                                            "are set differently these values are not "
+                                            "true map scales, but should get you into "
+                                            "the right neighborhood.")))
+                                            
+        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale)
+        self.widget.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale)
+        
+        self.lastMapScale = None
+
+    def Update(self):
+        scale = self.mapFrame.GetMapScale()
+        self.statusbar.SetStatusText("")
+        try:
+            self.SetValue("1:%ld" % (scale + 0.5))
+        except TypeError:
+            pass # FIXME, why this should happen?
+        
+        self.lastMapScale = scale
+        self.Show()
+
+        # disable long help
+        self.mapFrame.StatusbarEnableLongHelp(False)
+
+    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.SetValue('1:%ld' % int(self.lastMapScale))
+            return
+        
+        self.mapFrame.SetMapScale(value)
+        
+        # redraw a map
+        self.mapFrame.GetWindow().UpdateMap()
+        self.GetWidget().SetFocus()
+        
+        
+class SbGoTo(SbItem):
+    """!Textctrl to set coordinates which to focus on.
+    
+    Requires MapFrame.GetWindow, MapWindow.GoTo method.
+    """
+    
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'goto'
+        self.label = _("Go to")
+        
+        self.widget = wx.TextCtrl(parent = self.statusbar, id = wx.ID_ANY,
+                                                value = "", style = wx.TE_PROCESS_ENTER,
+                                                size = (300, -1))
+        
+        self.widget.Hide()
+        
+        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo)
+    
+    def ReprojectENToMap(self, e, n, useDefinedProjection):
+        """!Reproject east, north from user defined projection
+        
+        @param e,n coordinate (for DMS string, else float or string)
+        @param useDefinedProjection projection defined by user in settings dialog
+        
+        @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
+        """
+        if useDefinedProjection:
+            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
+            if not settings:
+                raise SbException(_("Projection not defined (check the settings)"))
+            else:
+                # reproject values
+                projIn = settings
+                projOut = RunCommand('g.proj',
+                                     flags = 'jf',
+                                     read = True)
+                proj = projIn.split(' ')[0].split('=')[1]
+                if proj in ('ll', 'latlong', 'longlat'):
+                    e, n = utils.DMS2Deg(e, n)
+                    proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
+                                                              projIn = projIn,
+                                                              projOut = projOut, flags = 'd')
+                    e, n = coord1
+                else:
+                    e, n = float(e), float(n)
+                    proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
+                                                              projIn = projIn,
+                                                              projOut = projOut, flags = 'd')
+                    e, n = coord1
+        elif self.mapFrame.GetMap().projinfo['proj'] == 'll':
+            e, n = utils.DMS2Deg(e, n)
+        else: 
+            e, n = float(e), float(n)
+        return e, n
+
+    def OnGoTo(self, event):
+        """!Go to position
+        """
+        try:
+            e, n = self.GetValue().split(';')
+            e, n = self.ReprojectENToMap(e, n, self.mapFrame.GetProperty('projection'))
+            self.mapFrame.GetWindow().GoTo(e, n)
+            self.widget.SetFocus()
+        except ValueError:
+            # FIXME: move this code to MapWindow/BufferedWindow/MapFrame
+            region = self.mapFrame.GetMap().GetCurrentRegion()
+            precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                                             subkey = 'precision'))
+            format = UserSettings.Get(group = 'projection', key = 'format',
+                                      subkey = 'll')
+            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
+                    self.SetValue("%s" % utils.Deg2DMS(region['center_easting'], 
+                                                                            region['center_northing'],
+                                                                            precision = precision))
+            else:
+                self.SetValue("%.*f; %.*f" % \
+                               (precision, region['center_easting'],
+                                precision, region['center_northing']))
+        except SbException, e:
+            # FIXME: this may be useless since statusbar update checks user defined projection and this exception raises when user def proj does not exists
+            self.statusbar.SetStatusText(str(e), 0)
+
+    def GetCenterString(self, map):
+        """!Get current map center in appropriate format"""
+        region = map.GetCurrentRegion()
+        precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                                         subkey = 'precision'))
+        format = UserSettings.Get(group = 'projection', key = 'format',
+                                  subkey = 'll')
+        projection = UserSettings.Get(group='projection', key='statusbar', subkey='proj4')
+        
+        if self.mapFrame.GetProperty('projection'):
+            if not projection:
+                raise SbException(_("Projection not defined (check the settings)"))
+            else:
+                proj, coord  = utils.ReprojectCoordinates(coord = (region['center_easting'],
+                                                                   region['center_northing']),
+                                                          projOut = projection,
+                                                          flags = 'd')
+                if coord:
+                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
+                        return "%s" % utils.Deg2DMS(coord[0],
+                                                                                coord[1],
+                                                                                precision = precision)
+                    else:
+                        return "%.*f; %.*f" % (precision, coord[0], precision, coord[1])
+                else:
+                    raise SbException(_("Error in projection (check the settings)"))
+        else:
+            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
+                return "%s" % utils.Deg2DMS(region['center_easting'], region['center_northing'],
+                                                                      precision = precision)
+            else:
+                return "%.*f; %.*f" % (precision, region['center_easting'], precision, region['center_northing'])
+
+
+    def SetCenter(self):
+        """!Set current map center as item value"""
+        center = self.GetCenterString(self.mapFrame.GetMap())
+        self.SetValue(center)
+        
+    def Update(self):
+        self.statusbar.SetStatusText("")
+        
+        try:
+            self.SetCenter()
+            self.Show()
+        except SbException, e:
+            self.statusbar.SetStatusText(str(e), 0)
+                        
+        # disable long help
+        self.mapFrame.StatusbarEnableLongHelp(False)
+        
+
+class SbProjection(SbItem):
+    """!Checkbox to enable user defined projection (can be set in settings)"""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'projection'
+        self.label = _("Projection")
+        
+        self.defaultLabel = _("Use defined projection")
+        
+        self.widget = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
+                                  label = self.defaultLabel)
+        
+        self.widget.SetValue(False)
+        
+        # necessary?
+        size = self.widget.GetSize()
+        self.widget.SetMinSize((size[0] + 150, size[1]))
+        
+        self.widget.Hide()
+        self.widget.SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
+                                             "in the statusbar. Projection can be "
+                                             "defined in GUI preferences dialog "
+                                             "(tab 'Projection')")))
+                                            
+    def Update(self):
+        self.statusbar.SetStatusText("")
+        epsg = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')
+        if epsg:
+            label = '%s (EPSG: %s)' % (self.defaultLabel, epsg)
+            self.widget.SetLabel(label)
+        else:
+            self.widget.SetLabel(self.defaultLabel)
+        self.Show()
+        
+        # disable long help
+        self.mapFrame.StatusbarEnableLongHelp(False)
+        
+
+class SbMask(SbItem):
+    """!StaticText to show whether mask is activated."""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'mask'
+        
+        self.widget = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY, label = _('MASK'))
+        self.widget.SetForegroundColour(wx.Colour(255, 0, 0))
+        self.widget.Hide()
+        
+    def Update(self):
+        if grass.find_file(name = 'MASK', element = 'cell')['name']:
+            self.Show()
+        else:
+            self.Hide()
+        
+class SbTextItem(SbItem):
+    """!Base class for items without widgets.
+    
+    Only sets statusbar text.
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        
+        self.text = None
+        
+    def Show(self):
+        self.statusbar.SetStatusText(self.GetValue(), self.position)
+        
+    def Hide(self):
+        self.statusbar.SetStatusText("", self.position)
+        
+    def SetValue(self, value):
+        self.text = value
+    
+    def GetValue(self):
+        return self.text
+            
+    def GetWidget(self):
+        return None
+    
+    def Update(self):
+        self._update(longHelp = True)
+
+class SbDisplayGeometry(SbTextItem):
+    """!Show current display resolution."""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbTextItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'displayGeometry'
+        self.label = _("Display geometry")
+        
+    def Show(self):
+        region = self.mapFrame.GetMap().GetCurrentRegion()
+        self.SetValue("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
+                     (region["rows"], region["cols"],
+                      region["nsres"], region["ewres"]))
+        SbTextItem.Show(self)
+
+class SbCoordinates(SbTextItem):
+    """!Show map coordinates when mouse moves.
+    
+    Requires MapWindow.GetLastEN method."""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbTextItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'coordinates'
+        self.label = _("Coordinates")
+        
+    def Show(self):
+        precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                             subkey = 'precision'))
+        format = UserSettings.Get(group = 'projection', key = 'format',
+                                       subkey = 'll')
+        projection = self.mapFrame.GetProperty('projection')
+        try:
+            e, n = self.mapFrame.GetWindow().GetLastEN()
+            self.SetValue(self.ReprojectENFromMap(e, n, projection, precision, format))
+        except SbException, e:
+            self.SetValue(e)
+        except TypeError, e:
+            self.SetValue("")
+        except AttributeError:
+            self.SetValue("") # during initialization MapFrame has no MapWindow
+        SbTextItem.Show(self)
+        
+    def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format):
+        """!Reproject east, north to user defined projection.
+        
+        @param e,n coordinate
+        
+        @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings
+        """
+        if useDefinedProjection:
+            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
+            if not settings:
+                raise SbException(_("Projection not defined (check the settings)"))
+            else:
+                # reproject values
+                proj, coord  = utils.ReprojectCoordinates(coord = (e, n),
+                                                          projOut = settings,
+                                                          flags = 'd')
+                if coord:
+                    e, n = coord
+                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
+                        return utils.Deg2DMS(e, n, precision = precision)
+                    else:
+                        return "%.*f; %.*f" % (precision, e, precision, n)
+                else:
+                    raise SbException(_("Error in projection (check the settings)"))
+        else:
+            if self.mapFrame.GetMap().projinfo['proj'] == 'll' and format == 'DMS':
+                return utils.Deg2DMS(e, n, precision = precision)
+            else:
+                return "%.*f; %.*f" % (precision, e, precision, n)
+        
+class SbRegionExtent(SbTextItem):
+    """!Shows current display region"""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbTextItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'displayRegion'
+        self.label = _("Extent")
+        
+    def Show(self):
+        precision = int(UserSettings.Get(group = 'projection', key = 'format',
+                             subkey = 'precision'))
+        format = UserSettings.Get(group = 'projection', key = 'format',
+                                       subkey = 'll')
+        projection = self.mapFrame.GetProperty('projection')        
+        region = self._getRegion()
+        try:
+            regionReprojected = self.ReprojectRegionFromMap(region, projection, precision, format)
+            self.SetValue(regionReprojected)
+        except SbException, e:
+            self.SetValue(e)
+        SbTextItem.Show(self)
+    
+    def _getRegion(self):
+        """!Get current display region"""
+        return self.mapFrame.GetMap().GetCurrentRegion() # display region
+        
+    def _formatRegion(self, w, e, s, n, nsres, ewres, precision = None):
+        """!Format display region string for statusbar
+
+        @param nsres,ewres unused
+        """
+        if precision is not None:
+            return "%.*f - %.*f, %.*f - %.*f" % (precision, w, precision, e,
+                                                 precision, s, precision, n)
+        else:
+            return "%s - %s, %s - %s" % (w, e, s, n)
+         
+           
+    def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format):
+        """!Reproject region values
+        
+        @todo reorganize this method to remove code useful only for derived class SbCompRegionExtent
+        """
+        if useDefinedProjection:
+            settings = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4')
+            
+            if not settings:
+                raise SbException(_("Projection not defined (check the settings)"))
+            else:
+                projOut = settings
+                proj, coord1 = utils.ReprojectCoordinates(coord = (region["w"], region["s"]),
+                                                          projOut = projOut, flags = 'd')
+                proj, coord2 = utils.ReprojectCoordinates(coord = (region["e"], region["n"]),
+                                                          projOut = projOut, flags = 'd')
+                # useless, used in derived class
+                proj, coord3 = utils.ReprojectCoordinates(coord = (0.0, 0.0),
+                                                          projOut = projOut, flags = 'd')
+                proj, coord4 = utils.ReprojectCoordinates(coord = (region["ewres"], region["nsres"]),
+                                                          projOut = projOut, flags = 'd')
+                if coord1 and coord2:
+                    if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
+                        w, s = utils.Deg2DMS(coord1[0], coord1[1], string = False,
+                                             precision = precision)
+                        e, n = utils.Deg2DMS(coord2[0], coord2[1], string = False,
+                                             precision = precision)
+                        ewres, nsres = utils.Deg2DMS(abs(coord3[0]) - abs(coord4[0]),
+                                                         abs(coord3[1]) - abs(coord4[1]),
+                                                         string = False, hemisphere = False,
+                                                         precision = precision)
+                        return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
+                    else:
+                        w, s = coord1
+                        e, n = coord2
+                        ewres, nsres = coord3
+                        return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
+                                                  nsres = nsres, precision = precision)
+                else:
+                    raise SbException(_("Error in projection (check the settings)"))
+                
+        else:
+            if self.mapFrame.GetMap().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)
+                ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
+                                             string = False, precision = precision)
+                return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres, nsres = nsres)
+            else:
+                w, s = region["w"], region["s"]
+                e, n = region["e"], region["n"]
+                ewres, nsres = region['ewres'], region['nsres']
+                return self._formatRegion(w = w, s = s, e = e, n = n, ewres = ewres,
+                                          nsres = nsres, precision = precision)
+                                
+                                
+class SbCompRegionExtent(SbRegionExtent):
+    """!Shows computational region."""
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbRegionExtent.__init__(self, mapframe, statusbar, position)
+        self.name = 'computationalRegion'
+        self.label = _("Comp. region")
+        
+    def _formatRegion(self, w, e, s, n, ewres, nsres, precision = None):
+        """!Format computational region string for statusbar"""
+        if precision is not None:
+            return "%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" % (precision, w, precision, e,
+                                                              precision, s, precision, n,
+                                                              precision, ewres, precision, nsres)
+        else:
+            return "%s - %s, %s - %s (%s, %s)" % (w, e, s, n, ewres, nsres)
+        
+    def _getRegion(self):
+        """!Returns computational region."""
+        return self.mapFrame.GetMap().GetRegion() # computational region
+        
+        
+class SbProgress(SbItem):
+    """!General progress bar to show progress.
+    
+    Underlaying widget is wx.Gauge.
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'progress'
+
+        # on-render gauge
+        self.widget = wx.Gauge(parent = self.statusbar, id = wx.ID_ANY,
+                                      range = 0, style = wx.GA_HORIZONTAL)
+        self.widget.Hide()
+        
+    def GetRange(self):
+        """!Returns progress range."""
+        return self.widget.GetRange()
+    
+    def SetRange(self, range):
+        """!Sets progress range."""
+        self.widget.SetRange(range)
+    
+
+class SbGoToGCP(SbItem):
+    """!SpinCtrl to select GCP to focus on
+    
+    Requires MapFrame.GetSrcWindow, MapFrame.GetTgtWindow, MapFrame.GetListCtrl,
+    MapFrame.GetMapCoordList.
+    """
+    
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'gotoGCP'
+        self.label = _("Go to GCP No.")
+
+        self.widget = wx.SpinCtrl(parent = self.statusbar, id = wx.ID_ANY,
+                                                value = "", min = 0)
+        self.widget.Hide()
+        
+        self.widget.Bind(wx.EVT_TEXT_ENTER, self.OnGoToGCP)
+        self.widget.Bind(wx.EVT_SPINCTRL, self.OnGoToGCP)
+    
+    def OnGoToGCP(self, event):
+        """!Zooms to given GCP."""
+        GCPNo = self.GetValue()
+        mapCoords = self.mapFrame.GetMapCoordList()
+        
+        if GCPNo < 0 or GCPNo > len(mapCoords): # always false, spin checks it
+            GMessage(parent=self,
+                     message="%s 1 - %s." % (_("Valid Range:"),
+                                             len(mapCoords)))
+            return
+
+        if GCPNo == 0:
+            return
+            
+        listCtrl = self.mapFrame.GetListCtrl()
+        
+        listCtrl.selectedkey = GCPNo
+        listCtrl.selected = listCtrl.FindItemData(-1, GCPNo)
+        listCtrl.render = False
+        listCtrl.SetItemState(listCtrl.selected,
+                          wx.LIST_STATE_SELECTED,
+                          wx.LIST_STATE_SELECTED)
+        listCtrl.render = True
+        
+        srcWin = self.mapFrame.GetSrcWindow()
+        tgtWin = self.mapFrame.GetTgtWindow()
+        
+        # Source MapWindow:
+        begin = (mapCoords[GCPNo][1], mapCoords[GCPNo][2])
+        begin = srcWin.Cell2Pixel(begin)
+        end = begin
+        srcWin.Zoom(begin, end, 0)
+
+        # redraw map
+        srcWin.UpdateMap()
+
+        if self.mapFrame.GetShowTarget():
+            # Target MapWindow:
+            begin = (mapCoords[GCPNo][3], mapCoords[GCPNo][4])
+            begin = tgtWin.Cell2Pixel(begin)
+            end = begin
+            tgtWin.Zoom(begin, end, 0)
+
+            # redraw map
+            tgtWin.UpdateMap()
+
+        self.GetWidget().SetFocus()
+    
+    def Update(self):
+        self.statusbar.SetStatusText("")
+        max = self.mapFrame.GetListCtrl().GetItemCount()
+        if max < 1:
+            max = 1
+        self.widget.SetRange(0, max)
+        self.Show()
+                        
+        # disable long help
+        self.mapFrame.StatusbarEnableLongHelp(False)
+        
+class SbRMSError(SbTextItem):
+    """!Shows RMS error.
+    
+    Requires MapFrame.GetFwdError, MapFrame.GetBkwError.
+    """
+    def __init__(self, mapframe, statusbar, position = 0):
+        SbTextItem.__init__(self, mapframe, statusbar, position)
+        self.name = 'RMSError'
+        self.label = _("RMS error")
+        
+    def Show(self):
+        self.SetValue(_("Forward: %(forw)s, Backward: %(back)s") %
+                                   { 'forw' : self.mapFrame.GetFwdError(),
+                                     'back' : self.mapFrame.GetBkwError() })
+        SbTextItem.Show(self)


Property changes on: grass/trunk/gui/wxpython/mapdisp/statusbar.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/mapdisp/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,211 @@
+"""!
+ at package mapdisp.toolbars
+
+ at brief Map display frame - toolbars
+
+Classes:
+ - MapToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Jachym Cepicky
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import wx
+
+from gui_core.toolbars import BaseToolbar
+from icons.icon        import Icons
+from nviz.main         import haveNviz
+from vdigit.main       import haveVDigit
+
+class MapToolbar(BaseToolbar):
+    """!Map Display toolbar
+    """
+    def __init__(self, parent, mapcontent):
+        """!Map Display constructor
+
+        @param parent reference to MapFrame
+        @param mapcontent reference to render.Map (registred by MapFrame)
+        """
+        self.mapcontent = mapcontent # render.Map
+        BaseToolbar.__init__(self, parent = parent) # MapFrame
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # optional tools
+        choices = [ _('2D view'), ]
+        self.toolId = { '2d' : 0 }
+        if self.parent.GetLayerManager():
+            log = self.parent.GetLayerManager().GetLogWindow()
+        
+        if haveNviz:
+            choices.append(_('3D view'))
+            self.toolId['3d'] = 1
+        else:
+            from nviz.main import errorMsg
+            log.WriteCmdLog(_('3D view mode not available'))
+            log.WriteWarning(_('Reason: %s') % str(errorMsg))
+            log.WriteLog(_('Note that the wxGUI\'s 3D view mode is currently disabled '
+                           'on MS Windows (hopefully this will be fixed soon). '
+                           'Please keep an eye out for updated versions of GRASS. '
+                           'In the meantime you can use "NVIZ" from the File menu.'), wrap = 60)
+            
+            self.toolId['3d'] = -1
+
+        if haveVDigit:
+            choices.append(_('Digitize'))
+            if self.toolId['3d'] > -1:
+                self.toolId['vdigit'] = 2
+            else:
+                self.toolId['vdigit'] = 1
+        else:
+            from vdigit.main import errorMsg
+            log.WriteCmdLog(_('Vector digitizer not available'))
+            log.WriteWarning(_('Reason: %s') % errorMsg)
+            log.WriteLog(_('Note that the wxGUI\'s vector digitizer is currently disabled '
+                           '(hopefully this will be fixed soon). '
+                           'Please keep an eye out for updated versions of GRASS. '
+                           'In the meantime you can use "v.digit" from the Develop Vector menu.'), wrap = 60)
+            
+            self.toolId['vdigit'] = -1
+        
+        self.combo = wx.ComboBox(parent = self, id = wx.ID_ANY,
+                                 choices = choices,
+                                 style = wx.CB_READONLY, size = (110, -1))
+        self.combo.SetSelection(0)
+        
+        self.comboid = self.AddControl(self.combo)
+        self.parent.Bind(wx.EVT_COMBOBOX, self.OnSelectTool, self.comboid)
+        
+        # realize the toolbar
+        self.Realize()
+        
+        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
+        self.combo.Hide()
+        self.combo.Show()
+        
+        self.action = { 'id' : self.pointer }
+        self.defaultAction = { 'id' : self.pointer,
+                               'bind' : self.parent.OnPointer }
+        
+        self.OnTool(None)
+        
+        self.EnableTool(self.zoomback, False)
+        
+        self.FixSize(width = 90)
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['displayWindow']
+        return self._getToolbarData((('displaymap', icons['display'],
+                                      self.parent.OnDraw),
+                                     ('rendermap', icons['render'],
+                                      self.parent.OnRender),
+                                     ('erase', icons['erase'],
+                                      self.parent.OnErase),
+                                     (None, ),
+                                     ('pointer', icons['pointer'],
+                                      self.parent.OnPointer,
+                                      wx.ITEM_CHECK),
+                                     ('query', icons['query'],
+                                      self.parent.OnQuery,
+                                      wx.ITEM_CHECK),
+                                     ('pan', icons['pan'],
+                                      self.parent.OnPan,
+                                      wx.ITEM_CHECK),
+                                     ('zoomin', icons['zoomIn'],
+                                      self.parent.OnZoomIn,
+                                      wx.ITEM_CHECK),
+                                     ('zoomout', icons['zoomOut'],
+                                      self.parent.OnZoomOut,
+                                      wx.ITEM_CHECK),
+                                     ('zoomextent', icons['zoomExtent'],
+                                      self.parent.OnZoomToMap),
+                                     ('zoomback', icons['zoomBack'],
+                                      self.parent.OnZoomBack),
+                                     ('zoommenu', icons['zoomMenu'],
+                                      self.parent.OnZoomMenu),
+                                     (None, ),
+                                     ('analyze', icons['analyze'],
+                                      self.parent.OnAnalyze),
+                                     (None, ),
+                                     ('dec', icons['overlay'],
+                                      self.parent.OnDecoration),
+                                     (None, ),
+                                     ('savefile', icons['saveFile'],
+                                      self.parent.SaveToFile),
+                                     ('printmap', icons['print'],
+                                      self.parent.PrintMenu),
+                                     (None, ))
+                                    )
+    def InsertTool(self, data):
+        """!Insert tool to toolbar
+        
+        @param data toolbar data"""
+        data = self._getToolbarData(data)
+        for tool in data:
+            self.CreateTool(*tool)
+        self.Realize()
+        
+        self.parent._mgr.GetPane('mapToolbar').BestSize(self.GetBestSize())
+        self.parent._mgr.Update()
+        
+    def RemoveTool(self, tool):
+        """!Remove tool from toolbar
+        
+        @param tool tool id"""
+        self.DeleteTool(tool)
+        
+        self.parent._mgr.GetPane('mapToolbar').BestSize(self.GetBestSize())
+        self.parent._mgr.Update()
+        
+    def ChangeToolsDesc(self, mode2d):
+        """!Change description of zoom tools for 2D/3D view"""
+        if mode2d:
+            set = 'displayWindow'
+        else:
+            set = 'nviz'
+        for i, data in enumerate(self._data):
+            for tool, toolname in (('zoomin', 'zoomIn'),('zoomout', 'zoomOut')):
+                if data[0] == tool:
+                    tmp = list(data)
+                    tmp[4] = Icons[set][toolname].GetDesc()
+                    self._data[i] = tuple(tmp)
+                
+    def OnSelectTool(self, event):
+        """!Select / enable tool available in tools list
+        """
+        tool =  event.GetSelection()
+        
+        if tool == self.toolId['2d']:
+            self.ExitToolbars()
+            self.Enable2D(True)
+            self.ChangeToolsDesc(mode2d = True)            
+        
+        elif tool == self.toolId['3d'] and \
+                not (self.parent.MapWindow3D and self.parent.IsPaneShown('3d')):
+            self.ExitToolbars()
+            self.parent.AddNviz()
+            
+        elif tool == self.toolId['vdigit'] and \
+                not self.parent.GetToolbar('vdigit'):
+            self.ExitToolbars()
+            self.parent.AddToolbar("vdigit")
+            self.parent.MapWindow.SetFocus()
+        
+    def ExitToolbars(self):
+        if self.parent.GetToolbar('vdigit'):
+            self.parent.toolbars['vdigit'].OnExit()
+        if self.parent.GetLayerManager().IsPaneShown('toolbarNviz'):
+            self.parent.RemoveNviz()
+        
+    def Enable2D(self, enabled):
+        """!Enable/Disable 2D display mode specific tools"""
+        for tool in (self.zoommenu,
+                     self.analyze,
+                     self.printmap):
+            self.EnableTool(tool, enabled)


Property changes on: grass/trunk/gui/wxpython/mapdisp/toolbars.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/modules/colorrules.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/colorrules.py)
===================================================================
--- grass/trunk/gui/wxpython/modules/colorrules.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/modules/colorrules.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1840 @@
+"""
+ at package module.colorrules
+
+ at brief Dialog for interactive management of raster/vector color tables
+and color rules.
+
+Classes:
+ - RulesPanel
+ - ColorTable
+ - RasterColorTable
+ - VectorColorTable
+ - ThematicVectorTable
+ - BuferedWindow
+
+(C) 2008, 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Martin Landa <landa.martin gmail.com> (various updates)
+ at author Anna Kratochvilova <kratochanna gmail.com> (split to base and derived classes)
+"""
+
+import os
+import shutil
+import copy
+import tempfile
+
+import wx
+import wx.lib.colourselect     as csel
+import wx.lib.scrolledpanel    as scrolled
+import wx.lib.filebrowsebutton as filebrowse
+
+import grass.script as grass
+
+from core             import globalvar
+from core             import utils
+from core.gcmd        import GMessage, RunCommand
+from gui_core.gselect import Select, LayerSelect, ColumnSelect, VectorDBInfo
+from core.render      import Map
+from core.forms       import GUI
+from core.debug       import Debug as Debug
+from core.settings    import UserSettings
+from nviz.mapwindow   import wxUpdateProperties
+
+class RulesPanel:
+    def __init__(self, parent, mapType, attributeType, properties, panelWidth = 180):
+        """!Create rules panel
+        
+        @param mapType raster/vector
+        @param attributeType color/size for choosing widget type
+        @param properties properties of classes derived from ColorTable
+        @param panelWidth width of scroll panel"""
+        
+        self.ruleslines = {}
+        self.mapType = mapType
+        self.attributeType = attributeType
+        self.properties = properties
+        self.parent = parent
+        self.panelWidth = panelWidth
+        
+        self.mainSizer = wx.FlexGridSizer(cols = 3, vgap = 6, hgap = 4)
+        # put small border at the top of panel
+        for i in range(3):
+            self.mainSizer.Add(item = wx.Size(3, 3))
+        
+        self.mainPanel = scrolled.ScrolledPanel(parent, id = wx.ID_ANY,
+                                          size = (self.panelWidth, 300),
+                                          style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+                
+        # (un)check all
+        self.checkAll = wx.CheckBox(parent, id = wx.ID_ANY, label = _("Check all"))
+        self.checkAll.SetValue(True)
+        # clear button
+        self.clearAll = wx.Button(parent, id = wx.ID_ANY, label = _("Clear all"))
+        #  determines how many rules should be added
+        self.numRules = wx.SpinCtrl(parent, id = wx.ID_ANY,
+                                    min = 1, max = 1e6)
+        # add rules
+        self.btnAdd = wx.Button(parent, id = wx.ID_ADD)
+        
+        self.btnAdd.Bind(wx.EVT_BUTTON, self.OnAddRules)
+        self.checkAll.Bind(wx.EVT_CHECKBOX, self.OnCheckAll)
+        self.clearAll.Bind(wx.EVT_BUTTON, self.OnClearAll)
+
+        self.mainPanel.SetSizer(self.mainSizer)
+        self.mainPanel.SetAutoLayout(True)
+        self.mainPanel.SetupScrolling()    
+    
+    def Clear(self):
+        """!Clear and widgets and delete information"""
+        self.ruleslines.clear()
+        self.mainSizer.Clear(deleteWindows=True)
+    
+    def OnCheckAll(self, event):
+        """!(Un)check all rules"""
+        check = event.GetInt()
+        for child in self.mainPanel.GetChildren():
+            if child.GetName() == 'enable':
+                child.SetValue(check)
+            else:
+                child.Enable(check)
+                
+    def OnClearAll(self, event):
+        """!Delete all widgets in panel"""
+        self.Clear()
+        
+    def OnAddRules(self, event):
+        """!Add rules button pressed"""
+        nrules = self.numRules.GetValue()
+        self.AddRules(nrules)
+        
+    def AddRules(self, nrules, start = False):
+        """!Add rules 
+        @param start set widgets (not append)"""
+       
+        snum = len(self.ruleslines.keys())
+        if start:
+            snum = 0
+        for num in range(snum, snum + nrules):
+            # enable
+            enable = wx.CheckBox(parent = self.mainPanel, id = num)
+            enable.SetValue(True)
+            enable.SetName('enable')
+            enable.Bind(wx.EVT_CHECKBOX, self.OnRuleEnable)
+            # value
+            txt_ctrl = wx.TextCtrl(parent = self.mainPanel, id = 1000 + num,
+                                   size = (80, -1),
+                                   style = wx.TE_NOHIDESEL)
+            if self.mapType == 'vector':
+                txt_ctrl.SetToolTipString(_("Enter vector attribute values"))
+            txt_ctrl.Bind(wx.EVT_TEXT, self.OnRuleValue)
+            txt_ctrl.SetName('source')
+            if self.attributeType == 'color':
+                # color
+                columnCtrl = csel.ColourSelect(self.mainPanel, id = 2000 + num,
+                                               size  =  globalvar.DIALOG_COLOR_SIZE)
+                columnCtrl.Bind(csel.EVT_COLOURSELECT, self.OnRuleColor)
+                columnCtrl.SetName('target')
+                if not start:
+                    self.ruleslines[enable.GetId()] = { 'value' : '',
+                                                        'color': "0:0:0" }
+            else:
+                # size or width
+                init = 2
+                if self.attributeType == 'size':
+                    init = 100
+                columnCtrl = wx.SpinCtrl(self.mainPanel, id = 2000 + num,
+                                         size = (50, -1), min = 1, max = 1e4,
+                                         initial = init)
+                columnCtrl.Bind(wx.EVT_SPINCTRL, self.OnRuleSize)
+                columnCtrl.Bind(wx.EVT_TEXT, self.OnRuleSize)
+                columnCtrl.SetName('target')
+                if not start:
+                    self.ruleslines[enable.GetId()] = { 'value' : '',
+                                                        self.attributeType: init }
+        
+            self.mainSizer.Add(item = enable, proportion = 0,
+                              flag = wx.ALIGN_CENTER_VERTICAL)
+            self.mainSizer.Add(item = txt_ctrl, proportion = 0,
+                              flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
+            self.mainSizer.Add(item = columnCtrl, proportion = 0,
+                              flag = wx.ALIGN_CENTER | wx.RIGHT, border = 10)
+        
+        self.mainPanel.Layout()
+        self.mainPanel.SetupScrolling(scroll_x = False)
+    
+    def OnRuleEnable(self, event):
+        """!Rule enabled/disabled"""
+        id = event.GetId()
+        
+        if event.IsChecked():
+            self.mainPanel.FindWindowById(id + 1000).Enable()
+            self.mainPanel.FindWindowById(id + 2000).Enable()
+            if self.mapType == 'vector' and not self.parent.GetParent().colorTable:
+                vals = []
+                vals.append(self.mainPanel.FindWindowById(id + 1000).GetValue())
+                try:
+                    vals.append(self.mainPanel.FindWindowById(id + 1 + 1000).GetValue())
+                except AttributeError:
+                    vals.append(None)
+                value = self.SQLConvert(vals)
+            else:
+                value = self.mainPanel.FindWindowById(id + 1000).GetValue()
+            color = self.mainPanel.FindWindowById(id + 2000).GetValue()
+            
+            if self.attributeType == 'color':
+            # color
+                color_str = str(color[0]) + ':' \
+                          + str(color[1]) + ':' \
+                          + str(color[2])
+                self.ruleslines[id] = {'value' : value,
+                                       'color' : color_str }
+                
+            else:
+            # size or width
+                self.ruleslines[id] = {'value' : value,
+                                       self.attributeType  : float(color) }
+        
+        else:
+            self.mainPanel.FindWindowById(id + 1000).Disable()
+            self.mainPanel.FindWindowById(id + 2000).Disable()
+            del self.ruleslines[id]
+        
+    def OnRuleColor(self, event):
+        """!Rule color changed"""
+        num = event.GetId()
+        
+        rgba_color = event.GetValue()
+        
+        rgb_string = str(rgba_color[0]) + ':' \
+                   + str(rgba_color[1]) + ':' \
+                   + str(rgba_color[2])
+        
+        self.ruleslines[num-2000]['color'] = rgb_string
+     
+    def OnRuleSize(self, event):
+        """!Rule size changed"""
+        num = event.GetId()
+        size = event.GetInt()
+        
+        self.ruleslines[num - 2000][self.attributeType] = size
+        
+    def OnRuleValue(self, event):
+        """!Rule value changed"""
+        num = event.GetId()
+        val = event.GetString().strip()
+        
+        if val == '':
+            return
+        try:
+            table = self.parent.colorTable
+        except AttributeError:
+            # due to scrollpanel in vector dialog
+            table = self.parent.GetParent().colorTable
+        if table:
+            self.SetRasterRule(num, val)
+        else:
+            self.SetVectorRule(num, val)
+
+    def SetRasterRule(self, num, val): 
+        """!Set raster rule"""       
+        self.ruleslines[num - 1000]['value'] = val
+
+    def SetVectorRule(self, num, val):
+        """!Set vector rule"""
+        vals = []
+        vals.append(val)
+        try:
+            vals.append(self.mainPanel.FindWindowById(num + 1).GetValue())
+        except AttributeError:
+            vals.append(None)
+        self.ruleslines[num - 1000]['value'] = self.SQLConvert(vals)
+            
+    def Enable(self, enable = True):
+        """!Enable/Disable all widgets"""
+        for child in self.mainPanel.GetChildren():
+            child.Enable(enable)
+        sql = True
+        self.LoadRulesline(sql)# todo
+        self.btnAdd.Enable(enable)
+        self.numRules.Enable(enable)
+        self.checkAll.Enable(enable)
+        self.clearAll.Enable(enable)
+        
+        
+    def LoadRules(self):
+        message = ""        
+        for item in range(len(self.ruleslines)):
+            try:
+                self.mainPanel.FindWindowById(item + 1000).SetValue(self.ruleslines[item]['value'])
+                r, g, b = (0, 0, 0) # default
+                if not self.ruleslines[item][self.attributeType]:
+                    if self.attributeType == 'color':
+                        self.ruleslines[item][self.attributeType] = '%d:%d:%d' % (r, g, b)
+                    elif self.attributeType == 'size':
+                        self.ruleslines[item][self.attributeType] = 100                
+                    elif self.attributeType == 'width':
+                        self.ruleslines[item][self.attributeType] = 2
+                    
+                if self.attributeType == 'color':
+                    try:
+                        r, g, b = map(int, self.ruleslines[item][self.attributeType].split(':'))
+                    except ValueError, e:
+                        message =  _("Bad color format. Use color format '0:0:0'")
+                    self.mainPanel.FindWindowById(item + 2000).SetValue((r, g, b))
+                else:
+                    value = float(self.ruleslines[item][self.attributeType])
+                    self.mainPanel.FindWindowById(item + 2000).SetValue(value)
+            except:
+                continue
+                
+        if message:
+            GMessage(parent = self.parent, message = message)
+            return False
+        
+        return True
+                
+    def SQLConvert(self, vals):
+        """!Prepare value for SQL query"""
+        if vals[0].isdigit():
+            sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
+            if vals[1]:
+                sqlrule += ' AND %s<%s' % (self.properties['sourceColumn'], vals[1])
+        else:
+            sqlrule = '%s=%s' % (self.properties['sourceColumn'], vals[0])
+        
+        return sqlrule  
+
+class ColorTable(wx.Frame):
+    def __init__(self, parent, title, id = wx.ID_ANY,
+                 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
+                 **kwargs):
+        """!Dialog for interactively entering rules for map management
+        commands
+
+        @param raster True to raster otherwise vector
+        @param nviz True if ColorTable is called from nviz thematic mapping
+        """
+        self.parent = parent # GMFrame
+        wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
+        
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        # instance of render.Map to be associated with display
+        self.Map  = Map() 
+        
+        # input map to change
+        self.inmap = ''
+        # reference to layer with preview
+        self.layer = None     
+        # layout
+        self._doLayout()
+        
+        # bindings
+        self.Bind(wx.EVT_BUTTON, self.OnHelp, self.btnHelp)
+        self.selectionInput.Bind(wx.EVT_TEXT, self.OnSelectionInput)
+        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
+        self.Bind(wx.EVT_BUTTON, self.OnApply, self.btnApply)
+        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
+        self.Bind(wx.EVT_CLOSE,  self.OnCloseWindow)
+       
+        self.Bind(wx.EVT_BUTTON, self.OnPreview, self.btnPreview)
+        
+    def _initLayer(self):
+        """!Set initial layer when opening dialog"""
+        # set map layer from layer tree, first selected,
+        # if not the right type, than select another
+        try:
+            sel = self.parent.curr_page.maptree.layer_selected
+            if sel and self.parent.curr_page.maptree.GetPyData(sel)[0]['type'] == self.mapType:
+                layer = sel
+            else:
+                layer = self.parent.curr_page.maptree.FindItemByData(key = 'type', value = self.mapType)
+        except:
+            layer = None
+        if layer:
+            mapLayer = self.parent.curr_page.maptree.GetPyData(layer)[0]['maplayer']
+            name = mapLayer.GetName()
+            type = mapLayer.GetType()
+            self.selectionInput.SetValue(name)
+            self.inmap = name
+    
+    def _createMapSelection(self, parent):
+        """!Create map selection part of dialog"""
+        # top controls
+        if self.mapType == 'raster':
+            maplabel = _('Select raster map:')
+        else:
+            maplabel = _('Select vector map:')
+        inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
+                                label = " %s " % maplabel)
+        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
+
+        self.selectionInput = Select(parent, id = wx.ID_ANY,
+                                     size = globalvar.DIALOG_GSELECT_SIZE,
+                                     type = self.mapType)
+        # layout
+        inputSizer.Add(item = self.selectionInput,
+                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
+        return inputSizer
+    
+    def _createFileSelection(self, parent):
+        """!Create file (open/save rules) selection part of dialog"""
+        inputBox = wx.StaticBox(parent, id = wx.ID_ANY,
+                                label = " %s " % _("Import or export color table:"))
+        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
+        
+        self.loadRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
+                                                     size = globalvar.DIALOG_GSELECT_SIZE,
+                                                     labelText = _('Load color table from file:'),
+                                                     dialogTitle = _('Choose file to load color table'),
+                                                     buttonText = _('Load'),
+                                                     toolTip = _("Type filename or click to choose "
+                                                                 "file and load color table"),
+                                                     startDirectory = os.getcwd(), fileMode = wx.OPEN,
+                                                     changeCallback = self.OnLoadRulesFile)
+        self.saveRules = filebrowse.FileBrowseButton(parent = parent, id = wx.ID_ANY, fileMask = '*',
+                                                     size = globalvar.DIALOG_GSELECT_SIZE,
+                                                     labelText = _('Save color table to file:'),
+                                                     dialogTitle = _('Choose file to save color table'),
+                                                     toolTip = _("Type filename or click to choose "
+                                                                 "file and save color table"),
+                                                     buttonText = _('Save'),
+                                                     startDirectory = os.getcwd(), fileMode = wx.SAVE,
+                                                     changeCallback = self.OnSaveRulesFile)
+        
+        default = wx.Button(parent = parent, id = wx.ID_ANY, label = _("Reload default table"))   
+        # layout
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(item = self.loadRules, proportion = 1,
+                  flag = wx.RIGHT | wx.EXPAND, border = 10)
+        sizer.Add(item = default, flag = wx.ALIGN_CENTER_VERTICAL)
+        inputSizer.Add(item = sizer,
+                       flag = wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 5)
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(item = self.saveRules, proportion = 1,
+                  flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+        inputSizer.Add(item = sizer, proportion = 1,
+                       flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        default.Bind(wx.EVT_BUTTON, self.OnLoadDefaultTable)
+        
+        if self.mapType == 'vector':
+            # parent is collapsible pane
+            parent.SetSizer(inputSizer)
+        
+        return inputSizer   
+         
+    def _createPreview(self, parent):
+        """!Create preview"""
+        # initialize preview display
+        self.InitDisplay()
+        self.preview = BufferedWindow(parent, id = wx.ID_ANY, size = (400, 300),
+                                      Map = self.Map)
+        self.preview.EraseMap()
+        
+    def _createButtons(self):
+        """!Create buttons for leaving dialog"""
+        self.btnHelp = wx.Button(parent = self, id = wx.ID_HELP)
+        self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+        self.btnApply = wx.Button(parent = self, id = wx.ID_APPLY) 
+        self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
+        
+        self.btnOK.SetDefault()
+        self.btnOK.Enable(False)
+        self.btnApply.Enable(False)
+        
+        # layout
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(wx.Size(-1, -1), proportion = 1)
+        btnSizer.Add(self.btnHelp,
+                     flag = wx.LEFT | wx.RIGHT, border = 5)
+        btnSizer.Add(self.btnCancel,
+                     flag = wx.LEFT | wx.RIGHT, border = 5)
+        btnSizer.Add(self.btnApply,
+                     flag = wx.LEFT | wx.RIGHT, border = 5)
+        btnSizer.Add(self.btnOK,
+                     flag = wx.LEFT | wx.RIGHT, border = 5)
+        
+        return btnSizer
+    
+    def _createBody(self, parent):
+        """!Create dialog body consisting of rules and preview"""
+        bodySizer =  wx.GridBagSizer(hgap = 5, vgap = 5)
+        bodySizer.AddGrowableRow(1)
+        bodySizer.AddGrowableCol(2)
+
+        row = 0
+        # label with range
+        self.cr_label = wx.StaticText(parent, id = wx.ID_ANY)
+        bodySizer.Add(item = self.cr_label, pos = (row, 0), span = (1, 3),
+                      flag = wx.ALL, border = 5)
+
+        row += 1
+        # color table
+        self.rulesPanel = RulesPanel(parent = parent, mapType = self.mapType,
+                                     attributeType = self.attributeType, properties = self.properties)
+        
+        bodySizer.Add(item = self.rulesPanel.mainPanel, pos = (row, 0),
+                      span = (1, 2), flag = wx.EXPAND)
+        # add two rules as default
+        self.rulesPanel.AddRules(2)
+        
+        # preview window
+        self._createPreview(parent = parent)
+        bodySizer.Add(item = self.preview, pos = (row, 2), flag = wx.EXPAND)
+        
+        row += 1
+        # add ckeck all and clear all
+        bodySizer.Add(item = self.rulesPanel.checkAll, flag = wx.ALIGN_CENTER_VERTICAL, 
+                      pos = (row, 0))
+        bodySizer.Add(item = self.rulesPanel.clearAll, pos = (row, 1))
+        
+        # preview button
+        self.btnPreview = wx.Button(parent, id = wx.ID_ANY,
+                                    label = _("Preview"))
+        bodySizer.Add(item = self.btnPreview, pos = (row, 2),
+                      flag = wx.ALIGN_RIGHT)
+        self.btnPreview.Enable(False)
+        self.btnPreview.SetToolTipString(_("Show preview of map "
+                                           "(current Map Display extent is used)."))
+        
+        row +=1
+        # add rules button and spin to sizer
+        bodySizer.Add(item = self.rulesPanel.numRules, pos = (row, 0),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        bodySizer.Add(item = self.rulesPanel.btnAdd, pos = (row, 1))
+        
+        return bodySizer    
+        
+    def InitDisplay(self):
+        """!Initialize preview display, set dimensions and region
+        """
+        self.width = self.Map.width = 400
+        self.height = self.Map.height = 300
+        self.Map.geom = self.width, self.height
+
+    def OnCloseWindow(self, event):
+        """!Window closed
+        """
+        self.OnCancel(event)
+          
+    def OnApply(self, event):
+        """!Apply selected color table
+        
+        @return True on success otherwise False
+        """
+        ret = self.CreateColorTable()
+        if not ret:
+            GMessage(parent = self, message = _("No valid color rules given."))
+        
+        if ret:
+            display = self.parent.GetLayerTree().GetMapDisplay()
+            if display and display.IsAutoRendered():
+                display.GetWindow().UpdateMap(render = True)
+        
+        return ret
+
+    def OnOK(self, event):
+        """!Apply selected color table and close the dialog"""
+        if self.OnApply(event):
+            self.OnCancel(event)
+    
+    def OnCancel(self, event):
+        """!Do not apply any changes, remove associated
+            rendered images and close the dialog"""
+        self.Map.Clean()
+        self.Destroy()
+        
+    def OnSaveRulesFile(self, event):
+        """!Save color table to file"""
+        path = event.GetString()
+        if not os.path.exists(path):
+            return
+        
+        rulestxt = ''   
+        for rule in self.rulesPanel.ruleslines.itervalues():
+            if 'value' not in rule:
+                continue
+            rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
+        if not rulestxt:
+            GMessage(message = _("Nothing to save."),
+                     parent = self)
+            return
+        
+        fd = open(path, 'w')
+        fd.write(rulestxt)
+        fd.close()            
+         
+    def OnLoadRulesFile(self, event):
+        """!Load color table from file"""
+        path = event.GetString()
+        if not os.path.exists(path):
+            return
+        
+        self.rulesPanel.Clear()
+        
+        file = open(path, 'r')
+        ctable = file.read()
+        self.ReadColorTable(ctable = ctable)
+        
+    def ReadColorTable(self, ctable):
+        """!Read color table
+        
+        @param table color table in format coming from r.colors.out"""
+        
+        rulesNumber = len(ctable.splitlines())
+        self.rulesPanel.AddRules(rulesNumber)
+        
+        minim = maxim = count = 0
+        for line in ctable.splitlines():
+            try:
+                value, color = map(lambda x: x.strip(), line.split(' '))
+            except ValueError:
+                GMessage(parent = self, message = _("Invalid color table format"))
+                self.rulesPanel.Clear()
+                return
+            
+            self.rulesPanel.ruleslines[count]['value'] = value
+            self.rulesPanel.ruleslines[count]['color'] = color
+            self.rulesPanel.mainPanel.FindWindowById(count + 1000).SetValue(value)
+            rgb = list()
+            for c in color.split(':'):
+                rgb.append(int(c))
+            self.rulesPanel.mainPanel.FindWindowById(count + 2000).SetColour(rgb)
+            # range
+            try:
+                if float(value) < minim:
+                    minim = float(value)
+                if float(value) > maxim:
+                    maxim = float(value)
+            except ValueError: # nv, default
+                pass
+            count += 1
+        
+        if self.mapType == 'vector':
+            # raster min, max is known from r.info
+            self.properties['min'], self.properties['max'] = minim, maxim
+            self.SetRangeLabel()
+            
+        self.OnPreview(tmp = True)  
+         
+    def OnLoadDefaultTable(self, event):
+        """!Load internal color table"""
+        self.LoadTable()
+        
+    def LoadTable(self, mapType = 'raster'):
+        """!Load current color table (using `r(v).colors.out`)
+        
+        @param mapType map type (raster or vector)"""
+        self.rulesPanel.Clear()
+
+        if mapType == 'raster':
+            cmd = ['r.colors.out',
+                   'read=True',
+                   'map=%s' % self.inmap,
+                   'rules=-']
+        else:
+            cmd = ['v.colors.out',
+                   'read=True',
+                   'map=%s' % self.inmap,
+                   'rules=-']
+            
+            if self.properties['sourceColumn'] and self.properties['sourceColumn'] != 'cat':
+                cmd.append('column=%s' % self.properties['sourceColumn'])
+            
+        cmd = utils.CmdToTuple(cmd)
+        
+        if self.inmap:
+            ctable = RunCommand(cmd[0], **cmd[1])
+        else:
+            self.OnPreview()
+            return
+        
+        self.ReadColorTable(ctable = ctable)     
+    
+    def CreateColorTable(self, tmp = False):
+        """!Creates color table
+
+        @return True on success
+        @return False on failure
+        """
+        rulestxt = ''
+        
+        for rule in self.rulesPanel.ruleslines.itervalues():
+            if 'value' not in rule: # skip empty rules
+                continue
+            
+            if rule['value'] not in ('nv', 'default') and \
+                    rule['value'][-1] != '%' and \
+                    not self._IsNumber(rule['value']):
+                GError(_("Invalid rule value '%s'. Unable to apply color table.") % rule['value'],
+                       parent = self)
+                return False
+            
+            rulestxt += rule['value'] + ' ' + rule['color'] + '\n'
+           
+        if not rulestxt:
+            return False
+        
+        gtemp = utils.GetTempfile()
+        output = open(gtemp, "w")
+        try:
+            output.write(rulestxt)
+        finally:
+            output.close()
+                
+        cmd = ['%s.colors' % self.mapType[0],#r.colors/v.colors
+                'map=%s' % self.inmap,
+                'rules=%s' % gtemp]
+        if self.mapType == 'vector' and self.properties['sourceColumn']\
+                                    and self.properties['sourceColumn'] != 'cat':
+            cmd.append('column=%s' % self.properties['sourceColumn'])
+        cmd = utils.CmdToTuple(cmd)
+        ret = RunCommand(cmd[0], **cmd[1])               
+        if ret != 0:
+            return False
+        
+        return True
+    
+    def DoPreview(self, ltype, cmdlist):
+        """!Update preview (based on computational region)"""
+        
+        if not self.layer:
+            self.layer = self.Map.AddLayer(type = ltype, name = 'preview', command = cmdlist,
+                                           l_active = True, l_hidden = False, l_opacity = 1.0,
+                                           l_render = False) 
+        else:
+            self.layer.SetCmd(cmdlist)
+        
+        # apply new color table and display preview
+        self.CreateColorTable(tmp = True)
+        self.preview.UpdatePreview()
+        
+    def RunHelp(self, cmd):
+        """!Show GRASS manual page"""
+        RunCommand('g.manual',
+                   quiet = True,
+                   parent = self,
+                   entry = cmd)
+        
+    def _IsNumber(self, s):
+        """!Check if 's' is a number"""
+        try:
+            float(s)
+            return True
+        except ValueError:
+            return False
+        
+
+class RasterColorTable(ColorTable):
+    def __init__(self, parent, **kwargs):
+        """!Dialog for interactively entering color rules for raster maps"""
+
+        self.mapType = 'raster'
+        self.attributeType = 'color' 
+        self.colorTable = True 
+        # raster properties
+        self.properties = {
+            # min cat in raster map
+            'min' : None,
+            # max cat in raster map
+            'max' : None,
+            }        
+        
+        ColorTable.__init__(self, parent,
+                            title = _('Create new color table for raster map'), **kwargs)
+        
+        self._initLayer()
+        
+        self.SetMinSize(self.GetSize()) 
+        self.CentreOnScreen()
+        self.Show()
+    
+    def _doLayout(self):
+        """!Do main layout"""
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        #
+        # map selection
+        #
+        mapSelection = self._createMapSelection(parent = self)
+        sizer.Add(item = mapSelection, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # manage extern tables
+        #
+        fileSelection = self._createFileSelection(parent = self)
+        sizer.Add(item = fileSelection, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # body & preview
+        #
+        bodySizer = self._createBody(parent = self)
+        sizer.Add(item = bodySizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # buttons
+        #
+        btnSizer = self._createButtons()
+        sizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
+                                       style = wx.LI_HORIZONTAL), proportion = 0,
+                                       flag = wx.EXPAND | wx.ALL, border = 5) 
+        
+        sizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
+        
+        self.SetSizer(sizer)
+        sizer.Layout()
+        sizer.Fit(self)
+        self.Layout()
+    
+    def OnSelectionInput(self, event):
+        """!Raster map selected"""
+        if event:
+            self.inmap = event.GetString()
+    
+        self.loadRules.SetValue('')
+        self.saveRules.SetValue('')
+        if self.inmap:
+            if not grass.find_file(name = self.inmap, element = 'cell')['file']:
+                self.inmap = None
+        
+        if not self.inmap:
+            self.btnPreview.Enable(False)
+            self.btnOK.Enable(False)
+            self.btnApply.Enable(False)
+            self.LoadTable()
+            return
+        
+        info = grass.raster_info(map = self.inmap)
+        
+        if info:
+            self.properties['min'] = info['min']
+            self.properties['max'] = info['max']
+            self.LoadTable()
+        else:
+            self.inmap = ''
+            self.properties['min'] = self.properties['max'] = None
+            self.btnPreview.Enable(False)
+            self.btnOK.Enable(False)
+            self.btnApply.Enable(False)
+            self.preview.EraseMap()
+            self.cr_label.SetLabel(_('Enter raster category values or percents'))
+            return
+        
+        if info['datatype'] == 'CELL':
+            mapRange = _('range')
+        else:
+            mapRange = _('fp range')
+        self.cr_label.SetLabel(_('Enter raster category values or percents (%(range)s = %(min)d-%(max)d)') %
+                                 { 'range' : mapRange,
+                                   'min' : self.properties['min'],
+                                   'max' : self.properties['max'] })                       
+            
+        self.btnPreview.Enable()
+        self.btnOK.Enable()
+        self.btnApply.Enable()
+            
+          
+    def OnPreview(self, tmp = True):
+        """!Update preview (based on computational region)"""
+        if not self.inmap:
+            self.preview.EraseMap()
+            return
+        
+        cmdlist = ['d.rast',
+                   'map=%s' % self.inmap]
+        ltype = 'raster'
+        
+        # find existing color table and copy to temp file
+        try:
+            name, mapset = self.inmap.split('@')
+        except ValueError:
+            name = self.inmap
+            mapset = grass.find_file(self.inmap, element = 'cell')['mapset']
+            if not mapset:
+                return
+        old_colrtable = None
+        if mapset == grass.gisenv()['MAPSET']:
+            old_colrtable = grass.find_file(name = name, element = 'colr')['file']
+        else:
+            old_colrtable = grass.find_file(name = name, element = 'colr2/' + mapset)['file']
+        
+        if old_colrtable:
+            colrtemp = utils.GetTempfile()
+            shutil.copyfile(old_colrtable, colrtemp)
+            
+        ColorTable.DoPreview(self, ltype, cmdlist)  
+        
+        # restore previous color table
+        if tmp:
+            if old_colrtable:
+                shutil.copyfile(colrtemp, old_colrtable)
+                os.remove(colrtemp)
+            else:
+                RunCommand('r.colors',
+                           parent = self,
+                           flags = 'r',
+                           map = self.inmap)
+        
+    def OnHelp(self, event):
+        """!Show GRASS manual page"""
+        cmd = 'r.colors'
+        ColorTable.RunHelp(self, cmd = cmd)
+    
+
+                      
+class VectorColorTable(ColorTable):
+    def __init__(self, parent, attributeType, **kwargs):
+        """!Dialog for interactively entering color rules for vector maps"""
+        # dialog attributes
+        self.mapType = 'vector'
+        self.attributeType = attributeType # color, size, width
+        # in version 7 v.colors used, otherwise color column only
+        self.version7 = int(grass.version()['version'].split('.')[0]) >= 7
+        self.colorTable = False
+        self.updateColumn = True
+        # vector properties
+        self.properties = {
+            # vector layer for attribute table to use for setting color
+            'layer' : 1, 
+            # vector attribute table used for setting color         
+            'table' : '',
+            # vector attribute column for assigning colors
+            'sourceColumn' : '', 
+            # vector attribute column to use for loading colors
+            'loadColumn' : '',
+            # vector attribute column to use for storing colors
+            'storeColumn' : '',    
+            # vector attribute column for temporary storing colors   
+            'tmpColumn' : 'tmp_0',
+            # min value of attribute column/vector color table
+            'min': None,
+            # max value of attribute column/vector color table            
+            'max': None
+            }     
+        self.columnsProp = {'color': {'name': 'GRASSRGB', 'type1': 'varchar(11)', 'type2': ['character']},
+                            'size' : {'name': 'GRASSSIZE', 'type1': 'integer', 'type2': ['integer']},
+                            'width': {'name': 'GRASSWIDTH', 'type1': 'integer', 'type2': ['integer']}}
+        ColorTable.__init__(self, parent = parent,
+                            title = _('Create new color rules for vector map'), **kwargs)
+        
+        # additional bindings for vector color management
+        self.Bind(wx.EVT_COMBOBOX, self.OnLayerSelection, self.layerSelect)
+        self.Bind(wx.EVT_COMBOBOX, self.OnSourceColumnSelection, self.sourceColumn)
+        self.Bind(wx.EVT_COMBOBOX, self.OnFromColSelection, self.fromColumn)
+        self.Bind(wx.EVT_COMBOBOX, self.OnToColSelection, self.toColumn)
+        self.Bind(wx.EVT_BUTTON, self.OnAddColumn, self.addColumn)
+        
+        self._initLayer()
+        if self.colorTable:
+            self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
+        else:
+            self.cr_label.SetLabel(_("Enter vector attribute values:"))
+        self.SetMinSize(self.GetSize()) 
+        self.CentreOnScreen()
+
+        self.SetSize((-1, 760))
+        self.Show()
+    
+    def _createVectorAttrb(self, parent):
+        """!Create part of dialog with layer/column selection"""
+        inputBox = wx.StaticBox(parent = parent, id = wx.ID_ANY,
+                                label = " %s " % _("Select vector columns"))
+        cb_vl_label = wx.StaticText(parent, id = wx.ID_ANY,
+                                             label = _('Layer:'))
+        cb_vc_label = wx.StaticText(parent, id = wx.ID_ANY,
+                                         label = _('Attribute column:'))
+                                        
+        if self.attributeType == 'color':
+            labels =  [_("Load color from column:"), _("Save color to column:")]
+        elif self.attributeType == 'size':
+            labels =  [_("Load size from column:"), _("Save size to column:")]
+        elif self.attributeType == 'width':
+            labels =  [_("Load width from column:"), _("Save width to column:")]
+            
+        if self.version7 and self.attributeType == 'color':
+            self.useColumn = wx.CheckBox(parent, id = wx.ID_ANY,
+                                  label = _("Use color column instead of color table:"))
+            self.useColumn.Bind(wx.EVT_CHECKBOX, self.OnCheckColumn)
+        
+        fromColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
+                                            label = labels[0])
+        toColumnLabel = wx.StaticText(parent, id = wx.ID_ANY,
+                                            label = labels[1])
+                                                
+        self.rgb_range_label = wx.StaticText(parent, id = wx.ID_ANY)
+        self.layerSelect = LayerSelect(parent)
+        self.sourceColumn = ColumnSelect(parent)
+        self.fromColumn = ColumnSelect(parent)
+        self.toColumn = ColumnSelect(parent)
+        self.addColumn = wx.Button(parent, id = wx.ID_ANY,
+                                             label = _('Add column'))
+        self.addColumn.SetToolTipString(_("Add GRASSRGB column to current attribute table."))
+        
+        # layout
+        inputSizer = wx.StaticBoxSizer(inputBox, wx.VERTICAL)
+        vSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        row = 0
+        vSizer.Add(cb_vl_label, pos = (row, 0),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.layerSelect,  pos = (row, 1),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1
+        vSizer.Add(cb_vc_label, pos = (row, 0),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.sourceColumn, pos = (row, 1),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.rgb_range_label, pos = (row, 2),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1   
+        if self.version7 and self.attributeType == 'color':
+            vSizer.Add(self.useColumn, pos = (row, 0), span = (1, 2),
+                       flag = wx.ALIGN_CENTER_VERTICAL)
+            row += 1
+            
+        vSizer.Add(fromColumnLabel, pos = (row, 0),
+                  flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.fromColumn, pos = (row, 1),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1
+        vSizer.Add(toColumnLabel, pos = (row, 0),
+                  flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.toColumn, pos = (row, 1),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        vSizer.Add(self.addColumn, pos = (row, 2),
+                   flag = wx.ALIGN_CENTER_VERTICAL)
+        inputSizer.Add(item = vSizer,
+                       flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border = 5)
+        self.colorColumnSizer = vSizer        
+        return inputSizer 
+       
+    def _doLayout(self):
+        """!Do main layout"""
+        scrollPanel = scrolled.ScrolledPanel(self, id = wx.ID_ANY, size = (650, 500),
+                                             style = wx.TAB_TRAVERSAL)
+        scrollPanel.SetupScrolling()
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        #
+        # map selection
+        #
+        mapSelection = self._createMapSelection(parent = scrollPanel)
+        sizer.Add(item = mapSelection, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # manage extern tables
+        #
+        if self.version7 and self.attributeType == 'color':
+            self.cp = wx.CollapsiblePane(scrollPanel, label = _("Import or export color table"),
+                                         winid = wx.ID_ANY,
+                                        style = wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)
+            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, self.cp)
+        
+            self._createFileSelection(parent = self.cp.GetPane())
+            sizer.Add(item = self.cp, proportion = 0,
+                      flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # set vector attributes
+        #
+        vectorAttrb = self._createVectorAttrb(parent = scrollPanel)
+        sizer.Add(item = vectorAttrb, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # body & preview
+        #
+        bodySizer = self._createBody(parent = scrollPanel)
+        sizer.Add(item = bodySizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        scrollPanel.SetSizer(sizer)
+        scrollPanel.Fit()        
+        
+        #
+        # buttons
+        #
+        btnSizer = self._createButtons()
+        
+        mainsizer = wx.BoxSizer(wx.VERTICAL)
+        mainsizer.Add(scrollPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        mainsizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
+                                       style = wx.LI_HORIZONTAL), proportion = 0,
+                                       flag = wx.EXPAND | wx.ALL, border = 5) 
+        mainsizer.Add(item = btnSizer, proportion = 0,
+                  flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
+        
+        self.SetSizer(mainsizer)
+        mainsizer.Layout()
+        mainsizer.Fit(self)     
+          
+    def OnPaneChanged(self, event = None):
+        # redo the layout
+        self.Layout()
+        # and also change the labels
+        if self.cp.IsExpanded():
+            self.cp.SetLabel('')
+        else:
+            self.cp.SetLabel(_("Import or export color table"))
+        
+    def CheckMapset(self):
+        """!Check if current vector is in current mapset"""
+        if grass.find_file(name = self.inmap,
+                           element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
+            return True
+        else:
+            return False 
+         
+    def NoConnection(self, vectorName):
+        dlg = wx.MessageDialog(parent = self,
+                                message = _("Database connection for vector map <%s> "
+                                            "is not defined in DB file.  Do you want to create and "
+                                            "connect new attribute table?") % vectorName,
+                                caption = _("No database connection defined"),
+                                style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
+        if dlg.ShowModal() == wx.ID_YES:
+            dlg.Destroy()
+            GUI(parent = self).ParseCommand(['v.db.addtable', 'map=' + self.inmap], 
+                                            completed = (self.CreateAttrTable, self.inmap, ''))
+        else:
+            dlg.Destroy()
+  
+    def OnCheckColumn(self, event):
+        """!Use color column instead of color table"""
+        if self.useColumn.GetValue():
+            self.properties['loadColumn'] = self.fromColumn.GetStringSelection()
+            self.properties['storeColumn'] = self.toColumn.GetStringSelection()
+            self.fromColumn.Enable(True)
+            self.toColumn.Enable(True)
+            self.colorTable = False
+            
+            if self.properties['loadColumn']:
+                self.LoadTable()
+            else:
+                self.rulesPanel.Clear()
+        else:
+            self.properties['loadColumn'] = ''
+            self.properties['storeColumn'] = ''
+            self.fromColumn.Enable(False)
+            self.toColumn.Enable(False)
+            self.colorTable = True
+            self.LoadTable()
+            
+    def EnableVectorAttributes(self, enable):
+        """!Enable/disable part of dialog connected with db"""
+        for child in self.colorColumnSizer.GetChildren():
+            child.GetWindow().Enable(enable)
+    
+    def DisableClearAll(self):
+        """!Enable, disable the whole dialog"""
+        self.rulesPanel.Clear()
+        self.EnableVectorAttributes(False)
+        self.btnPreview.Enable(False)
+        self.btnOK.Enable(False)
+        self.btnApply.Enable(False)
+        self.preview.EraseMap()
+        
+    def OnSelectionInput(self, event):
+        """!Vector map selected"""
+        if event:
+            if self.inmap:
+                # switch to another map -> delete temporary column
+                self.DeleteTemporaryColumn()
+            self.inmap = event.GetString()
+            
+        if self.version7 and self.attributeType == 'color': 
+            self.loadRules.SetValue('')
+            self.saveRules.SetValue('')
+        
+        if self.inmap:
+            if not grass.find_file(name = self.inmap, element = 'vector')['file']:
+                self.inmap = None
+        
+        self.UpdateDialog()
+       
+    def UpdateDialog(self):
+        """!Update dialog after map selection"""  
+        
+        if not self.inmap:
+            self.DisableClearAll()
+            return
+        
+        if not self.CheckMapset():
+            # v.colors doesn't need the map to be in current mapset
+            if not (self.version7 and self.attributeType == 'color'):
+                message = _("Selected map <%s> is not in current mapset <%s>. "
+                            "Attribute table cannot be edited.") % \
+                            (self.inmap, grass.gisenv()['MAPSET'])
+                wx.CallAfter(GMessage, parent = self, message = message)
+                self.DisableClearAll()
+                return
+                
+        # check for db connection
+        self.dbInfo = VectorDBInfo(self.inmap)
+        enable = True
+        if not len(self.dbInfo.layers): # no connection
+            if not (self.version7 and self.attributeType == 'color'): # otherwise it doesn't matter
+                wx.CallAfter(self.NoConnection, self.inmap)
+                enable = False
+            for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
+                combo.SetValue("")
+                combo.Clear()
+            for prop in ('sourceColumn', 'loadColumn', 'storeColumn'):
+                self.properties[prop] = ''
+            self.EnableVectorAttributes(False)
+        else: # db connection exist
+        # initialize layer selection combobox
+            self.EnableVectorAttributes(True)
+            self.layerSelect.InsertLayers(self.inmap)
+            # initialize attribute table for layer=1
+            self.properties['layer'] = self.layerSelect.GetString(0)
+            self.layerSelect.SetStringSelection(self.properties['layer'])
+            layer = int(self.properties['layer'])
+            self.properties['table'] = self.dbInfo.layers[layer]['table']
+            
+            if self.attributeType == 'color':
+                self.AddTemporaryColumn(type = 'varchar(11)')
+            else:
+                self.AddTemporaryColumn(type = 'integer')
+            
+            # initialize column selection comboboxes 
+            
+            self.OnLayerSelection(event = None)
+
+        if self.version7 and self.attributeType == 'color':
+            self.useColumn.SetValue(False)
+            self.OnCheckColumn(event = None) 
+            self.useColumn.Enable(self.CheckMapset())
+                    
+        self.LoadTable()
+            
+        self.btnPreview.Enable(enable)
+        self.btnOK.Enable(enable)
+        self.btnApply.Enable(enable)   
+    
+    def AddTemporaryColumn(self, type):
+        """!Add temporary column to not overwrite the original values,
+            need to be deleted when closing dialog and unloading map
+            
+            @param type type of column (e.g. vachar(11))"""
+        if not self.CheckMapset():
+            return
+        # because more than one dialog with the same map can be opened we must test column name and
+        # create another one
+        while self.properties['tmpColumn'] in self.dbInfo.GetTableDesc(self.properties['table']).keys():
+            name, idx = self.properties['tmpColumn'].split('_')
+            idx = int(idx)
+            idx += 1
+            self.properties['tmpColumn'] = name + '_' + str(idx)
+        
+        if self.version7:
+            modul = 'v.db.addcolumn'
+        else:
+            modul = 'v.db.addcol'
+        ret = RunCommand(modul,
+                         parent = self,
+                         map = self.inmap,
+                         layer = self.properties['layer'],
+                         column = '%s %s' % (self.properties['tmpColumn'], type))
+        
+    def DeleteTemporaryColumn(self):
+        """!Delete temporary column"""
+        if not self.CheckMapset():
+            return
+        
+        if self.inmap:
+            if self.version7:
+                modul = 'v.db.dropcolumn'
+            else:
+                modul = 'v.db.dropcol'
+            ret = RunCommand(modul,
+                             map = self.inmap,
+                             layer = self.properties['layer'],
+                             column = self.properties['tmpColumn'])
+        
+    def OnLayerSelection(self, event):
+        # reset choices in column selection comboboxes if layer changes
+        vlayer = int(self.layerSelect.GetStringSelection())
+        self.sourceColumn.InsertColumns(vector = self.inmap, layer = vlayer,
+                                        type = ['integer', 'double precision'], dbInfo = self.dbInfo,
+                                        excludeCols = ['tmpColumn'])
+        self.sourceColumn.SetStringSelection('cat')
+        self.properties['sourceColumn'] = self.sourceColumn.GetString(0)
+        
+        if self.attributeType == 'color':
+            type = ['character']
+        else:
+            type = ['integer']
+        self.fromColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
+                                      dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
+        self.toColumn.InsertColumns(vector = self.inmap, layer = vlayer, type = type,
+                                    dbInfo = self.dbInfo, excludeCols = ['tmpColumn'])
+        
+        found = self.fromColumn.FindString(self.columnsProp[self.attributeType]['name'])
+        if found != wx.NOT_FOUND:
+            self.fromColumn.SetSelection(found)
+            self.toColumn.SetSelection(found)
+            self.properties['loadColumn'] = self.fromColumn.GetString(found)
+            self.properties['storeColumn'] = self.toColumn.GetString(found)
+        else:
+            self.properties['loadColumn'] = ''
+            self.properties['storeColumn'] = ''
+        
+        if event:
+            self.LoadTable()
+        self.Update()
+        
+    def OnSourceColumnSelection(self, event):
+        self.properties['sourceColumn'] = event.GetString()
+        
+        self.LoadTable()
+    
+    def OnAddColumn(self, event):
+        """!Add GRASS(RGB,SIZE,WIDTH) column if it doesn't exist"""
+        if self.columnsProp[self.attributeType]['name'] not in self.fromColumn.GetItems():
+            if self.version7:
+                modul = 'v.db.addcolumn'
+            else:
+                modul = 'v.db.addcol'
+            ret = RunCommand(modul,
+                             map = self.inmap,
+                             layer = self.properties['layer'],
+                             columns = '%s %s' % (self.columnsProp[self.attributeType]['name'],
+                                                  self.columnsProp[self.attributeType]['type1']))
+            self.toColumn.InsertColumns(self.inmap, self.properties['layer'],
+                                        type = self.columnsProp[self.attributeType]['type2'])
+            self.toColumn.SetStringSelection(self.columnsProp[self.attributeType]['name'])
+            self.properties['storeColumn'] = self.toColumn.GetStringSelection()
+            
+            self.LoadTable()
+        else:
+            GMessage(parent = self,
+                     message = _("%s column already exists.") % \
+                         self.columnsProp[self.attributeType]['name'])
+                        
+    def CreateAttrTable(self, dcmd, layer, params, propwin):
+        """!Create attribute table"""
+        if dcmd:
+            cmd = utils.CmdToTuple(dcmd)
+            ret = RunCommand(cmd[0], **cmd[1])
+            if ret == 0:
+                self.OnSelectionInput(None)
+                return True
+            
+        for combo in (self.layerSelect, self.sourceColumn, self.fromColumn, self.toColumn):
+            combo.SetValue("")
+            combo.Disable()
+        return False    
+    
+    def LoadTable(self):
+        """!Load table"""
+        if self.colorTable:
+            ColorTable.LoadTable(self, mapType = 'vector')
+        else:
+            self.LoadRulesFromColumn()
+            
+    def LoadRulesFromColumn(self):
+        """!Load current column (GRASSRGB, size column)"""
+        
+        self.rulesPanel.Clear()
+        if not self.properties['sourceColumn']:
+            self.preview.EraseMap()
+            return
+        
+        busy = wx.BusyInfo(message = _("Please wait, loading data from attribute table..."),
+                           parent = self)
+        wx.Yield()
+        
+        columns = self.properties['sourceColumn']
+        if self.properties['loadColumn']:
+            columns += ',' + self.properties['loadColumn']
+            
+        if self.inmap:
+            outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
+            sep = '|'
+            ret = RunCommand('v.db.select',
+                             quiet = True,
+                             flags = 'c',
+                             map = self.inmap,
+                             layer = self.properties['layer'],
+                             columns = columns,
+                             fs = sep,
+                             stdout = outFile)
+        else:
+            self.preview.EraseMap()
+            busy.Destroy()
+            return
+        
+        outFile.seek(0)
+        i = 0
+        minim = maxim = 0.0
+        limit = 1000
+        
+        colvallist = []
+        readvals = False
+        
+        while True:
+            # os.linesep doesn't work here (MSYS)
+            record = outFile.readline().replace('\n', '')
+            if not record:
+                break
+            self.rulesPanel.ruleslines[i] = {}
+            
+            if not self.properties['loadColumn']:
+                col1 = record
+                col2 = None
+            else:
+                col1, col2 = record.split(sep)
+            
+            if float(col1) < minim:
+                minim = float(col1)
+            if float(col1) > maxim:
+                maxim = float(col1)
+
+                
+            # color rules list should only have unique values of col1, not all records
+            if col1 not in colvallist:                
+                self.rulesPanel.ruleslines[i]['value'] = col1
+                self.rulesPanel.ruleslines[i][self.attributeType] = col2
+
+                colvallist.append(col1)            
+                i += 1
+            
+            if i > limit and readvals == False:
+                dlg = wx.MessageDialog (parent = self, message = _(
+                                        "Number of loaded records reached %d, "
+                                        "displaying all the records will be time-consuming "
+                                        "and may lead to computer freezing, "
+                                        "do you still want to continue?") % i,
+                                        caption = _("Too many records"),
+                                        style  =  wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+                if dlg.ShowModal() == wx.ID_YES:
+                    readvals = True
+                    dlg.Destroy()
+                else:
+                    busy.Destroy()
+                    dlg.Destroy()
+                    self.updateColumn = False
+                    return
+            
+        self.rulesPanel.AddRules(i, start = True)
+        ret = self.rulesPanel.LoadRules()
+        
+        self.properties['min'], self.properties['max'] = minim, maxim
+        self.SetRangeLabel()
+        
+        if ret:
+            self.OnPreview()   
+        else:
+            self.rulesPanel.Clear()
+    
+        busy.Destroy()
+        
+    def SetRangeLabel(self):
+        """!Set labels with info about attribute column range"""
+        
+        if self.properties['sourceColumn']:
+            ctype = self.dbInfo.GetTableDesc(self.properties['table'])[self.properties['sourceColumn']]['ctype']
+        else:
+            ctype = int
+        
+        range = ''
+        if self.properties['min'] or self.properties['max']:
+            if ctype == float:
+                range = _("(range: %.1f to %.1f)") % (self.properties['min'], self.properties['max'])
+            elif ctype == int:
+                range = _("(range: %d to %d)") % (self.properties['min'], self.properties['max'])
+        if range:
+            if self.colorTable:
+                self.cr_label.SetLabel(_("Enter vector attribute values or percents %s:") % range)
+            else:
+                self.cr_label.SetLabel(_("Enter vector attribute values %s:") % range)
+        else:
+            if self.colorTable:
+                self.cr_label.SetLabel(_("Enter vector attribute values or percents:"))
+            else:
+                self.cr_label.SetLabel(_("Enter vector attribute values:"))
+                
+    def OnFromColSelection(self, event):
+        """!Selection in combobox (for loading values) changed"""
+        self.properties['loadColumn'] = event.GetString()
+        
+        self.LoadTable()
+    
+    def OnToColSelection(self, event):
+        """!Selection in combobox (for storing values) changed"""
+        self.properties['storeColumn'] = event.GetString()
+    
+    def OnPreview(self, event = None, tmp = True):
+        """!Update preview (based on computational region)"""
+        if self.colorTable:
+            self.OnTablePreview(tmp)
+        else:
+            self.OnColumnPreview() 
+                                 
+    def OnTablePreview(self, tmp):
+        """!Update preview (based on computational region)"""
+        if not self.inmap:
+            self.preview.EraseMap()
+            return
+        
+        ltype = 'vector'
+        cmdlist = ['d.vect',
+                   'map=%s' % self.inmap]
+        
+        # find existing color table and copy to temp file
+        try:
+            name, mapset = self.inmap.split('@')
+        except ValueError:
+            name = self.inmap
+            mapset = grass.find_file(self.inmap, element = 'cell')['mapset']
+            if not mapset:
+                return
+            
+        old_colrtable = None
+        if mapset == grass.gisenv()['MAPSET']:
+            old_colrtable = grass.find_file(name = 'colr', element = os.path.join('vector', name))['file']
+        else:
+            old_colrtable = grass.find_file(name = name, element = os.path.join('vcolr2', mapset))['file']
+            
+        if old_colrtable:
+            colrtemp = utils.GetTempfile()
+            shutil.copyfile(old_colrtable, colrtemp)
+            
+        ColorTable.DoPreview(self, ltype, cmdlist)  
+        
+        # restore previous color table
+        if tmp:
+            if old_colrtable:
+                shutil.copyfile(colrtemp, old_colrtable)
+                os.remove(colrtemp)
+            else:
+                RunCommand('v.colors',
+                           parent = self,
+                           flags = 'r',
+                           map = self.inmap)
+    def OnColumnPreview(self):
+        """!Update preview (based on computational region)"""
+        if not self.inmap or not self.properties['tmpColumn']:
+            self.preview.EraseMap()
+            return
+        
+        cmdlist = ['d.vect',
+                   'map=%s' % self.inmap,
+                   'type=point,line,boundary,area']
+                
+        if self.attributeType == 'color':
+            cmdlist.append('flags=a')
+            cmdlist.append('rgb_column=%s' % self.properties['tmpColumn'])
+        elif self.attributeType == 'size':
+            cmdlist.append('size_column=%s' % self.properties['tmpColumn'])
+        elif self.attributeType == 'width':
+            cmdlist.append('width_column=%s' % self.properties['tmpColumn'])
+            
+        ltype = 'vector'
+        
+        ColorTable.DoPreview(self, ltype, cmdlist)
+        
+    def OnHelp(self, event):
+        """!Show GRASS manual page"""
+        cmd = 'v.colors'
+        ColorTable.RunHelp(self, cmd = cmd)
+        
+    def UseAttrColumn(self, useAttrColumn):
+        """!Find layers and apply the changes in d.vect command"""
+        layers = self.parent.curr_page.maptree.FindItemByData(key = 'name', value = self.inmap)
+        if not layers:
+            return
+        for layer in layers:
+            if self.parent.curr_page.maptree.GetPyData(layer)[0]['type'] != 'vector':
+                continue
+            cmdlist = self.parent.curr_page.maptree.GetPyData(layer)[0]['maplayer'].GetCmd()
+            
+            if self.attributeType == 'color':
+                if useAttrColumn:
+                    cmdlist[1].update({'flags': 'a'})
+                    cmdlist[1].update({'rgb_column': self.properties['storeColumn']})
+                else:
+                    if 'flags' in cmdlist[1]:
+                        cmdlist[1]['flags'] = cmdlist[1]['flags'].replace('a', '')
+                    cmdlist[1].pop('rgb_column', None)
+            elif self.attributeType == 'size':
+                cmdlist[1].update({'size_column': self.properties['storeColumn']})
+            elif self.attributeType == 'width':
+                cmdlist[1].update({'width_column' :self.properties['storeColumn']})
+            self.parent.curr_page.maptree.GetPyData(layer)[0]['cmd'] = cmdlist
+        
+    def CreateColorTable(self, tmp = False):
+        """!Create color rules (color table or color column)"""
+        if self.colorTable:
+            ret = ColorTable.CreateColorTable(self)
+        else:
+            if self.updateColumn:
+                ret = self.UpdateColorColumn(tmp)
+            else:
+                ret = True
+        return ret
+        
+    def UpdateColorColumn(self, tmp):
+        """!Creates color table
+
+        @return True on success
+        @return False on failure
+        """
+        rulestxt = ''
+        
+        for rule in self.rulesPanel.ruleslines.itervalues():
+            if 'value' not in rule: # skip empty rules
+                break
+            
+            if tmp:
+                rgb_col = self.properties['tmpColumn']
+            else:
+                rgb_col = self.properties['storeColumn']
+                if not self.properties['storeColumn']:
+                    GMessage(self.parent, message = _("Please select column to save values to."))
+                    
+            rulestxt += "UPDATE %s SET %s='%s' WHERE %s ;\n" % (self.properties['table'],
+                                                                rgb_col,
+                                                                rule[self.attributeType],
+                                                                rule['value'])
+        if not rulestxt:
+            return False
+        
+        gtemp = utils.GetTempfile()
+        output = open(gtemp, "w")
+        try:
+            output.write(rulestxt)
+        finally:
+            output.close()
+        
+        RunCommand('db.execute',
+                   parent = self,
+                   input = gtemp)
+        return True
+    
+    def OnCancel(self, event):
+        """!Do not apply any changes and close the dialog"""
+        self.DeleteTemporaryColumn()
+        self.Map.Clean()
+        self.Destroy()
+
+    def OnApply(self, event):
+        """!Apply selected color table
+        
+        @return True on success otherwise False
+        """
+        if self.colorTable:
+            self.UseAttrColumn(False)
+        else:
+            self.UseAttrColumn(True)
+        
+        return ColorTable.OnApply(self, event)
+        
+class ThematicVectorTable(VectorColorTable):
+    def __init__(self, parent, vectorType, **kwargs):
+        """!Dialog for interactively entering color/size rules
+            for vector maps for thematic mapping in nviz"""
+        self.vectorType = vectorType
+        VectorColorTable.__init__(self, parent = parent, **kwargs)
+              
+        self.SetTitle(_("Thematic mapping for vector map in 3D view"))       
+                    
+    def _initLayer(self):
+        """!Set initial layer when opening dialog"""
+        self.inmap = self.parent.GetLayerData(nvizType = 'vector', nameOnly = True)
+        self.selectionInput.SetValue(self.inmap)
+        self.selectionInput.Disable()
+        
+    def OnApply(self, event):
+        """!Apply selected color table
+
+        @return True on success otherwise False
+        """
+        ret = self.CreateColorTable()
+        if not ret:
+            GMessage(parent = self, message = _("No valid color rules given."))
+        
+        data = self.parent.GetLayerData(nvizType = 'vector')
+        data['vector']['points']['thematic']['layer'] = int(self.properties['layer'])
+        
+        value = None
+        if self.properties['storeColumn']:
+            value = self.properties['storeColumn']
+            
+        if not self.colorTable:
+            if self.attributeType == 'color':
+                data['vector'][self.vectorType]['thematic']['rgbcolumn'] = value
+            else:
+                data['vector'][self.vectorType]['thematic']['sizecolumn'] = value
+        else:
+            if self.attributeType == 'color':
+                data['vector'][self.vectorType]['thematic']['rgbcolumn'] = None
+            else:
+                data['vector'][self.vectorType]['thematic']['sizecolumn'] = None
+        
+        data['vector'][self.vectorType]['thematic']['update'] = None
+        
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.parent.mapWindow, event)
+        self.parent.mapWindow.Refresh(False)
+        
+        return ret
+           
+class BufferedWindow(wx.Window):
+    """!A Buffered window class"""
+    def __init__(self, parent, id,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
+                 Map = None, **kwargs):
+        
+        wx.Window.__init__(self, parent, id, style = style, **kwargs)
+
+        self.parent = parent
+        self.Map = Map
+        
+        # re-render the map from GRASS or just redraw image
+        self.render = True
+        # indicates whether or not a resize event has taken place
+        self.resize = False 
+
+        #
+        # event bindings
+        #
+        self.Bind(wx.EVT_PAINT,        self.OnPaint)
+        self.Bind(wx.EVT_IDLE,         self.OnIdle)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
+
+        #
+        # render output objects
+        #
+        # image file to be rendered
+        self.mapfile = None 
+        # wx.Image object (self.mapfile)
+        self.img = None
+
+        self.pdc = wx.PseudoDC()
+        # will store an off screen empty bitmap for saving to file
+        self._Buffer = None 
+
+        # make sure that extents are updated at init
+        self.Map.region = self.Map.GetRegion()
+        self.Map.SetRegion()
+
+    def Draw(self, pdc, img = None, pdctype = 'image'):
+        """!Draws preview or clears window"""
+        pdc.BeginDrawing()
+
+        Debug.msg (3, "BufferedWindow.Draw(): pdctype=%s" % (pdctype))
+
+        if pdctype == 'clear': # erase the display
+            bg = wx.WHITE_BRUSH
+            pdc.SetBackground(bg)
+            pdc.Clear()
+            self.Refresh()
+            pdc.EndDrawing()
+            return
+
+        if pdctype == 'image' and img:
+            bg = wx.TRANSPARENT_BRUSH
+            pdc.SetBackground(bg)
+            bitmap = wx.BitmapFromImage(img)
+            w, h = bitmap.GetSize()
+            pdc.DrawBitmap(bitmap, 0, 0, True) # draw the composite map
+            
+        pdc.EndDrawing()
+        self.Refresh()
+
+    def OnPaint(self, event):
+        """!Draw pseudo DC to buffer"""
+        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
+        dc = wx.BufferedPaintDC(self, self._Buffer)
+        
+        # use PrepareDC to set position correctly
+        self.PrepareDC(dc)
+        
+        # we need to clear the dc BEFORE calling PrepareDC
+        bg = wx.Brush(self.GetBackgroundColour())
+        dc.SetBackground(bg)
+        dc.Clear()
+        
+        # create a clipping rect from our position and size
+        # and the Update Region
+        rgn = self.GetUpdateRegion()
+        r = rgn.GetBox()
+        
+        # draw to the dc using the calculated clipping rect
+        self.pdc.DrawToDCClipped(dc, r)
+        
+    def OnSize(self, event):
+        """!Init image size to match window size"""
+        # set size of the input image
+        self.Map.width, self.Map.height = self.GetClientSize()
+
+        # Make new off screen bitmap: this bitmap will always have the
+        # current drawing in it, so it can be used to save the image to
+        # a file, or whatever.
+        self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
+
+        # get the image to be rendered
+        self.img = self.GetImage()
+
+        # update map display
+        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
+            self.img = self.img.Scale(self.Map.width, self.Map.height)
+            self.render = False
+            self.UpdatePreview()
+
+        # re-render image on idle
+        self.resize = True
+
+    def OnIdle(self, event):
+        """!Only re-render a preview image from GRASS during
+        idle time instead of multiple times during resizing.
+        """
+        if self.resize:
+            self.render = True
+            self.UpdatePreview()
+        event.Skip()
+
+    def GetImage(self):
+        """!Converts files to wx.Image"""
+        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
+                os.path.getsize(self.Map.mapfile):
+            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
+        else:
+            img = None
+        
+        return img
+    
+    def UpdatePreview(self, img = None):
+        """!Update canvas if window changes geometry"""
+        Debug.msg (2, "BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.render))
+        oldfont = ""
+        oldencoding = ""
+        
+        if self.render:
+            # extent is taken from current map display
+            try:
+                self.Map.region = copy.deepcopy(self.parent.parent.curr_page.maptree.Map.region)
+            except AttributeError:
+                self.Map.region = self.Map.GetRegion()
+            # render new map images
+            self.mapfile = self.Map.Render(force = self.render)
+            self.img = self.GetImage()
+            self.resize = False
+        
+        if not self.img:
+            return
+        
+        # paint images to PseudoDC
+        self.pdc.Clear()
+        self.pdc.RemoveAll()
+        # draw map image background
+        self.Draw(self.pdc, self.img, pdctype = 'image')
+        
+        self.resize = False
+        
+    def EraseMap(self):
+        """!Erase preview"""
+        self.Draw(self.pdc, pdctype = 'clear')
+    

Copied: grass/trunk/gui/wxpython/modules/histogram.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/histogram.py)
===================================================================
--- grass/trunk/gui/wxpython/modules/histogram.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/modules/histogram.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,493 @@
+"""!
+ at package modules.histogram
+
+Plotting histogram based on d.histogram
+
+Classes:
+ - BufferedWindow
+ - HistogramFrame
+ - HistogramToolbar
+
+(C) 2007, 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton
+ at author Various updates by Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+
+from core                 import globalvar
+from core.render          import Map
+from core.forms           import GUI
+from mapdisp.gprint       import PrintOptions
+from core.utils           import GetLayerNameFromCmd
+from gui_core.dialogs     import GetImageHandlers, ImageSizeDialog
+from gui_core.preferences import DefaultFontDialog
+from core.debug           import Debug
+from icon                 import Icons
+from core.gcmd            import GError
+from gui_core.toolbars    import BaseToolbar
+
+class BufferedWindow(wx.Window):
+    """!A Buffered window class.
+
+    When the drawing needs to change, you app needs to call the
+    UpdateHist() method. Since the drawing is stored in a bitmap, you
+    can also save the drawing to file by calling the
+    SaveToFile(self,file_name,file_type) method.
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
+                 Map = None, **kwargs):
+        
+        wx.Window.__init__(self, parent, id = id, style = style, **kwargs)
+        
+        self.parent = parent
+        self.Map = Map
+        self.mapname = self.parent.mapname
+        
+        #
+        # Flags
+        #
+        self.render = True  # re-render the map from GRASS or just redraw image
+        self.resize = False # indicates whether or not a resize event has taken place
+        self.dragimg = None # initialize variable for map panning
+        self.pen = None     # pen for drawing zoom boxes, etc.
+        
+        #
+        # Event bindings
+        #
+        self.Bind(wx.EVT_PAINT,        self.OnPaint)
+        self.Bind(wx.EVT_SIZE,         self.OnSize)
+        self.Bind(wx.EVT_IDLE,         self.OnIdle)
+        
+        #
+        # Render output objects
+        #
+        self.mapfile = None # image file to be rendered
+        self.img = ""       # wx.Image object (self.mapfile)
+        
+        self.imagedict = {} # images and their PseudoDC ID's for painting and dragging
+        
+        self.pdc = wx.PseudoDC()
+        self._buffer = '' # will store an off screen empty bitmap for saving to file
+        
+        # make sure that extents are updated at init
+        self.Map.region = self.Map.GetRegion()
+        self.Map.SetRegion() 
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
+        
+    def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0,0,0,0]):
+        """!Draws histogram or clears window
+        """
+        if drawid == None:
+            if pdctype == 'image' :
+                drawid = imagedict[img]
+            elif pdctype == 'clear':
+                drawid == None
+            else:
+                drawid = wx.NewId()
+        else:
+            pdc.SetId(drawid)
+        
+        pdc.BeginDrawing()
+        
+        Debug.msg (3, "BufferedWindow.Draw(): id=%s, pdctype=%s, coord=%s" % (drawid, pdctype, coords))
+        
+        if pdctype == 'clear': # erase the display
+            bg = wx.WHITE_BRUSH
+            pdc.SetBackground(bg)
+            pdc.Clear()
+            self.Refresh()
+            pdc.EndDrawing()
+            return
+        
+        if pdctype == 'image':
+            bg = wx.TRANSPARENT_BRUSH
+            pdc.SetBackground(bg)
+            bitmap = wx.BitmapFromImage(img)
+            w,h = bitmap.GetSize()
+            pdc.DrawBitmap(bitmap, coords[0], coords[1], True) # draw the composite map
+            pdc.SetIdBounds(drawid, (coords[0],coords[1],w,h))
+        
+        pdc.EndDrawing()
+        self.Refresh()
+        
+    def OnPaint(self, event):
+        """!Draw psuedo DC to buffer
+        """
+        dc = wx.BufferedPaintDC(self, self._buffer)
+        
+        # use PrepareDC to set position correctly
+        self.PrepareDC(dc)
+        # we need to clear the dc BEFORE calling PrepareDC
+        bg = wx.Brush(self.GetBackgroundColour())
+        dc.SetBackground(bg)
+        dc.Clear()
+        # create a clipping rect from our position and size
+        # and the Update Region
+        rgn = self.GetUpdateRegion()
+        r = rgn.GetBox()
+        # draw to the dc using the calculated clipping rect
+        self.pdc.DrawToDCClipped(dc,r)
+        
+    def OnSize(self, event):
+        """!Init image size to match window size
+        """
+        # set size of the input image
+        self.Map.width, self.Map.height = self.GetClientSize()
+        
+        # Make new off screen bitmap: this bitmap will always have the
+        # current drawing in it, so it can be used to save the image to
+        # a file, or whatever.
+        self._buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
+        
+        # get the image to be rendered
+        self.img = self.GetImage()
+        
+        # update map display
+        if self.img and self.Map.width + self.Map.height > 0: # scale image during resize
+            self.img = self.img.Scale(self.Map.width, self.Map.height)
+            self.render = False
+            self.UpdateHist()
+        
+        # re-render image on idle
+        self.resize = True
+        
+    def OnIdle(self, event):
+        """!Only re-render a histogram image from GRASS during idle
+        time instead of multiple times during resizing.
+        """
+        if self.resize:
+            self.render = True
+            self.UpdateHist()
+        event.Skip()
+        
+    def SaveToFile(self, FileName, FileType, width, height):
+        """!This will save the contents of the buffer to the specified
+        file. See the wx.Windows docs for wx.Bitmap::SaveFile for the
+        details
+        """
+        busy = wx.BusyInfo(message=_("Please wait, exporting image..."),
+                           parent=self)
+        wx.Yield()
+        
+        self.Map.ChangeMapSize((width, height))
+        ibuffer = wx.EmptyBitmap(max(1, width), max(1, height))
+        self.Map.Render(force=True, windres = True)
+        img = self.GetImage()
+        self.Draw(self.pdc, img, drawid = 99)
+        dc = wx.BufferedPaintDC(self, ibuffer)
+        dc.Clear()
+        self.PrepareDC(dc)
+        self.pdc.DrawToDC(dc)
+        ibuffer.SaveFile(FileName, FileType)
+        
+        busy.Destroy()
+        
+    def GetImage(self):
+        """!Converts files to wx.Image
+        """
+        if self.Map.mapfile and os.path.isfile(self.Map.mapfile) and \
+                os.path.getsize(self.Map.mapfile):
+            img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
+        else:
+            img = None
+        
+        self.imagedict[img] = 99 # set image PeudoDC ID
+        return img
+    
+    def UpdateHist(self, img = None):
+        """!Update canvas if histogram options changes or window
+        changes geometry
+        """
+        Debug.msg (2, "BufferedWindow.UpdateHist(%s): render=%s" % (img, self.render))
+        oldfont = ""
+        oldencoding = ""
+        
+        if self.render:
+            # render new map images
+            # set default font and encoding environmental variables
+            if "GRASS_FONT" in os.environ:
+                oldfont = os.environ["GRASS_FONT"]
+            if self.parent.font != "": os.environ["GRASS_FONT"] = self.parent.font
+            if "GRASS_ENCODING" in os.environ:
+                oldencoding = os.environ["GRASS_ENCODING"]
+            if self.parent.encoding != None and self.parent.encoding != "ISO-8859-1":
+                os.environ[GRASS_ENCODING] = self.parent.encoding
+            
+            # using active comp region
+            self.Map.GetRegion(update = True)
+            
+            self.Map.width, self.Map.height = self.GetClientSize()
+            self.mapfile = self.Map.Render(force = self.render)
+            self.img = self.GetImage()
+            self.resize = False
+        
+        if not self.img: return
+        try:
+            id = self.imagedict[self.img]
+        except:
+            return
+        
+        # paint images to PseudoDC
+        self.pdc.Clear()
+        self.pdc.RemoveAll()
+        self.Draw(self.pdc, self.img, drawid = id) # draw map image background
+        
+        self.resize = False
+        
+        # update statusbar
+        # Debug.msg (3, "BufferedWindow.UpdateHist(%s): region=%s" % self.Map.region)
+        self.Map.SetRegion()
+        self.parent.statusbar.SetStatusText("Image/Raster map <%s>" % self.parent.mapname)
+        
+        # set default font and encoding environmental variables
+        if oldfont != "":
+            os.environ["GRASS_FONT"] = oldfont
+        if oldencoding != "":
+            os.environ["GRASS_ENCODING"] = oldencoding
+        
+    def EraseMap(self):
+        """!Erase the map display
+        """
+        self.Draw(self.pdc, pdctype = 'clear')
+        
+class HistFrame(wx.Frame):
+    """!Main frame for hisgram display window. Uses d.histogram
+    rendered onto canvas
+    """
+    def __init__(self, parent = None, id = wx.ID_ANY,
+                 title = _("GRASS GIS Histogram of raster map"),
+                 style = wx.DEFAULT_FRAME_STYLE, **kwargs):
+        wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.Map   = Map()         # instance of render.Map to be associated with display
+        self.layer = None          # reference to layer with histogram
+        
+        # Init variables
+        self.params = {}  # previously set histogram parameters
+        self.propwin = '' # ID of properties dialog
+        
+        self.font = ""
+        self.encoding = 'ISO-8859-1' # default encoding for display fonts
+        
+        self.toolbar = HistogramToolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+
+        # Add statusbar
+        self.mapname = ''
+        self.statusbar = self.CreateStatusBar(number = 1, style = 0)
+        # self.statusbar.SetStatusWidths([-2, -1])
+        hist_frame_statusbar_fields = ["Histogramming %s" % self.mapname]
+        for i in range(len(hist_frame_statusbar_fields)):
+            self.statusbar.SetStatusText(hist_frame_statusbar_fields[i], i)
+        
+        # Init map display
+        self.InitDisplay() # initialize region values
+        
+        # initialize buffered DC
+        self.HistWindow = BufferedWindow(self, id = wx.ID_ANY, Map = self.Map) # initialize buffered DC
+        
+        # Bind various events
+        self.Bind(wx.EVT_CLOSE,    self.OnCloseWindow)
+        
+        # Init print module and classes
+        self.printopt = PrintOptions(self, self.HistWindow)
+        
+        # Add layer to the map
+        self.layer = self.Map.AddLayer(type = "command", name = 'histogram', command = ['d.histogram'],
+                                       l_active = False, l_hidden = False, l_opacity = 1, l_render = False)
+        
+    def InitDisplay(self):
+        """!Initialize histogram display, set dimensions and region
+        """
+        self.width, self.height = self.GetClientSize()
+        self.Map.geom = self.width, self.height
+        
+    def OnOptions(self, event):
+        """!Change histogram settings"""
+        cmd = ['d.histogram']
+        if self.mapname != '':
+            cmd.append('map=%s' % self.mapname)
+        
+        GUI(parent = self).ParseCommand(cmd,
+                                        completed = (self.GetOptData, None, self.params))
+        
+    def GetOptData(self, dcmd, layer, params, propwin):
+        """!Callback method for histogram command generated by dialog
+        created in menuform.py
+        """
+        if dcmd:
+            name, found = GetLayerNameFromCmd(dcmd, fullyQualified = True,
+                                              layerType = 'raster')
+            if not found:
+                GError(parent = propwin,
+                       message = _("Raster map <%s> not found") % name)
+                return
+            
+            self.SetHistLayer(name)
+        self.params = params
+        self.propwin = propwin
+        
+        self.HistWindow.UpdateHist()
+        
+    def SetHistLayer(self, name):
+        """!Set histogram layer
+        """
+        self.mapname = name
+        
+        self.layer = self.Map.ChangeLayer(layer = self.layer,
+                                          command = [['d.histogram', 'map=%s' % self.mapname],],
+                                          active = True)
+        
+        return self.layer
+
+    def SetHistFont(self, event):
+        """!Set font for histogram. If not set, font will be default
+        display font.
+        """
+        dlg = DefaultFontDialog(parent = self, id = wx.ID_ANY,
+                                title = _('Select font for histogram text'))        
+        dlg.fontlb.SetStringSelection(self.font, True)
+        
+        if dlg.ShowModal() == wx.ID_CANCEL:
+            dlg.Destroy()
+            return
+        
+        # set default font type, font, and encoding to whatever selected in dialog
+        if dlg.font != None:
+            self.font = dlg.font
+        if dlg.encoding != None:
+            self.encoding = dlg.encoding
+        
+        dlg.Destroy()
+        self.HistWindow.UpdateHist()
+
+    def OnErase(self, event):
+        """!Erase the histogram display
+        """
+        self.HistWindow.Draw(self.HistWindow.pdc, pdctype = 'clear')
+        
+    def OnRender(self, event):
+        """!Re-render histogram
+        """
+        self.HistWindow.UpdateHist()
+        
+    def GetWindow(self):
+        """!Get buffered window"""
+        return self.HistWindow
+    
+    def SaveToFile(self, event):
+        """!Save to file
+        """
+        filetype, ltype = GetImageHandlers(self.HistWindow.img)
+        
+        # get size
+        dlg = ImageSizeDialog(self)
+        dlg.CentreOnParent()
+        if dlg.ShowModal() != wx.ID_OK:
+            dlg.Destroy()
+            return
+        width, height = dlg.GetValues()
+        dlg.Destroy()
+        
+        # get filename
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to save the image "
+                                        "(no need to add extension)"),
+                            wildcard = filetype,
+                            style=wx.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.HistWindow.SaveToFile(path, fileType,
+                                       width, height)
+        
+        self.HistWindow.UpdateHist()
+        dlg.Destroy()
+        
+    def PrintMenu(self, event):
+        """!Print options and output menu
+        """
+        point = wx.GetMousePosition()
+        printmenu = wx.Menu()
+        # Add items to the menu
+        setup = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('Page setup'))
+        printmenu.AppendItem(setup)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
+        
+        preview = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('Print preview'))
+        printmenu.AppendItem(preview)
+        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
+        
+        doprint = wx.MenuItem(printmenu, id = wx.ID_ANY, text = _('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 OnQuit(self, event):
+        self.Close(True)
+        
+    def OnCloseWindow(self, event):
+        """!Window closed
+        Also remove associated rendered images
+        """
+        try:
+            self.propwin.Close(True)
+        except:
+            pass
+        self.Map.Clean()
+        self.Destroy()
+        
+class HistogramToolbar(BaseToolbar):
+    """!Histogram toolbar (see histogram.py)
+    """
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['displayWindow']
+        return self._getToolbarData((('histogram', icons["histogram"],
+                                      self.parent.OnOptions),
+                                     ('rendermao', icons["display"],
+                                      self.parent.OnRender),
+                                     ('erase', icons["erase"],
+                                      self.parent.OnErase),
+                                     ('font', Icons['misc']["font"],
+                                      self.parent.SetHistFont),
+                                     (None, ),
+                                     ('save', icons["saveFile"],
+                                      self.parent.SaveToFile),
+                                     ('hprint', icons["print"],
+                                      self.parent.PrintMenu),
+                                     (None, ),
+                                     ('quit', Icons['misc']["quit"],
+                                      self.parent.OnQuit))
+                                    )

Copied: grass/trunk/gui/wxpython/modules/mcalc_builder.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/mcalc_builder.py)
===================================================================
--- grass/trunk/gui/wxpython/modules/mcalc_builder.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/modules/mcalc_builder.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,580 @@
+"""!
+ at package modules mcalc_builder
+
+ at brief Map calculator, GUI wrapper for r.mapcalc
+
+Classes:
+ - MapCalcFrame
+
+(C) 2008, 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+ at author Martin Landa <landa.martin gmail.com>
+ at author Tim Michelsen (load/save expression)
+"""
+
+import os
+
+from core import globalvar
+import wx
+
+import grass.script as grass
+
+from core.gcmd        import GError, RunCommand
+from gui_core.gselect import Select
+from core.forms       import GUI
+from core.settings    import UserSettings
+
+class MapCalcFrame(wx.Frame):
+    """!Mapcalc Frame class. Calculator-style window to create and run
+    r(3).mapcalc statements.
+    """
+    def __init__(self, parent, cmd, id = wx.ID_ANY,
+                 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER, **kwargs):
+        self.parent = parent
+        if self.parent:
+            self.log = self.parent.GetLogWindow()
+        else:
+            self.log = None
+        
+        # grass command
+        self.cmd = cmd
+
+        if self.cmd == 'r.mapcalc':
+            self.rast3d = False
+            title = _('GRASS GIS Raster Map Calculator')
+        if self.cmd == 'r3.mapcalc':
+            self.rast3d = True
+            title = _('GRASS GIS 3D Raster Map Calculator')
+            
+        wx.Frame.__init__(self, parent, id = id, title = title, **kwargs)
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        self.CreateStatusBar()
+        
+        #
+        # variables
+        #
+        self.heading = _('mapcalc statement')
+        self.funct_dict = {
+            'abs(x)':'abs()',
+            'acos(x)':'acos()',
+            'asin(x)':'asin()',
+            'atan(x)':'atan()',
+            'atan(x,y)':'atan( , )',
+            'cos(x)':'cos()',
+            'double(x)':'double()',
+            'eval([x,y,...,]z)':'eval()',
+            'exp(x)':'exp()',
+            'exp(x,y)':'exp( , )',
+            'float(x)':'float()',
+            'graph(x,x1,y1[x2,y2..])':'graph( , , )',
+            'if(x)':'if()',
+            'if(x,a)':'if( , )',
+            'if(x,a,b)':'if( , , )',
+            'if(x,a,b,c)':'if( , , , )',
+            'int(x)':'if()',
+            'isnull(x)':'isnull()',
+            'log(x)':'log(',
+            'log(x,b)':'log( , )',
+            'max(x,y[,z...])':'max( , )',
+            'median(x,y[,z...])':'median( , )',
+            'min(x,y[,z...])':'min( , )',
+            'mode(x,y[,z...])':'mode( , )',
+            'not(x)':'not()',
+            'pow(x,y)':'pow( , )',
+            'rand(a,b)':'rand( , )',
+            'round(x)':'round()',
+            'sin(x)':'sin()',
+            'sqrt(x)':'sqrt()',
+            'tan(x)':'tan()',
+            'xor(x,y)':'xor( , )',
+            'row()':'row()',
+            'col()':'col()',
+            'x()':'x()',
+            'y()':'y()',
+            'ewres()':'ewres()',
+            'nsres()':'nsres()',
+            'null()':'null()'
+            }
+        
+        if self.rast3d:
+            self.funct_dict['z()'] = 'z()'
+            self.funct_dict['tbres()'] = 'tbres()'
+            element = 'rast3d'
+        else:
+            element = 'cell'
+        
+        self.operatorBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                        label=" %s " % _('Operators'))
+        self.operandBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                       label=" %s " % _('Operands'))
+        self.expressBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                       label=" %s " % _('Expression'))
+        
+        #
+        # Buttons
+        #
+        self.btn_clear = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
+        self.btn_help = wx.Button(parent = self.panel, id = wx.ID_HELP)
+        self.btn_run = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Run"))
+        self.btn_run.SetForegroundColour(wx.Colour(35, 142, 35))
+        self.btn_run.SetDefault()
+        self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+        self.btn_cmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                 label = _("Command dialog"))
+        self.btn_cmd.SetToolTipString(_('Open %s dialog') % self.cmd)
+        self.btn_save = wx.Button(parent = self.panel, id = wx.ID_SAVE)
+        self.btn_save.SetToolTipString(_('Save expression to file'))
+        self.btn_load = wx.Button(parent = self.panel, id = wx.ID_ANY,
+                                  label = _("&Load"))
+        self.btn_load.SetToolTipString(_('Load expression from file'))
+        
+        self.btn = dict()        
+        self.btn['pow'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "^")
+        self.btn['pow'].SetToolTipString(_('exponent'))
+        self.btn['div'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "/")
+        self.btn['div'].SetToolTipString(_('divide'))
+        self.btn['add'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "+")
+        self.btn['add'].SetToolTipString(_('add'))
+        self.btn['minus'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "-")
+        self.btn['minus'].SetToolTipString(_('subtract'))
+        self.btn['mod'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "%")
+        self.btn['mod'].SetToolTipString(_('modulus'))
+        self.btn['mult'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "*")
+        self.btn['mult'].SetToolTipString(_('multiply'))
+
+        self.btn['parenl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "(") 
+        self.btn['parenr'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ")")
+        self.btn['lshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<<")
+        self.btn['lshift'].SetToolTipString(_('left shift'))
+        self.btn['rshift'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>")
+        self.btn['rshift'].SetToolTipString(_('right shift'))
+        self.btn['rshiftu'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">>>")
+        self.btn['rshiftu'].SetToolTipString(_('right shift (unsigned)'))
+        self.btn['gt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">")
+        self.btn['gt'].SetToolTipString(_('greater than'))
+        self.btn['gteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = ">=")
+        self.btn['gteq'].SetToolTipString(_('greater than or equal to'))
+        self.btn['lt'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<")
+        self.btn['lt'].SetToolTipString(_('less than'))
+        self.btn['lteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "<=")
+        self.btn['lteq'].SetToolTipString(_('less than or equal to'))
+        self.btn['eq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "==")
+        self.btn['eq'].SetToolTipString(_('equal to'))
+        self.btn['noteq'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!=")
+        self.btn['noteq'].SetToolTipString(_('not equal to'))
+
+        self.btn['compl'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "~")
+        self.btn['compl'].SetToolTipString(_('one\'s complement'))
+        self.btn['not'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "!")
+        self.btn['not'].SetToolTipString(_('NOT'))
+        self.btn['andbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = '&&')
+        self.btn['andbit'].SetToolTipString(_('bitwise AND'))
+        self.btn['orbit'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|")
+        self.btn['orbit'].SetToolTipString(_('bitwise OR'))
+        self.btn['and'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&")
+        self.btn['and'].SetToolTipString(_('logical AND'))
+        self.btn['andnull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "&&&&&&")
+        self.btn['andnull'].SetToolTipString(_('logical AND (ignores NULLs)'))
+        self.btn['or'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "||")
+        self.btn['or'].SetToolTipString(_('logical OR'))
+        self.btn['ornull'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "|||")
+        self.btn['ornull'].SetToolTipString(_('logical OR (ignores NULLs)'))
+        self.btn['cond'] = wx.Button(parent = self.panel, id = wx.ID_ANY, label = "a ? b : c") 
+        self.btn['cond'].SetToolTipString(_('conditional'))
+        
+        #
+        # Text area
+        #
+        self.text_mcalc = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size = (-1, 75),
+                                      style = wx.TE_MULTILINE)
+        wx.CallAfter(self.text_mcalc.SetFocus)
+        
+        #
+        # Map and function insertion text and ComboBoxes
+        self.newmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
+        if self.rast3d:
+            self.newmaplabel.SetLabel(_('Name for new 3D raster map to create'))
+        else:
+            self.newmaplabel.SetLabel(_('Name for new raster map to create'))
+        self.newmaptxt = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, size=(250, -1))
+        self.mapsellabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY)
+        if self.rast3d:
+            self.mapsellabel.SetLabel(_('Insert existing 3D raster map'))
+        else:
+            self.mapsellabel.SetLabel(_('Insert existing raster map'))
+        self.mapselect = Select(parent = self.panel, id = wx.ID_ANY, size = (250, -1),
+                                type = element, multiple = False)
+        self.functlabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+                                        label = _('Insert mapcalc function'))
+        self.function = wx.ComboBox(parent = self.panel, id = wx.ID_ANY, 
+                                    size = (250, -1), choices = sorted(self.funct_dict.keys()),
+                                    style = wx.CB_DROPDOWN |
+                                    wx.CB_READONLY | wx.TE_PROCESS_ENTER)
+        
+        self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+                                     label=_("Allow output files to overwrite existing files"))
+        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
+        
+        self.addbox = wx.CheckBox(parent=self.panel,
+                                  label=_('Add created raster map into layer tree'), style = wx.NO_BORDER)
+        self.addbox.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
+        if not self.parent or self.parent.GetName() != 'LayerManager':
+            self.addbox.Hide()
+        
+        #
+        # Bindings
+        #
+        for btn in self.btn.keys():
+            self.btn[btn].Bind(wx.EVT_BUTTON, self.AddMark)
+        
+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
+        self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
+        self.btn_run.Bind(wx.EVT_BUTTON, self.OnMCalcRun)
+        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
+        self.btn_cmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+        self.btn_save.Bind(wx.EVT_BUTTON, self.OnSaveExpression)
+        self.btn_load.Bind(wx.EVT_BUTTON, self.OnLoadExpression)
+        
+        self.mapselect.Bind(wx.EVT_TEXT, self.OnSelect)
+        self.function.Bind(wx.EVT_COMBOBOX, self._return_funct)
+        self.function.Bind(wx.EVT_TEXT_ENTER, self.OnSelect)
+        self.newmaptxt.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
+        self.text_mcalc.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
+
+        self._layout()
+
+        self.SetMinSize(self.GetBestSize())
+    
+    def _return_funct(self,event):
+	i = event.GetString()
+	self._addSomething(self.funct_dict[i])
+    
+    def _layout(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        controlSizer = wx.BoxSizer(wx.HORIZONTAL)
+        operatorSizer = wx.StaticBoxSizer(self.operatorBox, wx.HORIZONTAL)
+
+        buttonSizer1 = wx.GridBagSizer(5, 1)
+        buttonSizer1.Add(item = self.btn['add'], pos = (0,0))
+        buttonSizer1.Add(item = self.btn['minus'], pos = (0,1))
+        buttonSizer1.Add(item = self.btn['mod'], pos = (5,0))
+        buttonSizer1.Add(item = self.btn['mult'], pos = (1,0))
+        buttonSizer1.Add(item = self.btn['div'], pos = (1,1))
+        buttonSizer1.Add(item = self.btn['pow'], pos = (5,1))
+        buttonSizer1.Add(item = self.btn['gt'], pos = (2,0))
+        buttonSizer1.Add(item = self.btn['gteq'], pos = (2,1))
+        buttonSizer1.Add(item = self.btn['eq'], pos = (4,0))
+        buttonSizer1.Add(item = self.btn['lt'], pos = (3,0))
+        buttonSizer1.Add(item = self.btn['lteq'], pos = (3,1))
+        buttonSizer1.Add(item = self.btn['noteq'], pos = (4,1))
+
+        buttonSizer2 = wx.GridBagSizer(5, 1)
+        buttonSizer2.Add(item = self.btn['and'], pos = (0,0))
+        buttonSizer2.Add(item = self.btn['andbit'], pos = (1,0))
+        buttonSizer2.Add(item = self.btn['andnull'], pos = (2,0))
+        buttonSizer2.Add(item = self.btn['or'], pos = (0,1))
+        buttonSizer2.Add(item = self.btn['orbit'], pos = (1,1))
+        buttonSizer2.Add(item = self.btn['ornull'], pos = (2,1))
+        buttonSizer2.Add(item = self.btn['lshift'], pos = (3,0))
+        buttonSizer2.Add(item = self.btn['rshift'], pos = (3,1))
+        buttonSizer2.Add(item = self.btn['rshiftu'], pos = (4,0))
+        buttonSizer2.Add(item = self.btn['cond'], pos = (5,0))
+        buttonSizer2.Add(item = self.btn['compl'], pos = (5,1))
+        buttonSizer2.Add(item = self.btn['not'], pos = (4,1))
+
+        operandSizer = wx.StaticBoxSizer(self.operandBox, wx.HORIZONTAL)
+        
+        buttonSizer3 = wx.GridBagSizer(7, 1)
+        buttonSizer3.Add(item = self.newmaplabel, pos = (0,0),
+                         span = (1, 2), flag = wx.ALIGN_CENTER)
+        buttonSizer3.Add(item = self.newmaptxt, pos = (1,0),
+                         span = (1, 2))
+        buttonSizer3.Add(item = self.functlabel, pos = (2,0),
+                         span = (1,2), flag = wx.ALIGN_CENTER)
+        buttonSizer3.Add(item = self.function, pos = (3,0),
+                         span = (1,2))                         
+        buttonSizer3.Add(item = self.mapsellabel, pos = (4,0),
+                         span = (1,2), flag = wx.ALIGN_CENTER)
+        buttonSizer3.Add(item = self.mapselect, pos = (5,0),
+                         span = (1,2))
+        threebutton = wx.GridBagSizer(1, 2)
+        threebutton.Add(item = self.btn['parenl'], pos = (0,0),
+                         span = (1,1), flag = wx.ALIGN_LEFT)
+        threebutton.Add(item = self.btn['parenr'], pos = (0,1),
+                         span = (1,1), flag = wx.ALIGN_CENTER)
+        threebutton.Add(item = self.btn_clear, pos = (0,2),
+                         span = (1,1), flag = wx.ALIGN_RIGHT)
+        buttonSizer3.Add(item = threebutton, pos = (6,0),
+	                 span = (1,1), flag = wx.ALIGN_CENTER)
+
+        buttonSizer4 = wx.BoxSizer(wx.HORIZONTAL)
+        buttonSizer4.Add(item = self.btn_cmd,
+                         flag = wx.ALL, border = 5)
+        buttonSizer4.AddSpacer(10)
+        buttonSizer4.Add(item = self.btn_load,
+                         flag = wx.ALL, border = 5)
+        buttonSizer4.Add(item = self.btn_save,
+                         flag = wx.ALL, border = 5)                         
+        buttonSizer4.AddSpacer(30)
+        buttonSizer4.Add(item = self.btn_help,
+                         flag = wx.ALL, border = 5)
+        buttonSizer4.Add(item = self.btn_run,
+                         flag = wx.ALL, border = 5)
+        buttonSizer4.Add(item = self.btn_close,
+                         flag = wx.ALL, border = 5)
+        
+        operatorSizer.Add(item = buttonSizer1, proportion = 0,
+                          flag = wx.ALL | wx.EXPAND, border = 5)
+        operatorSizer.Add(item = buttonSizer2, proportion = 0,
+                          flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 5)
+        
+        operandSizer.Add(item = buttonSizer3, proportion = 0,
+                         flag = wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
+        
+        controlSizer.Add(item = operatorSizer, proportion = 1,
+                         flag = wx.RIGHT | wx.EXPAND, border = 5)
+        controlSizer.Add(item = operandSizer, proportion = 0,
+                         flag = wx.EXPAND)
+
+        expressSizer = wx.StaticBoxSizer(self.expressBox, wx.HORIZONTAL)
+        expressSizer.Add(item = self.text_mcalc, proportion = 1,
+                         flag = wx.EXPAND)
+
+        sizer.Add(item = controlSizer, proportion = 0,
+                  flag = wx.EXPAND | wx.ALL,
+                  border = 5)        
+        sizer.Add(item = expressSizer, proportion = 1,
+                  flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
+                  border = 5)
+        sizer.Add(item = buttonSizer4, proportion = 0,
+                  flag = wx.ALIGN_RIGHT | wx.ALL, border = 3)
+        
+        sizer.Add(item = self.overwrite, proportion = 0,
+                  flag = wx.LEFT | wx.RIGHT,
+                  border = 5)
+        if self.addbox.IsShown():
+            sizer.Add(item = self.addbox, proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT,
+                      border = 5)
+        
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(sizer)
+        sizer.Fit(self.panel)
+        
+        self.Layout()
+        
+    def AddMark(self,event):
+        """!Sends operators to insertion method
+        """
+        if event.GetId() == self.btn['compl'].GetId(): mark = "~"
+        elif event.GetId() == self.btn['not'].GetId(): mark = "!"
+        elif event.GetId() == self.btn['pow'].GetId(): mark = "^"
+        elif event.GetId() == self.btn['div'].GetId(): mark = "/"
+        elif event.GetId() == self.btn['add'].GetId(): mark = "+"
+        elif event.GetId() == self.btn['minus'].GetId(): mark = "-"
+        elif event.GetId() == self.btn['mod'].GetId(): mark = "%"
+        elif event.GetId() == self.btn['mult'].GetId(): mark = "*"
+        elif event.GetId() == self.btn['lshift'].GetId(): mark = "<<"
+        elif event.GetId() == self.btn['rshift'].GetId(): mark = ">>"
+        elif event.GetId() == self.btn['rshiftu'].GetId(): mark = ">>>"
+        elif event.GetId() == self.btn['gt'].GetId(): mark = ">"
+        elif event.GetId() == self.btn['gteq'].GetId(): mark = ">="
+        elif event.GetId() == self.btn['lt'].GetId(): mark = "<"
+        elif event.GetId() == self.btn['lteq'].GetId(): mark = "<="
+        elif event.GetId() == self.btn['eq'].GetId(): mark = "=="
+        elif event.GetId() == self.btn['noteq'].GetId(): mark = "!="
+        elif event.GetId() == self.btn['andbit'].GetId(): mark = "&"
+        elif event.GetId() == self.btn['orbit'].GetId(): mark = "|"
+        elif event.GetId() == self.btn['or'].GetId(): mark =  "||"
+        elif event.GetId() == self.btn['ornull'].GetId(): mark = "|||"
+        elif event.GetId() == self.btn['and'].GetId(): mark = "&&"
+        elif event.GetId() == self.btn['andnull'].GetId(): mark = "&&&"
+        elif event.GetId() == self.btn['cond'].GetId(): mark = " ? : "
+        elif event.GetId() == self.btn['parenl'].GetId(): mark = "("
+        elif event.GetId() == self.btn['parenr'].GetId(): mark = ")"
+        self._addSomething(mark)
+        
+    def OnSelect(self, event):
+        """!Gets raster map or function selection and send it to
+        insertion method
+        """
+        item = event.GetString()
+        self._addSomething(item)
+
+    def OnUpdateStatusBar(self, event):
+        """!Update statusbar text"""
+        expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
+        self.SetStatusText("r.mapcalc '%s = %s'" % (self.newmaptxt.GetValue(),
+                                                    expr))
+        event.Skip()
+        
+    def _addSomething(self, what):
+        """!Inserts operators, map names, and functions into text area
+        """
+        self.text_mcalc.SetFocus()
+        mcalcstr  = self.text_mcalc.GetValue()
+        position  = self.text_mcalc.GetInsertionPoint()
+        
+        newmcalcstr = mcalcstr[:position]
+        
+        position_offset = 0
+        try:
+            if newmcalcstr[-1] != ' ':
+                newmcalcstr += ' '
+                position_offset += 1
+        except:
+            pass
+        
+        newmcalcstr += what + ' ' + mcalcstr[position:]
+        position_offset += len(what)
+        
+        self.text_mcalc.SetValue(newmcalcstr)
+        if len(what) > 1 and what[-2:] == '()':
+            position_offset -= 1
+        self.text_mcalc.SetInsertionPoint(position + position_offset)
+        self.text_mcalc.Update()
+        
+    def OnMCalcRun(self,event):
+        """!Builds and runs r.mapcalc statement
+        """
+        name = self.newmaptxt.GetValue().strip()
+        if not name:
+            GError(parent = self,
+                   message = _("You must enter the name of "
+                               "a new raster map to create."))
+            return
+        
+        expr = self.text_mcalc.GetValue().strip().replace("\n", " ")
+        if not expr:
+            GError(parent = self,
+                   message = _("You must enter an expression "
+                               "to create a new raster map."))
+            return
+        
+        if self.log:
+            cmd = [self.cmd, str('expression=%s = %s' % (name, expr))]
+            if self.overwrite.IsChecked():
+                cmd.append('--overwrite')
+            self.log.RunCmd(cmd, onDone = self.OnDone)
+            self.parent.Raise()
+        else:
+            if self.overwrite.IsChecked():
+                overwrite = True
+            else:
+                overwrite = False
+            RunCommand(self.cmd,
+                       expression = "%s=%s" % (name, expr),
+                       overwrite = overwrite)
+        
+    def OnDone(self, cmd, returncode):
+        """!Add create map to the layer tree"""
+        if not self.addbox.IsChecked():
+            return
+        name = self.newmaptxt.GetValue().strip() + '@' + grass.gisenv()['MAPSET']
+        mapTree = self.parent.GetLayerTree()
+        if not mapTree.GetMap().GetListOfLayers(l_name = name):
+            mapTree.AddLayer(ltype = 'raster',
+                             lname = name,
+                             lcmd = ['d.rast', 'map=%s' % name],
+                             multiple = False)
+        
+        display = self.parent.GetLayerTree().GetMapDisplay()
+        if display and display.IsAutoRendered():
+            display.GetWindow().UpdateMap(render = True)
+        
+    def OnSaveExpression(self, event):
+        """!Saves expression to file
+        """
+        mctxt = self.newmaptxt.GetValue() + ' = ' + self.text_mcalc.GetValue() + os.linesep
+        
+        #dialog
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to save the expression"),
+                            wildcard = _("Expression file (*)|*"),
+                            style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            if not path:
+                dlg.Destroy()
+                return
+            
+            try:
+                fobj = open(path, 'w')
+                fobj.write(mctxt)
+            finally:
+                fobj.close()
+        
+        dlg.Destroy()
+
+    def OnLoadExpression(self, event):
+        """!Load expression from file
+        """
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Choose a file name to load the expression"),
+                            wildcard = _("Expression file (*)|*"),
+                            style = wx.OPEN)
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            if not path:
+                dlg.Destroy()
+                return
+
+            try:
+                fobj = open(path,'r')
+                mctxt = fobj.read()
+            finally:
+                fobj.close()
+            
+            try:
+                result, exp = mctxt.split('=', 1)
+            except ValueError:
+                result = ''
+                exp = mctxt
+            
+            self.newmaptxt.SetValue(result.strip())
+            self.text_mcalc.SetValue(exp.strip())
+            self.text_mcalc.SetFocus()
+            self.text_mcalc.SetInsertionPointEnd()
+        
+        dlg.Destroy()
+                
+    def OnClear(self, event):
+        """!Clears text area
+        """
+        self.text_mcalc.SetValue('')
+        
+    def OnHelp(self, event):
+        """!Launches r.mapcalc help
+        """
+        RunCommand('g.manual', parent = self, entry = self.cmd)
+        
+    def OnClose(self,event):
+        """!Close window"""
+        self.Destroy()
+
+    def OnCmdDialog(self, event):
+        """!Shows command dialog"""
+        name = self.newmaptxt.GetValue().strip()
+        mctxt = self.text_mcalc.GetValue().strip().replace("\n"," ")
+        mctxt = mctxt.replace(" " , "")
+        expr = name
+        if expr:
+            expr += '='
+        expr += mctxt
+        
+        GUI(parent = self).ParseCommand(cmd = [self.cmd, 'expression=' + expr])
+        
+if __name__ == "__main__":
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    app = wx.App(0)
+    frame = MapCalcFrame(parent = None, cmd = 'r.mapcalc')
+    frame.Show()
+    app.MainLoop()

Copied: grass/trunk/gui/wxpython/modules/ogc_services.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/ogc_services.py)
===================================================================
--- grass/trunk/gui/wxpython/modules/ogc_services.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/modules/ogc_services.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,299 @@
+"""!
+ at package module.ogc_services
+
+ at brief Dialogs for OGC services
+
+Currently only implemeted WMS.
+
+List of classes:
+ - WMSDialog
+ - LayersList
+
+(C) 2009 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import wx
+from wx.gizmos import TreeListCtrl
+import wx.lib.mixins.listctrl as listmix
+
+from core.gcmd     import RunCommand
+from core.settings import UserSettings
+
+class WMSDialog(wx.Dialog):
+    def __init__(self, parent, service = 'wms',
+                 id=wx.ID_ANY,
+                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        """!Dialog to import data from WMS server"""
+        self.parent  = parent  # GMFrame 
+        self.service = service # currently only WMS is implemented
+        
+        wx.Dialog.__init__(self, parent, id, style=style)
+        if self.service == 'wms':
+            self.SetTitle(_("Import data from WMS server"))
+            
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        self.__createWidgets()
+        
+        self.__doLayout()
+
+        self.SetMinSize((550, 400))
+        
+    def __createWidgets(self):
+        """!Create dialog widgets"""
+        #
+        # settings
+        #
+        self.settingsBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                        label = _(" Server settings "))
+
+        self.serverText = wx.StaticText(parent = self.panel, id = wx.ID_ANY, label = _("Server:"))
+        self.server  = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
+        
+        #
+        # list of layers
+        #
+        self.layersBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+                                label=_(" List of layers "))
+
+        self.list = LayersList(self.panel)
+        self.list.LoadData()
+
+        self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
+                               label=_("Add imported layers into layer tree"))
+        self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
+                
+        #
+        # buttons
+        #
+        # cancel
+        self.btn_cancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+        self.btn_cancel.SetToolTipString(_("Close dialog"))
+        # connect
+        self.btn_connect = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Connect"))
+        self.btn_connect.SetToolTipString(_("Connect to the server"))
+        self.btn_connect.SetDefault()
+        if not self.server.GetValue():
+            self.btn_connect.Enable(False)
+        # import
+        self.btn_import = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
+        self.btn_import.SetToolTipString(_("Import selected layers"))
+        self.btn_import.Enable(False)
+        
+        #
+        # bindings
+        #
+        self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        self.btn_connect.Bind(wx.EVT_BUTTON, self.OnConnect)
+        self.server.Bind(wx.EVT_TEXT, self.OnServer)
+        
+    def __doLayout(self):
+        """!Do dialog layout"""
+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        #
+        # settings
+        #
+        settingsSizer = wx.StaticBoxSizer(self.settingsBox, wx.HORIZONTAL)
+        
+        gridSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
+
+        gridSizer.Add(item=self.serverText,
+                      flag=wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.AddGrowableCol(1)
+        gridSizer.Add(item=self.server,
+                      flag=wx.EXPAND | wx.ALL)
+        
+        settingsSizer.Add(item=gridSizer, proportion=1,
+                       flag=wx.EXPAND | wx.ALL)
+        
+        dialogSizer.Add(item=settingsSizer, proportion=0,
+                        flag=wx.ALL | wx.EXPAND, border=5)
+        
+        #
+        # list of layers
+        #
+        layersSizer = wx.StaticBoxSizer(self.layersBox, wx.HORIZONTAL)
+
+        layersSizer.Add(item=self.list, proportion=1,
+                        flag=wx.ALL | wx.EXPAND, border=5)
+        
+        dialogSizer.Add(item=layersSizer, proportion=1,
+                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
+
+        dialogSizer.Add(item=self.add, proportion=0,
+                        flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
+        
+        #
+        # buttons
+        #
+        btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL)
+
+        btnsizer.Add(item=self.btn_cancel, proportion=0,
+                     flag=wx.ALL | wx.ALIGN_CENTER,
+                     border=10)
+        
+        btnsizer.Add(item=self.btn_connect, proportion=0,
+                     flag=wx.ALL | wx.ALIGN_CENTER,
+                     border=10)
+        
+        btnsizer.Add(item=self.btn_import, proportion=0,
+                     flag=wx.ALL | wx.ALIGN_CENTER,
+                     border=10)
+        
+        dialogSizer.Add(item=btnsizer, proportion=0,
+                        flag=wx.ALIGN_CENTER)
+        
+        self.panel.SetAutoLayout(True)
+        self.panel.SetSizer(dialogSizer)
+        dialogSizer.Fit(self.panel)
+        self.Layout()
+
+    def OnCancel(self, event):
+        """!Button 'Cancel' pressed -> close the dialog"""
+        self.Close()
+
+    def OnConnect(self, event):
+        """!Button 'Connect' pressed"""
+        server = self.server.GetValue()
+        if not server:
+            self.btn_import.Enable(False)
+            return # not reachable
+
+        layers = {}
+        ret = RunCommand('r.in.wms',
+                         quiet = True,
+                         parent = self,
+                         read = True,
+                         flags = 'l',
+                         mapserver = server)
+        
+        if not ret:
+            self.list.LoadData()
+            self.btn_import.Enable(False)
+            return # no layers found
+        
+        lastLayer = lastStyle = ''
+        for line in ret.splitlines():
+            try:
+                key, value = line.split(':', 1)
+            except ValueError:
+                continue
+            key = key.strip().lower()
+            value = value.strip()
+            
+            if key == 'layer':
+                layers[value] = {}
+                lastLayer = value
+            elif key == 'title':
+                layers[lastLayer][key] = value
+            elif key == 'style':
+                if 'style' not in layers[lastLayer]:
+                    layers[lastLayer]['style'] = {}
+                layers[lastLayer]['style'][value] = ''
+                lastStyle = value
+            elif key == 'style title':
+                layers[lastLayer]['style'][lastStyle] = value
+        
+        # update list of layers
+        self.list.LoadData(layers)
+        
+        if len(layers.keys()) > 0:
+            self.btn_import.Enable(True)
+        else:
+            self.btn_import.Enable(False)
+        
+    def OnServer(self, event):
+        """!Server settings changed"""
+        value = event.GetString()
+        if value:
+            self.btn_connect.Enable(True)
+        else:
+            self.btn_connect.Enable(False)
+        
+    def GetLayers(self):
+        """!Get list of selected layers/styles to be imported"""
+        return self.list.GetSelectedLayers()
+
+    def GetSettings(self):
+        """!Get connection settings"""
+        return { 'server' : self.server.GetValue() }
+    
+class LayersList(TreeListCtrl, listmix.ListCtrlAutoWidthMixin):
+    def __init__(self, parent, pos=wx.DefaultPosition):
+        """!List of layers to be imported (dxf, shp...)"""
+        self.parent = parent
+        
+        TreeListCtrl.__init__(self, parent, wx.ID_ANY,
+                              style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT |
+                              wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_MULTIPLE)
+        
+        # setup mixins
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        
+        self.AddColumn(_('Layer / Style'))
+        self.AddColumn(_('Title'))
+        self.SetMainColumn(0) # column with the tree
+        self.SetColumnWidth(0, 175)
+        
+        self.root = None
+        
+    def LoadData(self, data = {}):
+        """!Load data into list"""
+        # detete first all items
+        self.DeleteAllItems()
+        self.root = self.AddRoot(_("Layers"))
+
+        layers = data.keys()
+        if not layers:
+            return
+        
+        layers.sort()
+
+        for layer in layers:
+            title = data[layer]['title']
+            lchild = self.AppendItem(self.root, layer)
+            self.SetItemText(lchild, title, 1)
+            if 'style' in data[layer]:
+                styles = data[layer]['style'].keys()
+                if not styles:
+                    continue
+                styles.sort()
+                for style in styles:
+                    title = data[layer]['style'][style]
+                    schild = self.AppendItem(lchild, style)
+                    self.SetItemText(schild, title, 1)
+        
+        self.Expand(self.root)
+        
+    def GetItemCount(self):
+        """!Required for listmix.ListCtrlAutoWidthMixin"""
+        return 0
+
+    def GetCountPerPage(self):
+        """!Required for listmix.ListCtrlAutoWidthMixin"""
+        return 0
+
+    def GetSelectedLayers(self):
+        """!Get selected layers/styles"""
+        layers = dict()
+
+        for item in self.GetSelections():
+            parent = self.GetItemParent(item)
+            if parent == self.root: # -> layer
+                layer = self.GetItemText(item, 0)
+                layers[layer] = list()
+                sitem, cookie = self.GetFirstChild(item)
+                while sitem:
+                    layers[layer].append(self.GetItemText(sitem, 0))
+                    sitem, cookie = self.GetNextChild(item, cookie)
+            else: # -> style
+                layer = self.GetItemText(parent, 0)
+                layers[layer] = list()
+                layers[layer].append(self.GetItemText(item, 0))
+        
+        return layers

Copied: grass/trunk/gui/wxpython/modules/vclean.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/vclean.py)
===================================================================
--- grass/trunk/gui/wxpython/modules/vclean.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/modules/vclean.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,538 @@
+"""
+ at package modules.vclean
+
+ at brief Dialog for interactive construction of vector cleaning
+operations
+
+Classes:
+ - VectorCleaningFrame
+
+(C) 2010-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+
+import wx
+import wx.lib.scrolledpanel as scrolled
+
+from grass.script import core as grass
+
+from core.gcmd        import RunCommand
+from core             import globalvar
+from gui_core.gselect import Select
+from core.debug       import Debug
+from core.settings    import UserSettings
+
+class VectorCleaningFrame(wx.Frame):
+    def __init__(self, parent, id = wx.ID_ANY, title = _('Set up vector cleaning tools'),
+                 style = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
+                 **kwargs):
+        """!
+        Dialog for interactively defining vector cleaning tools
+        """
+        wx.Frame.__init__(self, parent, id, title, pos, size, style)
+
+        self.parent = parent # GMFrame
+        if self.parent:
+            self.log = self.parent.GetLogWindow()
+        else:
+            self.log = None
+  
+        # grass command
+        self.cmd = 'v.clean'
+        
+        # statusbar
+        self.CreateStatusBar()
+
+	# icon
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+	# self.panel not set as in colorrules
+        # self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+        
+        # input map to clean
+        self.inmap = ''
+        
+        # cleaned output map
+        self.outmap = ''
+
+	self.ftype = ''
+
+        # cleaning tools
+        self.toolslines = {}
+
+        self.tool_desc_list = [
+            _('break lines/boundaries'),
+            _('remove duplicates'),
+            _('remove dangles'),
+            _('change boundary dangles to lines'),
+            _('remove bridges'),
+	    _('change bridges to lines'),
+	    _('snap lines/boundaries'),
+	    _('remove duplicate area centroids'),
+	    _('break polygons'),
+	    _('prune lines/boundaries'),
+	    _('remove small areas'),
+	    _('remove lines/boundaries of zero length'),
+	    _('remove small angles at nodes')
+	    ]
+
+        self.tool_list = [
+            'break',
+            'rmdupl',
+            'rmdangle',
+            'chdangle',
+            'rmbridge',
+	    'chbridge',
+	    'snap',
+	    'rmdac',
+	    'bpol',
+	    'prune',
+	    'rmarea',
+	    'rmline',
+	    'rmsa'
+	    ]
+
+	self.ftype = [
+	    'point',
+	    'line',
+	    'boundary',
+	    'centroid',
+	    'area',
+	    'face']
+
+	self.n_ftypes = 6
+        
+	self.tools_string = ''
+	self.thresh_string = ''
+	self.ftype_string = ''
+
+	self.SetTitle(_('Set up vector cleaning tools'))
+	self.SetStatusText(_("Set up vector cleaning tools"))
+	self.elem = 'vector'
+	self.ctlabel = _('Choose cleaning tools and set thresholds')
+
+        # top controls
+        self.inmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                         label= _('Select input vector map:'))
+        self.selectionInput = Select(parent=self, id=wx.ID_ANY,
+                                     size=globalvar.DIALOG_GSELECT_SIZE,
+                                     type='vector')
+	self.ftype_check = {}
+        ftypeBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
+                                label=_(' Feature type: '))
+        self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL)
+
+        self.outmaplabel = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                         label= _('Select output vector map:'))
+        self.selectionOutput = Select(parent=self, id=wx.ID_ANY,
+                                      size=globalvar.DIALOG_GSELECT_SIZE,
+                                      type='vector')
+        
+        self.overwrite = wx.CheckBox(parent=self, id=wx.ID_ANY,
+                                       label=_('Allow output files to overwrite existing files'))
+        self.overwrite.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
+
+        # cleaning tools
+        self.ct_label = wx.StaticText(parent=self, id=wx.ID_ANY,
+                                      label=self.ctlabel)
+
+        self.ct_panel = self.__toolsPanel()
+
+	# buttons to manage cleaning tools
+        self.btn_add = wx.Button(parent=self, id=wx.ID_ADD)
+        self.btn_remove = wx.Button(parent=self, id=wx.ID_REMOVE)
+        self.btn_moveup = wx.Button(parent=self, id=wx.ID_UP)
+        self.btn_movedown = wx.Button(parent=self, id=wx.ID_DOWN)
+
+        # add one tool as default
+        self.AddTool()
+	self.selected = -1
+        
+        # Buttons
+        self.btn_close = wx.Button(parent = self, id = wx.ID_CLOSE)
+        self.btn_run = wx.Button(parent = self, id = wx.ID_ANY, label = _("&Run"))
+        self.btn_run.SetDefault()
+	self.btn_clipboard = wx.Button(parent=self, id=wx.ID_COPY)
+	self.btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard (Ctrl+C)"))
+        self.btn_help = wx.Button(parent = self, id = wx.ID_HELP)
+        
+        # bindings
+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
+        self.btn_run.Bind(wx.EVT_BUTTON, self.OnCleaningRun)
+	self.btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
+        self.btn_help.Bind(wx.EVT_BUTTON, self.OnHelp)
+
+        self.btn_add.Bind(wx.EVT_BUTTON, self.OnAddTool)
+        self.btn_remove.Bind(wx.EVT_BUTTON, self.OnClearTool)
+        self.btn_moveup.Bind(wx.EVT_BUTTON, self.OnMoveToolUp)
+        self.btn_movedown.Bind(wx.EVT_BUTTON, self.OnMoveToolDown)
+
+        self.SetMinSize(self.GetBestSize())
+
+        # layout
+        self._layout()
+
+        self.CentreOnScreen()
+        self.Show()
+        
+    def _layout(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        #
+        # input output
+        #
+	inSizer = wx.GridBagSizer(hgap=5, vgap=5)
+
+        inSizer.Add(item=self.inmaplabel, pos=(0, 0),
+                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
+        inSizer.Add(item=self.selectionInput, pos=(1, 0),
+                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
+
+	self.ftype_check = [
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('point')),
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('line')),
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('boundary')),
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('centroid')),
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('area')),
+	    wx.CheckBox(parent=self, id=wx.ID_ANY, label=_('face'))
+	    ]
+
+	typeoptSizer = wx.BoxSizer(wx.HORIZONTAL)
+	for num in range(0, self.n_ftypes):
+	    type_box = self.ftype_check[num]
+	    typeoptSizer.Add(item=type_box, flag=wx.ALIGN_LEFT, border=1)
+
+	self.ftypeSizer.Add(item = typeoptSizer,
+	           flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2)
+
+	outSizer = wx.GridBagSizer(hgap=5, vgap=5)
+
+        outSizer.Add(item=self.outmaplabel, pos=(0, 0),
+                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
+        outSizer.Add(item=self.selectionOutput, pos=(1, 0),
+                       flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=1)
+        replaceSizer = wx.BoxSizer(wx.HORIZONTAL)
+        replaceSizer.Add(item=self.overwrite, proportion=1,
+                         flag=wx.ALL | wx.EXPAND, border=1)
+
+        outSizer.Add(item=replaceSizer, pos=(2, 0),
+                       flag=wx.ALL | wx.EXPAND, border=1)
+
+        #
+        # tools selection
+        #
+        bodySizer = wx.GridBagSizer(hgap=5, vgap=5)
+
+        bodySizer.Add(item=self.ct_label, pos=(0, 0), span=(1, 2),
+                      flag=wx.ALL, border=5)
+
+        bodySizer.Add(item=self.ct_panel, pos=(1, 0), span=(1, 2))
+
+	manageBoxSizer = wx.GridBagSizer(hgap=10, vgap=1)
+	# start with row 1 for nicer layout
+        manageBoxSizer.Add(item=self.btn_add, pos=(1, 0), border=2, flag=wx.ALL | wx.EXPAND)
+        manageBoxSizer.Add(item=self.btn_remove, pos=(2, 0), border=2, flag=wx.ALL | wx.EXPAND)
+        manageBoxSizer.Add(item=self.btn_moveup, pos=(3, 0), border=2, flag=wx.ALL | wx.EXPAND)
+        manageBoxSizer.Add(item=self.btn_movedown, pos=(4, 0), border=2, flag=wx.ALL | wx.EXPAND)
+
+        bodySizer.Add(item=manageBoxSizer, pos=(1, 2),
+                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
+
+        bodySizer.AddGrowableCol(2)
+        
+        #
+        # standard buttons
+        #
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(self.btn_close,
+                     flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(self.btn_run,
+                     flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(self.btn_clipboard,
+                     flag=wx.LEFT | wx.RIGHT, border=5)
+        btnSizer.Add(self.btn_help,
+                     flag=wx.LEFT | wx.RIGHT, border=5)
+        
+        #
+        # put it all together
+        #
+        sizer.Add(item=inSizer, proportion=0,
+                  flag=wx.ALL | wx.EXPAND, border=5)
+        
+        sizer.Add(item=self.ftypeSizer, proportion=0,
+                  flag=wx.ALL | wx.EXPAND, border=5)
+
+        sizer.Add(item=outSizer, proportion=0,
+                  flag=wx.ALL | wx.EXPAND, border=5)
+
+        sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
+                  style=wx.LI_HORIZONTAL), proportion=0,
+                  flag=wx.EXPAND | wx.ALL, border=5) 
+        
+        sizer.Add(item=bodySizer, proportion=1,
+                  flag=wx.ALL | wx.EXPAND, border=5)
+
+        sizer.Add(item=wx.StaticLine(parent=self, id=wx.ID_ANY,
+                  style=wx.LI_HORIZONTAL), proportion=0,
+                  flag=wx.EXPAND | wx.ALL, border=5) 
+        
+        sizer.Add(item=btnSizer, proportion=0,
+                  flag=wx.ALL | wx.ALIGN_RIGHT, border=5)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+        self.Layout()
+        
+    def __toolsPanel(self):
+        ct_panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY,
+	                                  size=(500, 240),
+                                          style=wx.SUNKEN_BORDER)
+
+        self.ct_sizer = wx.GridBagSizer(vgap=2, hgap=4)
+        
+        ct_panel.SetSizer(self.ct_sizer)
+        ct_panel.SetAutoLayout(True)
+        
+        return ct_panel        
+
+    def OnAddTool(self, event):
+        """!Add tool button pressed"""
+	self.AddTool()
+
+    def AddTool(self):
+        snum = len(self.toolslines.keys())
+	num = snum + 1
+	# tool number
+	tool_no = wx.StaticText(parent = self.ct_panel, id = 3000+num,
+                                         label= str(num)+'.')
+	# tool
+	tool_cbox = wx.ComboBox(parent = self.ct_panel, id=1000+num, 
+				size = (300, -1), choices = self.tool_desc_list,
+				style = wx.CB_DROPDOWN |
+				wx.CB_READONLY | wx.TE_PROCESS_ENTER)
+	self.Bind(wx.EVT_COMBOBOX, self.OnSetTool, tool_cbox)
+	# threshold
+	txt_ctrl = wx.TextCtrl(parent=self.ct_panel, id=2000+num, value='0.00',
+			       size=(100,-1),
+			       style=wx.TE_NOHIDESEL)
+	self.Bind(wx.EVT_TEXT, self.OnThreshValue, txt_ctrl)
+
+	# select
+	select = wx.CheckBox(parent=self.ct_panel, id=num)
+	select.SetValue(False)
+	self.Bind(wx.EVT_CHECKBOX, self.OnSelect, select)
+
+	# start with row 1 and col 1 for nicer layout
+	self.ct_sizer.Add(item=tool_no, pos=(num, 1),
+			  flag=wx.ALIGN_CENTER_VERTICAL, border=5)
+	self.ct_sizer.Add(item=tool_cbox, pos=(num, 2),
+			  flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
+	self.ct_sizer.Add(item=txt_ctrl, pos=(num, 3),
+			  flag=wx.ALIGN_CENTER | wx.RIGHT, border=5)
+	self.ct_sizer.Add(item=select, pos=(num, 4),
+			  flag=wx.ALIGN_CENTER | wx.RIGHT)
+
+	self.toolslines[num] = {
+	    'tool_desc' : '' ,
+	    'tool' : '' ,
+	    'thresh' : '0.00' }
+        
+        self.ct_panel.Layout()
+        self.ct_panel.SetupScrolling()
+        
+    def OnClearTool(self, event):
+        """!Remove tool button pressed"""
+        id = self.selected
+
+	if id > 0:
+	    self.FindWindowById(id+1000).SetValue('')
+	    self.toolslines[id]['tool_desc'] = ''
+	    self.toolslines[id]['tool'] = ''
+	    self.SetStatusText(_("%s. cleaning tool removed, will be ignored") % id)
+	else:
+	    self.SetStatusText(_("Please select a cleaning tool to remove"))
+
+    def OnMoveToolUp(self, event):
+        """!Move up tool button pressed"""
+        id = self.selected
+
+	if id > 1:
+	    id_up = id - 1
+	    this_toolline = self.toolslines[id]
+	    up_toolline = self.toolslines[id_up]
+	    
+	    self.FindWindowById(id_up).SetValue(True)
+	    self.FindWindowById(id_up+1000).SetValue(this_toolline['tool_desc'])
+	    self.FindWindowById(id_up+2000).SetValue(this_toolline['thresh'])
+	    self.toolslines[id_up] = this_toolline
+	    
+	    self.FindWindowById(id).SetValue(False)
+	    self.FindWindowById(id+1000).SetValue(up_toolline['tool_desc'])
+	    self.FindWindowById(id+2000).SetValue(up_toolline['thresh'])
+	    self.toolslines[id] = up_toolline
+	    self.selected = id_up
+	    self.SetStatusText(_("%s. cleaning tool moved up") % id)
+	elif id == 1:
+	    self.SetStatusText(_("1. cleaning tool can not be moved up "))
+	elif id == -1:
+	    self.SetStatusText(_("Please select a cleaning tool to move up"))
+
+
+    def OnMoveToolDown(self, event):
+        """!Move down tool button pressed"""
+        id = self.selected
+        snum = len(self.toolslines.keys())
+
+	if id > 0 and id < snum:
+	    id_down = id + 1
+	    this_toolline = self.toolslines[id]
+	    down_toolline = self.toolslines[id_down]
+	    
+	    self.FindWindowById(id_down).SetValue(True)
+	    self.FindWindowById(id_down+1000).SetValue(this_toolline['tool_desc'])
+	    self.FindWindowById(id_down+2000).SetValue(this_toolline['thresh'])
+	    self.toolslines[id_down] = this_toolline
+	    
+	    self.FindWindowById(id).SetValue(False)
+	    self.FindWindowById(id+1000).SetValue(down_toolline['tool_desc'])
+	    self.FindWindowById(id+2000).SetValue(down_toolline['thresh'])
+	    self.toolslines[id] = down_toolline
+	    self.selected = id_down
+	    self.SetStatusText(_("%s. cleaning tool moved down") % id)
+	elif id == snum:
+	    self.SetStatusText(_("Last cleaning tool can not be moved down "))
+	elif id == -1:
+	    self.SetStatusText(_("Please select a cleaning tool to move down"))
+
+    def OnSetTool(self, event):
+        """!Tool was defined"""
+        id = event.GetId()
+	tool_no = id-1000
+	num = self.FindWindowById(id).GetCurrentSelection()
+
+	self.toolslines[tool_no]['tool_desc'] = self.tool_desc_list[num]
+	self.toolslines[tool_no]['tool'] = self.tool_list[num]
+
+	self.SetStatusText( str(tool_no) + '. ' + _("cleaning tool: '%s'") % (self.tool_list[num]))
+
+    def OnThreshValue(self, event):
+        """!Threshold value was entered"""
+        id = event.GetId()
+	num = id-2000
+	self.toolslines[num]['thresh'] = self.FindWindowById(id).GetValue()
+
+	self.SetStatusText(_("Threshold for %(num)s. tool '%(tool)s': %(thresh)s") % \
+                               { 'num' : num,
+                                 'tool' : self.toolslines[num]['tool'],
+                                 'thresh' : self.toolslines[num]['thresh'] })
+
+    def OnSelect(self, event):
+        """!Tool was selected"""
+        id = event.GetId()
+
+	if self.selected > -1 and self.selected != id:
+	    win = self.FindWindowById(self.selected)
+	    win.SetValue(False)
+
+	if self.selected != id:
+	    self.selected = id
+	else:
+	    self.selected = -1
+
+    def OnCleaningRun(self, event):
+        """!Builds options and runs v.clean
+        """
+	self.SetStatusText(_("Executing selected cleaning operations..."))
+        snum = len(self.toolslines.keys())
+	self.GetCmdStrings()
+
+        if self.log:
+	    cmd = [ self.cmd,
+                    'input=%s' % self.inmap,
+                    'output=%s' % self.outmap,
+                    'tool=%s' % self.tools_string,
+                    'thres=%s' % self.thresh_string ]
+            if self.ftype_string:
+                cmd.append('type=%s' % self.ftype_string)
+	    if self.overwrite.IsChecked():
+		cmd.append('--overwrite')
+            
+            self.log.RunCmd(cmd)
+            self.parent.Raise()
+        else:
+	    if self.overwrite.IsChecked():
+		overwrite = True
+	    else:
+		overwrite = False
+            
+	    RunCommand(self.cmd,
+                       input = self.inmap,
+                       output = self.outmap,
+                       type = self.ftype_string,
+                       tool = self.tools_string,
+                       thresh = self.thresh_string,
+                       overwrite = overwrite)
+
+    def OnClose(self, event):
+        self.Destroy()
+        
+    def OnHelp(self, event):
+        """!Show GRASS manual page"""
+        RunCommand('g.manual',
+                   quiet = True,
+                   parent = self,
+                   entry = self.cmd)
+        
+    def OnCopy(self, event):
+        """!Copy the command"""
+        cmddata = wx.TextDataObject()
+	# get tool and thresh strings
+	self.GetCmdStrings()
+        cmdstring = '%s' % (self.cmd)
+        # list -> string
+        cmdstring += ' input=%s output=%s type=%s tool=%s thres=%s' % \
+	    (self.inmap, self.outmap, self.ftype_string, self.tools_string, self.thresh_string)
+	if self.overwrite.IsChecked():
+	    cmdstring += ' --overwrite'
+ 
+        cmddata.SetText(cmdstring)
+        if wx.TheClipboard.Open():
+            wx.TheClipboard.SetData(cmddata)
+            wx.TheClipboard.Close()
+            self.SetStatusText(_("Vector cleaning command copied to clipboard"))
+
+    def GetCmdStrings(self):
+	self.tools_string = ''
+	self.thresh_string = ''
+	self.ftype_string = ''
+	# feature types
+	first = 1
+        for num in range(0, self.n_ftypes - 1):
+	    if self.ftype_check[num].IsChecked():
+		if first:
+		    self.ftype_string = '%s' % self.ftype[num]
+		    first = 0
+		else:
+		    self.ftype_string += ',%s' % self.ftype[num]
+		    
+	    
+	# cleaning tools
+	first = 1
+        snum = len(self.toolslines.keys())
+        for num in range(1, snum + 1):
+	    if self.toolslines[num]['tool']:
+		if first:
+		    self.tools_string = '%s' % self.toolslines[num]['tool']
+		    self.thresh_string = '%s' % self.toolslines[num]['thresh']
+		    first = 0
+		else:
+		    self.tools_string += ',%s' % self.toolslines[num]['tool']
+		    self.thresh_string += ',%s' % self.toolslines[num]['thresh']
+
+	self.inmap = self.selectionInput.GetValue()
+	self.outmap = self.selectionOutput.GetValue()

Copied: grass/trunk/gui/wxpython/nviz/animation.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/nviz_animation.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/animation.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/animation.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,208 @@
+"""!
+ at package nviz.animation
+
+ at brief Nviz (3D view) animation
+
+Classes:
+ - Animation
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Anna Kratochvilova <kratochanna gmail.com> 
+"""
+
+import os
+import copy
+
+import wx
+from wx.lib.newevent import NewEvent
+
+wxAnimationFinished,    EVT_ANIM_FIN        = NewEvent()
+wxAnimationUpdateIndex, EVT_ANIM_UPDATE_IDX = NewEvent()
+
+class Animation:
+    """!Class represents animation as a sequence of states (views).
+    It enables to record, replay the sequence and finally generate
+    all image files. Recording and replaying is based on timer events.
+    There is no frame interpolation like in the Tcl/Tk based Nviz.
+    """
+    def __init__(self, mapWindow, timer):
+        """!Animation constructor
+        
+        @param mapWindow glWindow where rendering takes place
+        @param timer timer for recording and replaying
+        """
+        
+        self.animationList = []         # view states
+        self.timer = timer
+        self.mapWindow = mapWindow
+        self.actions = {'record': self.Record,
+                        'play': self.Play}
+        self.formats = ['ppm', 'tif']   # currently supported formats
+        self.mode = 'record'            # current mode (record, play, save)
+        self.paused = False             # recording/replaying paused
+        self.currentFrame = 0           # index of current frame
+        self.fps = 24 # user settings   # Frames per second
+        
+        self.stopSaving = False         # stop during saving images
+        self.animationSaved = False     # current animation saved or not
+        
+    def Start(self):
+        """!Start recording/playing"""
+        self.timer.Start(self.GetInterval())
+        
+    def Pause(self):
+        """!Pause recording/playing"""
+        self.timer.Stop()
+        
+    def Stop(self):
+        """!Stop recording/playing"""
+        self.timer.Stop()
+        self.PostFinishedEvent()
+        
+    def Update(self):
+        """!Record/play next view state (on timer event)"""
+        self.actions[self.mode]()
+    
+    def Record(self):
+        """!Record new view state"""
+        self.animationList.append({'view' : copy.deepcopy(self.mapWindow.view),
+                                   'iview': copy.deepcopy(self.mapWindow.iview)})
+        self.currentFrame += 1
+        self.PostUpdateIndexEvent(index = self.currentFrame)
+        self.animationSaved = False
+        
+    def Play(self):
+        """!Render next frame"""
+        if not self.animationList:
+            self.Stop()
+            return
+        try:
+            self.IterAnimation()
+        except IndexError:
+            # no more frames
+            self.Stop()
+            
+    def IterAnimation(self):
+        params = self.animationList[self.currentFrame]
+        self.UpdateView(params)
+        self.currentFrame += 1
+        
+        self.PostUpdateIndexEvent(index = self.currentFrame)
+        
+    def UpdateView(self, params):
+        """!Update view data in map window and render"""
+        toolWin = self.mapWindow.GetToolWin()
+        toolWin.UpdateState(view = params['view'], iview = params['iview'])
+        
+        self.mapWindow.UpdateView()
+        
+        self.mapWindow.render['quick'] = True
+        self.mapWindow.Refresh(False)
+        
+    def IsRunning(self):
+        """!Test if timer is running"""
+        return self.timer.IsRunning()
+        
+    def SetMode(self, mode):
+        """!Start animation mode
+        
+        @param mode animation mode (record, play, save)
+        """
+        self.mode = mode
+        
+    def GetMode(self):
+        """!Get animation mode (record, play, save)"""
+        return self.mode
+        
+    def IsPaused(self):
+        """!Test if animation is paused"""
+        return self.paused
+        
+    def SetPause(self, pause):
+        self.paused = pause
+        
+    def Exists(self):
+        """!Returns if an animation has been recorded"""
+        return bool(self.animationList)
+        
+    def GetFrameCount(self):
+        """!Return number of recorded frames"""
+        return len(self.animationList)
+        
+    def Clear(self):
+        """!Clear all records"""
+        self.animationList = []
+        self.currentFrame = 0
+        
+    def GoToFrame(self, index):
+        """!Render frame of given index"""
+        if index >= len(self.animationList):
+            return
+            
+        self.currentFrame = index
+        params = self.animationList[self.currentFrame]
+        self.UpdateView(params)
+        
+    def PostFinishedEvent(self):
+        """!Animation ends"""
+        toolWin = self.mapWindow.GetToolWin()
+        event = wxAnimationFinished(mode = self.mode)
+        wx.PostEvent(toolWin, event)
+        
+    def PostUpdateIndexEvent(self, index):
+        """!Frame index changed, update tool window"""
+        toolWin = self.mapWindow.GetToolWin()
+        event = wxAnimationUpdateIndex(index = index, mode = self.mode)
+        wx.PostEvent(toolWin, event)
+        
+    def StopSaving(self):
+        """!Abort image files generation"""
+        self.stopSaving = True
+        
+    def IsSaved(self):
+        """"!Test if animation has been saved (to images)"""
+        return self.animationSaved
+        
+    def SaveAnimationFile(self, path, prefix, format):
+        """!Generate image files
+        
+        @param path path to direcory
+        @param prefix file prefix
+        @param format index of image file format
+        """
+        w, h = self.mapWindow.GetClientSizeTuple()
+        toolWin = self.mapWindow.GetToolWin()
+        
+        self.currentFrame = 0
+        self.mode = 'save'
+        for params in self.animationList:
+            if not self.stopSaving:
+                self.UpdateView(params)
+                filename = prefix + "_" + str(self.currentFrame) + '.' + self.formats[format]
+                filepath = os.path.join(path, filename)
+                self.mapWindow.SaveToFile(FileName = filepath, FileType = self.formats[format],
+                                                  width = w, height = h)
+                self.currentFrame += 1
+                
+                wx.Yield()
+                toolWin.UpdateFrameIndex(index = self.currentFrame, goToFrame = False)
+            else:
+                self.stopSaving = False
+                break
+        self.animationSaved = True
+        self.PostFinishedEvent()
+
+    def SetFPS(self, fps):
+        """!Set Frames Per Second value
+        @param fps frames per second
+        """
+        self.fps = fps
+    
+    def GetInterval(self):
+        """!Return timer interval in ms"""
+        return 1000. / self.fps


Property changes on: grass/trunk/gui/wxpython/nviz/animation.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/nviz/main.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/nviz.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/main.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/main.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,37 @@
+"""!
+ at package nviz.main
+
+ at brief Nviz (3D view) module
+
+This module implements 3D visualization mode for map display.
+
+Map Display supports standard 2D view mode ('mapdisp' module) and
+2.5/3D mode ('nviz_mapdisp' module).
+
+(C) 2008, 2010-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
+"""
+
+errorMsg = ''
+
+try:
+    from wx import glcanvas
+    import nviz.mapdisp
+    import nviz.tools
+    import wxnviz
+    haveNviz = True
+except ImportError, err:
+    haveNviz = False
+    errorMsg = err
+
+if haveNviz:
+    GLWindow       = nviz.mapdisp.GLWindow
+    NvizToolWindow = nviz.tools.NvizToolWindow
+else:
+    GLWindow       = None
+    NvizToolWindow = None

Copied: grass/trunk/gui/wxpython/nviz/mapwindow.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/nviz_mapdisp.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/mapwindow.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/mapwindow.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2514 @@
+"""!
+ at package nviz.mapwindow
+
+ at brief wxGUI 3D view mode (map canvas)
+
+This module implements 3D visualization mode for map display.
+
+List of classes:
+ - NvizThread
+ - GLWindow
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
+"""
+
+import os
+import sys
+import time
+import copy
+import math
+import types
+
+from threading import Thread
+
+import wx
+from   wx.lib.newevent import NewEvent
+from   wx              import glcanvas
+
+import grass.script as grass
+
+from core.gcmd        import GMessage, GException, GError
+from core.debug       import Debug
+from mapdisp.window   import MapWindow
+from gui_core.goutput import wxCmdOutput
+from core.settings    import UserSettings
+from nviz.workspace   import NvizSettings
+from nviz.animation   import Animation
+
+import nviz.wxcore as wxnviz
+
+wxUpdateProperties, EVT_UPDATE_PROP  = NewEvent()
+wxUpdateView,       EVT_UPDATE_VIEW  = NewEvent()
+wxUpdateLight,      EVT_UPDATE_LIGHT = NewEvent()
+wxUpdateCPlane,     EVT_UPDATE_CPLANE = NewEvent()
+
+class NvizThread(Thread):
+    def __init__(self, log, progressbar, window):
+        Thread.__init__(self)
+        Debug.msg(5, "NvizThread.__init__():")
+        self.log = log
+        self.progressbar = progressbar
+        self.window = window
+        
+        self._display = None
+        
+        self.setDaemon(True)
+
+    def run(self):
+        self._display = wxnviz.Nviz(self.log, self.progressbar)
+        
+    def GetDisplay(self):
+        """!Get display instance"""
+        return self._display
+
+class GLWindow(MapWindow, glcanvas.GLCanvas):
+    """!OpenGL canvas for Map Display Window"""
+    def __init__(self, parent, id = wx.ID_ANY,
+                 Map = None, tree = None, lmgr = None):
+        self.parent = parent # MapFrame
+        
+        glcanvas.GLCanvas.__init__(self, parent, id)
+        MapWindow.__init__(self, parent, id, 
+                           Map, tree, lmgr)
+        self.Hide()
+        
+        self.init = False
+        self.initView = False
+        
+        # render mode 
+        self.render = { 'quick' : False,
+                        # do not render vector lines in quick mode
+                        'vlines' : False,
+                        'vpoints' : False,
+                        'overlays': False }
+        self.mouse = {
+            'use': 'pointer'
+            }
+        self.cursors = {
+            'default' : wx.StockCursor(wx.CURSOR_ARROW),
+            'cross'   : wx.StockCursor(wx.CURSOR_CROSS),
+            }
+        # list of loaded map layers (layer tree items)
+        self.layers  = list()
+        # list of constant surfaces
+        self.constants = list()
+        # id of base surface (when vector is loaded and no surface exist)
+        self.baseId = -1
+        # list of cutting planes
+        self.cplanes = list()
+        # list of query points
+        self.qpoints = list()
+        # list of past views
+        self.viewhistory  = []
+        self.saveHistory = False
+        # offset for dialog (e.g. DisplayAttributesDialog)
+        self.dialogOffset = 5
+        # overlays
+        self.overlays = {}
+        self.imagelist = []
+        self.overlay = wx.Overlay()
+        #self.pdc = wx.PseudoDC()
+        self.textdict = {}
+        self.dragid = -1
+        self.hitradius = 5
+        # layer manager toolwindow
+        self.toolWin = None
+        
+        if self.lmgr:
+            self.log = self.lmgr.goutput
+            logerr = self.lmgr.goutput.GetLog(err = True)
+            logmsg = self.lmgr.goutput.GetLog()
+        else:
+            self.log = logmsg = sys.stdout
+            logerr = sys.stderr
+        
+        # create nviz instance - use display region instead of computational
+        os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
+        
+        self.nvizThread = NvizThread(logerr,
+                                     self.parent.GetProgressBar(),
+                                     logmsg)
+        self.nvizThread.start()
+        time.sleep(.1)
+        self._display = self.nvizThread.GetDisplay()
+        
+        # GRASS_REGION needed only for initialization
+        del os.environ['GRASS_REGION']
+        
+        self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
+        
+        # size of MapWindow, to avoid resizing if size is the same
+        self.size = (0, 0)
+        
+        # default values
+        self.nvizDefault = NvizSettings()
+        self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
+        self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True)
+        self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
+        self.decoration = self.nvizDefault.SetDecorDefaultProp(type = 'arrow')
+        self.decoration['scalebar'] = []
+        self.decoration['arrow']['size'] = self._getDecorationSize()
+        self.fly = self.InitFly()
+        
+        # timer for flythrough
+        self.timerFly = wx.Timer(self, id = wx.NewId())
+        # timer for animations
+        self.timerAnim = wx.Timer(self, id = wx.NewId())
+        self.animation = Animation(mapWindow = self, timer = self.timerAnim)        
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+        self.Bind(wx.EVT_SIZE,             self.OnSize)
+        self.Bind(wx.EVT_PAINT,            self.OnPaint)
+        self._bindMouseEvents()
+        
+        self.Bind(EVT_UPDATE_PROP,   self.UpdateMapObjProperties)
+        self.Bind(EVT_UPDATE_VIEW,   self.OnUpdateView)
+        self.Bind(EVT_UPDATE_LIGHT,  self.UpdateLight)
+        self.Bind(EVT_UPDATE_CPLANE, self.UpdateCPlane)
+        
+        self.Bind(wx.EVT_TIMER, self.OnTimerAnim, self.timerAnim)
+        self.Bind(wx.EVT_TIMER, self.OnTimerFly, self.timerFly)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+        
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        
+        # cplanes cannot be initialized now
+        wx.CallAfter(self.InitCPlanes)
+
+    def InitFly(self):
+        """!Initialize fly through dictionary"""
+        fly = {'interval' : 10,             # interval for timerFly
+               'value': [0, 0, 0],          # calculated values for navigation
+               'mode' : 0,                  # fly through mode (0, 1)
+               'exag' : {                   # sensitivity
+                    'move' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'move']),
+                    'turn' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'turn'])},
+               'exagMultiplier' : 3,        # speed up by Shift
+               'flySpeed' : 4,              # speed of flying
+               'mouseControl' : None,       # if mouse or keys are used
+               'pos' : {'x' : 0, 'y' : 0},  # virtual mouse position when using arrows
+               'arrowStep' : 50,            # step in pixels (when using arrows)
+               'flySpeedStep' : 2,
+            }
+            
+        return fly
+        
+    def OnTimerFly(self, event):
+        """!Fly event was emitted, move the scene"""
+        if self.mouse['use'] != 'fly':
+            return
+        
+        if self.fly['mouseControl']:
+            mx, my = self.ComputeMxMy(*self.mouse['tmp'])
+        else:
+            mx, my = self.ComputeMxMy(self.fly['pos']['x'], self.fly['pos']['y'])
+            
+        self.ComputeFlyValues(mx = mx, my = my)
+        self._display.FlyThrough(flyInfo = self.fly['value'], mode = self.fly['mode'],
+                                 exagInfo = self.fly['exag'])
+        self.ChangeInnerView()                                 
+        self.render['quick'] = True
+        self.Refresh(False)
+        
+    def ComputeMxMy(self, x, y):
+        """!Compute values for flythrough navigation 
+        (ComputeFlyValues should follow). 
+        
+        Based on visualization/nviz/src/togl_flythrough.c.
+        @param x,y screen coordinates
+        """
+        sx, sy = self.GetClientSizeTuple()
+        dx = dy = 0.01
+        
+        mx = 2 * (float(x) / sx) - 1
+        my = 2 * (float(y) / sy) - 1
+    
+        if mx < - dx:
+            mx += dx
+        elif mx > dx:
+            mx -= dx
+        else:
+            mx = 0.0 # ?
+        if my < - dy:
+            my += dy
+        elif my > dy:
+            my -= dy
+        else:
+            my = 0.0
+    
+        mx = mx / (1.0 - dx)
+        my = my / (1.0 - dy)
+    
+        # Quadratic seems smoother 
+        mx *= abs(mx)
+        my *= abs(my)
+        
+        return mx, my
+        
+    def ComputeFlyValues(self, mx, my):
+        """!Compute parameters for fly-through navigation
+        
+        @params mx,my results from ComputeMxMy method
+        """
+        self.fly['value'] = [0, 0, 0]
+        
+        if self.fly['mode'] == 0:
+            self.fly['value'][0] = self.fly['flySpeed'] * self.fly['interval'] / 1000. # forward */
+            self.fly['value'][1] = mx * 0.1 * self.fly['interval'] / 1000. # heading 
+            self.fly['value'][2] = my * 0.1 * self.fly['interval'] / 1000. # pitch 
+        else:
+            self.fly['value'][0] = mx * 100.0 * self.fly['interval'] /1000.
+            self.fly['value'][2] = - my * 100.0 * self.fly['interval'] /1000.
+    
+    def ChangeFlySpeed(self, increase):
+        """!Increase/decrease flight spped"""
+        if increase:
+            self.fly['flySpeed'] += self.fly['flySpeedStep']
+        else:
+            self.fly['flySpeed'] -= self.fly['flySpeedStep']
+        
+    def __del__(self):
+        """!Stop timers if running, unload data"""
+        self.StopTimer(self.timerAnim)
+        self.StopTimer(self.timerFly)
+        self.UnloadDataLayers(force = True)
+    
+    def StopTimer(self, timer):
+        """!Stop timer if running"""
+        if timer.IsRunning():
+            timer.Stop()
+            
+    def _bindMouseEvents(self):
+        self.Bind(wx.EVT_MOUSE_EVENTS,     self.OnMouseAction)
+        self.Bind(wx.EVT_MOTION,           self.OnMotion)
+        
+    def InitCPlanes(self):
+        """!Initialize cutting planes list"""
+        for i in range(self._display.GetCPlanesCount()):
+            cplane = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'cplane'))
+            cplane['on'] = False
+            self.cplanes.append(cplane)
+        
+    def SetToolWin(self, toolWin):
+        """!Sets reference to nviz toolwindow in layer manager"""
+        self.toolWin = toolWin
+        
+    def GetToolWin(self):
+        """!Returns reference to nviz toolwindow in layer manager"""
+        return self.toolWin
+            
+    def OnClose(self, event):
+        self.StopTimer(self.timerAnim)
+        self.StopTimer(self.timerFly)
+        # cleanup when window actually closes (on quit) and not just is hidden
+        self.UnloadDataLayers(force = True)
+        
+    def OnEraseBackground(self, event):
+        pass # do nothing, to avoid flashing on MSW
+    
+    def OnSize(self, event):
+        size = self.GetClientSize()
+        if self.size != size \
+            and self.GetContext():
+            Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \
+                      (size.width, size.height))
+            self.SetCurrent()
+            self._display.ResizeWindow(size.width,
+                                       size.height)
+        
+            # reposition checkbox in statusbar
+            self.parent.StatusbarReposition()
+            
+            # update statusbar
+            self.parent.StatusbarUpdate()
+            
+        self.size = size
+        
+        event.Skip()
+       
+    def OnPaint(self, event):
+        Debug.msg(1, "GLCanvas.OnPaint()")
+        
+        self.render['overlays'] = True
+        dc = wx.PaintDC(self)
+        self.DoPaint()
+        
+
+    def DoPaint(self):
+        self.SetCurrent()
+        
+        if not self.initView:
+            self._display.InitView()
+            self.initView = True
+        
+        self.LoadDataLayers()
+        self.UnloadDataLayers()
+        
+        if not self.init:
+            self.ResetView()
+            
+            if hasattr(self.lmgr, "nviz"):
+                self.lmgr.nviz.UpdatePage('view')
+                self.lmgr.nviz.UpdatePage('light')
+                self.lmgr.nviz.UpdatePage('cplane')
+                self.lmgr.nviz.UpdatePage('decoration')
+                self.lmgr.nviz.UpdatePage('animation')
+                layer = self.GetSelectedLayer()
+                if layer:
+                    if layer.type ==  'raster':
+                        self.lmgr.nviz.UpdatePage('surface')
+                        self.lmgr.nviz.UpdatePage('fringe')
+                    elif layer.type ==  'vector':
+                        self.lmgr.nviz.UpdatePage('vector')
+                
+                self.lmgr.nviz.UpdateSettings()
+                
+                # update widgets
+                win = self.lmgr.nviz.FindWindowById( \
+                    self.lmgr.nviz.win['vector']['lines']['surface'])
+                win.SetItems(self.GetLayerNames('raster'))
+            
+            self.init = True
+        
+        self.UpdateMap()
+        
+    def DrawImages(self):
+        """!Draw overlay image"""
+        for texture in self.imagelist:
+            if texture.IsActive():
+                texture.Draw()
+            
+    def GetLegendRect(self):
+        """!Estimates legend size for dragging"""
+        size = None
+        if 1 in self.overlays:
+            for param in self.overlays[1]['cmd'][1:]:
+                if param.startswith("at="):
+                    size = map(int, param.split("=")[-1].split(','))
+                    break
+        if size:
+            wSize = self.GetClientSizeTuple()
+            x, y = size[2]/100. * wSize[0], wSize[1] - (size[1]/100. * wSize[1])
+            x += self.overlays[1]['coords'][0]
+            y += self.overlays[1]['coords'][1]
+            w = (size[3] - size[2])/100. * wSize[0]
+            h = (size[1] - size[0])/100. * wSize[1]
+            
+            rect = wx.Rect(x, y, w, h)
+            return rect
+        
+        return wx.Rect()        
+        
+    def DrawTextImage(self, textDict, relCoords):
+        """!Draw overlay text"""
+        bmp = wx.EmptyBitmap(textDict['bbox'][2], textDict['bbox'][3])
+        memDC = wx.MemoryDC()
+        memDC.SelectObject(bmp)
+        
+        mask = self.view['background']['color']
+        if mask == textDict['color']:
+            mask = wx.WHITE
+        memDC.SetBackground(wx.Brush(mask))
+        memDC.Clear()
+        memDC.SetFont(textDict['font'])
+        memDC.SetTextForeground(textDict['color'])
+        if textDict['rotation'] == 0:
+            memDC.DrawText(textDict['text'], 0, 0)
+        else:
+            memDC.DrawRotatedText(textDict['text'], relCoords[0], relCoords[1],
+                                  textDict['rotation'])
+        bmp.SetMaskColour(mask)
+        memDC.DrawBitmap(bmp, 0, 0, 1)
+        
+        filename = grass.tempfile(create = False) + '.png'
+        bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
+        memDC.SelectObject(wx.NullBitmap)
+        
+        return filename
+        
+    def UpdateOverlays(self):
+        """!Converts rendered overlay files and text labels to wx.Image
+            and then to textures so that they can be rendered by OpenGL.
+            Updates self.imagelist"""
+        self.Map.ChangeMapSize(self.GetClientSize())
+        self.Map.RenderOverlays(force = True)
+        
+        # delete textures
+        for texture in self.imagelist:
+            # inactive overlays, remove text labels
+            if texture.GetId() < 100:
+                if not self.overlays[texture.GetId()]['layer'].IsActive():
+                    texture.SetActive(False)
+                else:
+                    texture.SetActive(True)
+            else: # text label
+                if texture.GetId() not in self.textdict:
+                    self.imagelist.remove(texture)
+                    
+        # update images (only legend so far)
+        for oid, overlay in self.overlays.iteritems():
+            layer = overlay['layer']
+            if not layer.IsActive() or oid == 0: # 0 for barscale
+                continue
+            if oid not in [t.GetId() for t in self.imagelist]: # new
+                self.CreateTexture(overlay = layer)
+            else:
+                for t in self.imagelist:
+                    if t.GetId() == oid: # check if it is the same
+                        if not t.Corresponds(layer):
+                            self.imagelist.remove(t)
+                            t = self.CreateTexture(overlay = layer)
+                        # always set coordinates, needed for synchr. 2D and 3D modes
+                        t.SetCoords(overlay['coords'])
+
+                    
+        # update text labels
+        for textId in self.textdict.keys():
+            if textId not in [t.GetId() for t in self.imagelist]:# new
+                self.CreateTexture(textId = textId)
+            else:
+                for t in self.imagelist:
+                    if t.GetId() == textId: # check if it is the same
+                        self.textdict[textId]['bbox'] = t.textDict['bbox']
+                        if not t.Corresponds(self.textdict[textId]):
+                            self.imagelist.remove(t)
+                            t = self.CreateTexture(textId = textId)
+                        # always set coordinates, needed for synchr. 2D and 3D modes
+                        t.SetCoords(self.textdict[textId]['coords'])
+            
+    def CreateTexture(self, overlay = None, textId = None):
+        """!Create texture from overlay image or from textdict"""
+        if overlay: # legend  
+            texture = wxnviz.ImageTexture(filepath = overlay.mapfile, overlayId = overlay.id,
+                                          coords = list(self.overlays[overlay.id]['coords']),
+                                          cmd = overlay.GetCmd())
+            if overlay.id == 1: # legend
+                texture.SetBounds(self.GetLegendRect())
+        else: # text
+            coords, bbox, relCoords = self.TextBounds(self.textdict[textId])
+            self.textdict[textId]['coords'] = coords
+            self.textdict[textId]['bbox'] = bbox
+            file = self.DrawTextImage(self.textdict[textId], relCoords)
+            texture = wxnviz.TextTexture(filepath = file, overlayId = textId,
+                                         coords = coords, textDict = self.textdict[textId])
+            bbox.OffsetXY(*relCoords)
+            texture.SetBounds(bbox)
+            
+        if not texture.textureId: # texture too big
+            GMessage(parent = self, message = 
+                     _("Image is too large, your OpenGL implementation "
+                       "supports maximum texture size %d px.") % texture.maxSize)
+            return texture
+            
+        self.imagelist.append(texture)
+        
+        return texture
+        
+    def FindObjects(self, mouseX, mouseY, radius):
+        """Find object which was clicked on"""
+        for texture in self.imagelist:
+            if texture.HitTest(mouseX, mouseY, radius):
+                return texture.id
+        return -1
+        
+    def OnTimerAnim(self, event):
+         self.animation.Update()
+         
+    def GetAnimation(self):
+         return self.animation
+         
+    def OnKeyDown(self, event):
+        """!Key was pressed.
+        
+        Used for fly-through mode.
+        """
+        if not self.mouse['use'] == 'fly':
+            return
+            
+        key = event.GetKeyCode()
+        if key == wx.WXK_CONTROL: # Mac ?
+            self.fly['mode'] = 1
+            
+        elif key == wx.WXK_SHIFT: 
+            self.fly['exag']['move'] *= self.fly['exagMultiplier']
+            self.fly['exag']['turn'] *= self.fly['exagMultiplier']
+            
+        elif key == wx.WXK_ESCAPE and self.timerFly.IsRunning() and not self.fly['mouseControl']:
+            self.StopTimer(self.timerFly)
+            self.fly['mouseControl'] = None
+            self.render['quick'] = False
+            self.Refresh(False)
+            
+        elif key in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
+            if not self.fly['mouseControl']:
+                if not self.timerFly.IsRunning():
+                    sx, sy = self.GetClientSizeTuple()
+                    self.fly['pos']['x'] = sx / 2
+                    self.fly['pos']['y'] = sy / 2
+                    self.fly['mouseControl'] = False # controlled by keyboard
+                    self.timerFly.Start(self.fly['interval'])
+    
+                self.ProcessFlyByArrows(keyCode = key)
+                
+            # change speed of flight when using mouse
+            else:
+                if key == wx.WXK_UP:
+                    self.ChangeFlySpeed(increase = True)
+                elif key == wx.WXK_DOWN:
+                    self.ChangeFlySpeed(increase = False)
+        
+        elif key in (wx.WXK_HOME, wx.WXK_PAGEUP) and self.timerFly.IsRunning():
+            self.ChangeFlySpeed(increase = True)
+        elif key in (wx.WXK_END, wx.WXK_PAGEDOWN) and self.timerFly.IsRunning():
+            self.ChangeFlySpeed(increase = False)
+            
+        event.Skip()
+        
+    def ProcessFlyByArrows(self, keyCode):
+        """!Process arrow key during fly-through"""
+        step = self.fly['arrowStep']
+        if keyCode == wx.WXK_UP:
+            self.fly['pos']['y'] -= step
+        elif keyCode == wx.WXK_DOWN:
+            self.fly['pos']['y'] += step
+        elif keyCode == wx.WXK_LEFT:
+            self.fly['pos']['x'] -= step
+        elif keyCode == wx.WXK_RIGHT:
+            self.fly['pos']['x'] += step
+            
+    def OnKeyUp(self, event):
+        """!Key was released.
+        
+        Used for fly-through mode.
+        """
+        if not self.mouse['use'] == 'fly':
+            return
+            
+        key = event.GetKeyCode()
+        if key == wx.WXK_CONTROL: # Mac ?
+            self.fly['mode'] = 0
+        elif key == wx.WXK_SHIFT: 
+            self.fly['exag']['move'] = math.floor(self.fly['exag']['move'] / self.fly['exagMultiplier'])
+            self.fly['exag']['turn'] = math.floor(self.fly['exag']['turn'] / self.fly['exagMultiplier'])
+        
+        event.Skip()
+        
+    def OnMouseAction(self, event):
+        """!Handle mouse events"""
+        # zoom with mouse wheel
+        if event.GetWheelRotation() != 0:
+            self.OnMouseWheel(event)
+            
+        # left mouse button pressed
+        elif event.LeftDown():
+            self.OnLeftDown(event)
+        
+        # left mouse button released
+        elif event.LeftUp():
+            self.OnLeftUp(event)
+        
+        # dragging
+        elif event.Dragging():
+            self.OnDragging(event)
+            
+        # double click    
+        elif event.ButtonDClick():
+            self.OnDClick(event)
+        
+        event.Skip()
+
+    def OnMouseWheel(self, event):
+        """!Change perspective"""
+        wheel = event.GetWheelRotation()
+        Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel)
+        if self.timerFly.IsRunning() and self.fly['mouseControl']:
+            if wheel > 0:
+                self.ChangeFlySpeed(increase = True)
+            else:
+                self.ChangeFlySpeed(increase = False)
+        else:
+            self.DoZoom(zoomtype = wheel, pos = event.GetPositionTuple())
+            
+        # update statusbar
+        ### self.parent.StatusbarUpdate()
+            
+    def OnLeftDown(self, event):
+        """!On left mouse down"""
+        self.mouse['begin'] = event.GetPositionTuple()
+        self.mouse['tmp'] = event.GetPositionTuple()
+        if self.mouse['use'] == "lookHere":
+            size = self.GetClientSize()
+            self._display.LookHere(self.mouse['begin'][0], size[1] - self.mouse['begin'][1])
+            focus = self._display.GetFocus()
+            for i, coord in enumerate(('x', 'y', 'z')):
+                self.iview['focus'][coord] = focus[i]
+            self.saveHistory = True
+            self.Refresh(False)
+            toggle = self.lmgr.nviz.FindWindowByName('here')
+            toggle.SetValue(False)
+            self.mouse['use'] = 'pointer'
+            self.SetCursor(self.cursors['default'])
+                
+        if self.mouse['use'] == 'arrow':
+            pos = event.GetPosition()
+            size = self.GetClientSize()
+            self.SetDrawArrow((pos[0], size[1] - pos[1]))
+                
+        if self.mouse['use'] == 'scalebar':
+            pos = event.GetPosition()
+            size = self.GetClientSize()
+            self.SetDrawScalebar((pos[0], size[1] - pos[1]))
+        
+        if self.mouse['use'] == 'pointer':
+            # get decoration or text id
+            self.dragid = self.FindObjects(self.mouse['tmp'][0], self.mouse['tmp'][1],
+                                          self.hitradius)   
+                
+        if self.mouse['use'] == 'fly':
+            if not self.timerFly.IsRunning():
+                self.timerFly.Start(self.fly['interval'])
+                self.fly['mouseControl'] = True
+            
+        event.Skip()    
+        
+    def OnDragging(self, event):
+                
+        if self.mouse['use'] == 'pointer':
+            if self.dragid > 0:
+                self.DragItem(self.dragid, event)
+            
+        if self.mouse['use'] == 'rotate':    
+            dx, dy = event.GetX() - self.mouse['tmp'][0], event.GetY() - self.mouse['tmp'][1]
+            
+            angle, x, y, z = self._display.GetRotationParameters(dx, dy)
+            self._display.Rotate(angle, x, y, z)
+            
+            self.render['quick'] = True
+            self.Refresh(False)
+            
+        if self.mouse['use'] == 'pan':
+            self.FocusPanning(event)
+            
+        self.mouse['tmp'] = event.GetPositionTuple()
+                
+        event.Skip()
+            
+    def Pixel2Cell(self, (x, y)):
+        """!Convert image coordinates to real word coordinates
+
+        @param x, y image coordinates
+        
+        @return easting, northing
+        @return None on error
+        """
+        size = self.GetClientSize()
+        # UL -> LL
+        sid, x, y, z = self._display.GetPointOnSurface(x, size[1] - y)
+        
+        if not sid:
+            return None
+        
+        return (x, y)
+    
+    def DoZoom(self, zoomtype, pos):
+        """!Change perspective and focus"""
+        
+        prev_value = self.view['persp']['value']
+        if zoomtype > 0:
+            value = -1 * self.view['persp']['step']
+        else:
+            value = self.view['persp']['step']
+        self.view['persp']['value'] +=  value
+        if self.view['persp']['value'] < 1:
+            self.view['persp']['value'] = 1
+        elif self.view['persp']['value'] > 180:
+            self.view['persp']['value'] = 180
+        
+        if prev_value !=  self.view['persp']['value']:
+            if hasattr(self.lmgr, "nviz"):
+                self.lmgr.nviz.UpdateSettings()
+                x, y = pos[0], self.GetClientSize()[1] - pos[1]
+                result = self._display.GetPointOnSurface(x, y)
+                if result[0]:
+                    self._display.LookHere(x, y)
+                    focus = self._display.GetFocus()
+                    for i, coord in enumerate(('x', 'y', 'z')):
+                        self.iview['focus'][coord] = focus[i]
+                self._display.SetView(self.view['position']['x'], self.view['position']['y'],
+                                      self.iview['height']['value'],
+                                      self.view['persp']['value'],
+                                      self.view['twist']['value'])
+                self.saveHistory = True
+            # redraw map
+            self.DoPaint()
+            
+    def OnLeftUp(self, event):
+        self.mouse['end'] = event.GetPositionTuple()
+        if self.mouse["use"] == "query":
+            # querying
+            layers = self.GetSelectedLayer(multi = True)
+            isRaster = False
+            nVectors = 0
+            for l in layers:
+                if l.GetType() == 'raster':
+                    isRaster = True
+                    break
+                if l.GetType() == 'vector':
+                    nVectors += 1
+            
+            if isRaster or nVectors > 1:
+                self.OnQueryMap(event)
+            else:
+                self.OnQueryVector(event)
+                    
+        elif self.mouse["use"] in ('arrow', 'scalebar'):
+            self.lmgr.nviz.FindWindowById(
+                    self.lmgr.nviz.win['decoration'][self.mouse["use"]]['place']).SetValue(False)
+            self.mouse['use'] = 'pointer'
+            self.SetCursor(self.cursors['default'])
+        elif self.mouse['use'] == 'pointer':
+            if self.dragid > 0:
+                dx = self.mouse['end'][0] - self.mouse['begin'][0]
+                dy = self.mouse['end'][1] - self.mouse['begin'][1]
+                if self.dragid < 99:
+                    coords = self.overlays[self.dragid]['coords']
+                    self.overlays[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
+                else: # text
+                    coords = self.textdict[self.dragid]['coords']
+                    self.textdict[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
+                self.dragid = -1
+                self.render['quick'] = False
+                self.Refresh(False)
+            
+        elif self.mouse['use'] == 'rotate':
+            self._display.UnsetRotation()
+            self.iview['rotation'] = self._display.GetRotationMatrix()
+            self.saveHistory = True
+            self.render['quick'] = False
+            self.Refresh(False)
+            
+        elif self.mouse['use'] == 'pan':
+            self.saveHistory = True
+            self.render['quick'] = False
+            self.Refresh(False)
+            
+        elif self.mouse['use'] == 'fly':
+            if self.fly['mouseControl']:
+                self.StopTimer(self.timerFly)
+                self.fly['mouseControl'] = None
+                #for key in self.iview['dir'].keys():
+                    #self.iview[''][key] = -1
+                # this causes sudden change, but it should be there
+                #if hasattr(self.lmgr, "nviz"):
+                    #self.lmgr.nviz.UpdateSettings()
+                    
+                self.render['quick'] = False
+                self.Refresh(False)
+            
+        elif self.mouse['use'] == 'zoom':
+            self.DoZoom(zoomtype = self.zoomtype, pos = self.mouse['end'])
+        event.Skip()
+            
+    def OnDClick(self, event):
+        """!On mouse double click"""
+        if self.mouse['use'] != 'pointer': return
+        pos = event.GetPositionTuple()
+        self.dragid = self.FindObjects(pos[0], pos[1], self.hitradius)
+        
+        if self.dragid == 1:
+            self.parent.OnAddLegend(None)
+        elif self.dragid > 100:
+            self.parent.OnAddText(None)
+        else:
+            return
+    
+    def FocusPanning(self, event):
+        """!Simulation of panning using focus"""
+        size = self.GetClientSizeTuple()
+        id1, x1, y1, z1 = self._display.GetPointOnSurface(
+                      self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
+        id2, x2, y2, z2 = self._display.GetPointOnSurface(
+                      event.GetX(), size[1] - event.GetY())
+        if id1 and id1 == id2:
+            dx, dy, dz = x2 - x1, y2 - y1, z2 - z1
+            focus = self.iview['focus']
+            focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
+            focus['x'] -= dx
+            focus['y'] -= dy
+            focus['z'] -= dz
+            
+            #update properties
+            self.PostViewEvent()
+            
+            self.mouse['tmp'] = event.GetPositionTuple()
+            self.render['quick'] = True
+            self.Refresh(False)
+            
+    def HorizontalPanning(self, event):
+        """!Move all layers in horizontal (x, y) direction.
+        Currently not used.
+        """
+        size = self.GetClientSizeTuple()
+        id1, x1, y1, z1 = self._display.GetPointOnSurface(
+                      self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
+        id2, x2, y2, z2 = self._display.GetPointOnSurface(
+                      event.GetX(), size[1] - event.GetY())
+        
+        if id1 and id1 == id2:
+            dx, dy = x2 - x1, y2 - y1
+            # find raster and volume
+            for item in self.layers:
+                mapLayer = self.tree.GetPyData(item)[0]['maplayer']
+                  
+                data = self.tree.GetPyData(item)[0]['nviz']
+                if mapLayer.GetType() == 'raster':
+                    data['surface']['position']['x'] += dx
+                    data['surface']['position']['y'] += dy
+                    data['surface']['position']['update'] = None
+                    
+                    #update properties
+                    evt = wxUpdateProperties(data = data)
+                    wx.PostEvent(self, evt)
+                    
+                    if event.CmdDown() and id1 == data['surface']['object']['id']:
+                        break
+                    
+                elif mapLayer.GetType() == '3d-raster':
+                    if 'x' not in data['volume']['position']:
+                        data['volume']['position']['x'] = 0
+                        data['volume']['position']['y'] = 0
+                        data['volume']['position']['z'] = 0
+                    data['volume']['position']['x'] += dx
+                    data['volume']['position']['y'] += dy
+                    data['volume']['position']['update'] = None
+                    
+                    #update properties
+                    evt = wxUpdateProperties(data = data)
+                    wx.PostEvent(self, evt)
+                
+            self.mouse['tmp'] = event.GetPositionTuple()
+            self.render['quick'] = True
+            self.Refresh(False)
+            
+    def DragItem(self, id, event):
+        """!Drag an overlay decoration item
+        """
+        if not id: return
+        Debug.msg (5, "GLWindow.DragItem(): id=%d" % id)
+        x, y = self.mouse['tmp']
+        dx = event.GetX() - x
+        dy = event.GetY() - y
+        for texture in self.imagelist:
+            if texture.id == id:
+                texture.MoveTexture(dx, dy)
+
+
+        self.render['quick'] = True
+        self.Refresh(False)
+        
+        self.mouse['tmp'] = (event.GetX(), event.GetY()) 
+        
+    def ZoomBack(self):
+        """!Set previous view in history list
+        """
+        view = {}
+        if len(self.viewhistory) > 1:
+            self.viewhistory.pop()
+            view = copy.deepcopy(self.viewhistory[-1])
+        
+        # disable tool if stack is empty
+        if len(self.viewhistory) < 2: # disable tool
+            toolbar = self.parent.GetMapToolbar()
+            toolbar.Enable('zoomback', enable = False)
+            
+        # set view and update nviz view page
+        self.lmgr.nviz.UpdateState(view = view[0], iview = view[1])
+        self.lmgr.nviz.UpdatePage('view')
+        # update map
+        self.Refresh(False)
+
+    def ViewHistory(self, view, iview):
+        """!Manages a list of last 10 views
+        
+        @param view view dictionary
+        @param iview view dictionary (internal)
+        
+        @return removed history item if exists (or None)
+        """
+        removed = None
+        hview = copy.deepcopy(view)
+        hiview = copy.deepcopy(iview)
+        
+        if not (self.viewhistory and self.viewhistory[-1] == (hview, hiview)):  
+            self.viewhistory.append((hview, hiview))
+            
+        if len(self.viewhistory) > 10:
+            removed = self.viewhistory.pop(0)
+        
+        if removed:
+            Debug.msg(4, "GLWindow.ViewHistory(): hist=%s, removed=%s" %
+                      (self.viewhistory, removed))
+        else:
+            Debug.msg(4, "GLWindow.ViewHistory(): hist=%s" %
+                      (self.viewhistory))
+        
+        # update toolbar
+        if len(self.viewhistory) > 1:
+            enable = True
+        else:
+            enable = False
+        
+        toolbar = self.parent.GetMapToolbar()
+        toolbar.Enable('zoomback', enable)
+        
+        return removed     
+    
+    def ResetViewHistory(self):
+        """!Reset view history"""
+        self.viewhistory = list()
+    
+    def GoTo(self, e, n):
+        """!Focus on given point"""
+        w = self.Map.region['w']
+        s = self.Map.region['s']
+        e -= w
+        n -= s
+        focus = self.iview['focus']
+        focus['x'], focus['y'] = e, n
+        self.saveHistory = True
+        #update properties
+        self.PostViewEvent()
+        
+        self.render['quick'] = False
+        self.Refresh(False)
+    
+    def OnQueryMap(self, event):
+        """!Query raster and vector maps"""
+        self.OnQuerySurface(event)
+        self.parent.QueryMap(event.GetX(), event.GetY())
+        
+    def OnQuerySurface(self, event):
+        """!Query surface on given position"""
+        size = self.GetClientSizeTuple()
+        result = self._display.QueryMap(event.GetX(), size[1] - event.GetY())
+        if result:
+            self.qpoints.append((result['x'], result['y'], result['z']))
+            self.log.WriteLog("%-30s: %.3f" % (_("Easting"),   result['x']))
+            self.log.WriteLog("%-30s: %.3f" % (_("Northing"),  result['y']))
+            self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z']))
+            name = ''
+            for item in self.layers:
+                self.tree.GetPyData(item)[0]['nviz']
+                if self.tree.GetPyData(item)[0]['maplayer'].type == 'raster' and\
+                    self.tree.GetPyData(item)[0]['nviz']['surface']['object']['id'] == result['id']:
+                    name = self.tree.GetPyData(item)[0]['maplayer'].name
+            self.log.WriteLog("%-30s: %s" % (_("Surface map name"), name))
+            self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation']))
+            self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color']))
+            if len(self.qpoints) > 1:
+                prev = self.qpoints[-2]
+                curr = self.qpoints[-1]
+                dxy = math.sqrt(pow(prev[0]-curr[0], 2) +
+                                pow(prev[1]-curr[1], 2))
+                dxyz = math.sqrt(pow(prev[0]-curr[0], 2) +
+                                 pow(prev[1]-curr[1], 2) +
+                                 pow(prev[2]-curr[2], 2))
+                self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy))
+                self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz))
+                self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"),
+                                              self._display.GetDistanceAlongSurface(result['id'],
+                                                                                    (curr[0], curr[1]),
+                                                                                    (prev[0], prev[1]),
+                                                                                    useExag = False)))
+                self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"),
+                                              self._display.GetDistanceAlongSurface(result['id'],
+                                                                                    (curr[0], curr[1]),
+                                                                                    (prev[0], prev[1]),
+                                                                                      useExag = True)))
+            self.log.WriteCmdLog('-' * 80)
+        else:
+            self.log.WriteLog(_("No point on surface"))
+            self.log.WriteCmdLog('-' * 80)
+    
+    def PostViewEvent(self, zExag = False):
+        """!Change view settings"""
+        event = wxUpdateView(zExag = zExag)
+        wx.PostEvent(self, event)
+        
+    def OnQueryVector(self, event):
+        """!Query vector on given position"""
+        self.parent.QueryVector(*event.GetPosition())
+
+    def ChangeInnerView(self):
+        """!Get current viewdir and viewpoint and set view"""
+        view = self.view
+        iview = self.iview
+        (view['position']['x'], view['position']['y'],
+        iview['height']['value']) = self._display.GetViewpointPosition()
+        for key, val in zip(('x', 'y', 'z'), self._display.GetViewdir()):
+            iview['dir'][key] = val
+        
+        iview['dir']['use'] = True
+        
+    def OnUpdateView(self, event):
+        """!Change view settings"""
+        if event:
+                self.UpdateView(zexag = event.zExag)
+                
+        self.saveHistory = True
+        if event:
+            event.Skip()
+            
+            
+    def UpdateView(self, zexag = False):
+        """!Change view settings"""
+        view = self.view
+        iview = self.iview
+        if zexag and 'value' in view['z-exag']:
+            self._display.SetZExag(self.iview['z-exag']['original'] * view['z-exag']['value'])
+        
+        
+        self._display.SetView(view['position']['x'], view['position']['y'],
+                              iview['height']['value'],
+                              view['persp']['value'],
+                              view['twist']['value'])
+        
+        if iview['dir']['use']:
+            self._display.SetViewdir(iview['dir']['x'], iview['dir']['y'], iview['dir']['z'])
+        
+        elif iview['focus']['x'] != -1:
+            self._display.SetFocus(self.iview['focus']['x'], self.iview['focus']['y'],
+                                   self.iview['focus']['z'])
+                                       
+        if 'rotation' in iview:
+            if iview['rotation']:
+                self._display.SetRotationMatrix(iview['rotation'])
+            else:
+                self._display.ResetRotation()
+        
+    def UpdateLight(self, event):
+        """!Change light settings"""
+        data = self.light
+        self._display.SetLight(x = data['position']['x'], y = data['position']['y'],
+                               z = data['position']['z'] / 100., color = data['color'],
+                               bright = data['bright'] / 100.,
+                               ambient = data['ambient'] / 100.)
+        self._display.DrawLightingModel()
+        if event.refresh:
+            self.Refresh(False)
+        
+    def UpdateMap(self, render = True):
+        """!Updates the canvas anytime there is a change to the
+        underlaying images or to the geometry of the canvas.
+        
+        @param render re-render map composition
+        """
+        start = time.clock()
+        
+        self.resize = False
+        
+        if self.render['quick'] is False:
+            self.parent.GetProgressBar().Show()
+            self.parent.GetProgressBar().SetRange(2)
+            self.parent.GetProgressBar().SetValue(0)
+        
+        if self.render['quick'] is False:
+            self.parent.GetProgressBar().SetValue(1)
+            self._display.Draw(False, -1)
+            if self.saveHistory:
+                self.ViewHistory(view = self.view, iview = self.iview)
+                self.saveHistory = False
+        elif self.render['quick'] is True:
+            # quick
+            mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
+            if self.render['vlines']:
+                mode |=  wxnviz.DRAW_QUICK_VLINES
+            if self.render['vpoints']:
+                mode |=  wxnviz.DRAW_QUICK_VPOINTS
+            self._display.Draw(True, mode)
+        else: # None -> reuse last rendered image
+            pass # TODO
+            
+        self.SwapBuffers()
+        # draw fringe after SwapBuffers, otherwise it don't have to be visible
+        # on some computers
+        if self.render['quick'] is False:
+            self._display.DrawFringe()
+            if self.decoration['arrow']['show']:
+                self._display.DrawArrow()
+            if self.decoration['scalebar']:
+                self._display.DrawScalebar()
+        if self.imagelist:
+            if ((self.render['quick'] and self.dragid > -1) or # during dragging
+                (not self.render['quick'] and self.dragid < 0)): # redraw
+                self._display.Start2D()
+                self.DrawImages()
+                
+            
+            
+        stop = time.clock()
+        
+        if self.render['quick'] is False:
+            self.parent.GetProgressBar().SetValue(2)
+            # hide process bar
+            self.parent.GetProgressBar().Hide()
+        
+        Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \
+                      (self.render['quick'], (stop-start)))
+        
+    def EraseMap(self):
+        """!Erase the canvas
+        """
+        self._display.EraseMap()
+        self.SwapBuffers()
+    
+    def _getDecorationSize(self):
+        """!Get initial size of north arrow/scalebar"""
+        size = self._display.GetLongDim() / 8.
+        coef = 0.01
+        if size < 1:
+            coef = 100.
+        return int(size * coef)/coef
+    
+    def SetDrawArrow(self, pos):
+        
+        if self._display.SetArrow(pos[0], pos[1], 
+                                 self.decoration['arrow']['size'],
+                                 self.decoration['arrow']['color']):
+            self._display.DrawArrow()
+            # update
+            self.decoration['arrow']['show'] = True
+            self.decoration['arrow']['position']['x'] = pos[0]
+            self.decoration['arrow']['position']['y'] = pos[1]
+            self.Refresh(False)
+    
+    def SetDrawScalebar(self, pos):
+        """!Add scale bar, sets properties and draw"""
+        if len(self.decoration['scalebar']) == 0:
+            self.decoration['scalebar'].append(
+                    self.nvizDefault.SetDecorDefaultProp(type = 'scalebar')['scalebar'])
+            self.decoration['scalebar'][0]['size'] = self._getDecorationSize()
+        else:
+            self.decoration['scalebar'].append(copy.deepcopy(self.decoration['scalebar'][-1]))
+            self.decoration['scalebar'][-1]['id'] += 1
+        
+        ret = self._display.SetScalebar(self.decoration['scalebar'][-1]['id'], pos[0], pos[1], 
+                                 self.decoration['scalebar'][-1]['size'],
+                                 self.decoration['scalebar'][-1]['color'])
+        if ret:
+            self._display.DrawScalebar()
+            # update
+            self.decoration['scalebar'][-1]['position']['x'] = pos[0]
+            self.decoration['scalebar'][-1]['position']['y'] = pos[1]
+            self.Refresh(False)
+        
+    def IsLoaded(self, item):
+        """!Check if layer (item) is already loaded
+        
+        @param item layer item
+        """
+        layer = self.tree.GetPyData(item)[0]['maplayer']
+        data = self.tree.GetPyData(item)[0]['nviz']
+        
+        if not data:
+            return 0
+        
+        if layer.type ==  'raster':
+            if 'object' not in data['surface']:
+                return 0
+        elif layer.type ==  'vector':
+            if 'object' not in data['vlines'] and \
+                    'object' not in data['points']:
+                return 0
+        
+        return 1
+
+    def _GetDataLayers(self, item, litems):
+        """!Return get list of enabled map layers"""
+        # load raster & vector maps
+        while item and item.IsOk():
+            type = self.tree.GetPyData(item)[0]['type']
+            if type ==  'group':
+                subItem = self.tree.GetFirstChild(item)[0]
+                self._GetDataLayers(subItem, litems)
+                item = self.tree.GetNextSibling(item)
+                
+            if not item.IsChecked() or \
+                    type not in ('raster', 'vector', '3d-raster'):
+                item = self.tree.GetNextSibling(item)
+                continue
+            
+            litems.append(item)
+            
+            item = self.tree.GetNextSibling(item)
+        
+    def LoadDataLayers(self):
+        """!Load raster/vector from current layer tree
+        
+        @todo volumes
+        """
+        if not self.tree:
+            return
+        
+        listOfItems = []
+        item = self.tree.GetFirstChild(self.tree.root)[0]
+        self._GetDataLayers(item, listOfItems)
+        
+        start = time.time()
+        
+        while(len(listOfItems) > 0):
+            item = listOfItems.pop()
+            type = self.tree.GetPyData(item)[0]['type']
+            if item in self.layers:
+                continue
+            # "raster (double click to set properties)" - tries to load this 
+            # layer - no idea how to fix it
+            if ' ' in self.tree.GetPyData(item)[0]['maplayer'].name:
+                return
+            try:
+                if type ==  'raster':
+                    self.LoadRaster(item)
+                elif type ==  '3d-raster':
+                    self.LoadRaster3d(item)
+                elif type ==  'vector':
+                    # data = self.tree.GetPyData(item)[0]['nviz']
+                    # vecType = []
+                    # if data and 'vector' in data:
+                    #     for v in ('lines', 'points'):
+                    #         if data['vector'][v]:
+                    #             vecType.append(v)
+                    layer = self.tree.GetPyData(item)[0]['maplayer']
+                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
+                    if npoints > 0:
+                        self.LoadVector(item, points = True)
+                    if nlines > 0:
+                        self.LoadVector(item, points = False)
+            except GException, e:
+                GError(parent = self,
+                       message = e.value)
+            self.init = False
+        
+        stop = time.time()
+        
+        Debug.msg(1, "GLWindow.LoadDataLayers(): time = %f" % (stop-start))
+                
+    def UnloadDataLayers(self, force = False):
+        """!Unload any layers that have been deleted from layer tree
+
+        @param force True to unload all data layers
+        """
+        if not self.tree:
+            return
+        
+        listOfItems = []
+        if not force:
+            item = self.tree.GetFirstChild(self.tree.root)[0]
+            self._GetDataLayers(item, listOfItems)
+        
+        start = time.time()
+        
+        update = False
+        layersTmp = self.layers[:]
+        for layer in layersTmp:
+            if layer in listOfItems:
+                continue
+            ltype = self.tree.GetPyData(layer)[0]['type']
+            try:
+                if ltype ==  'raster':
+                    self.UnloadRaster(layer)
+                elif ltype ==  '3d-raster':
+                    self.UnloadRaster3d(layer) 
+                elif ltype ==  'vector':
+                    maplayer = self.tree.GetPyData(layer)[0]['maplayer']
+                    npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(maplayer)
+                    if npoints > 0:
+                        self.UnloadVector(layer, points = True)
+                    if nlines > 0:
+                        self.UnloadVector(layer, points = False)
+                        
+            except GException, e:
+                GError(parent = self,
+                       message = e.value)
+        
+        if force and self.baseId > 0: # unload base surface when quitting
+            ret = self._display.UnloadSurface(self.baseId)
+            self.baseId = -1
+        if update:
+            self.lmgr.nviz.UpdateSettings()        
+            self.UpdateView(None)
+        
+        stop = time.time()
+        
+        Debug.msg(1, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start))        
+        
+    def SetVectorSurface(self, data):
+        """!Set reference surfaces of vector"""
+        data['mode']['surface'] = {}
+        data['mode']['surface']['value'] = list()
+        data['mode']['surface']['show'] = list()
+        for name in self.GetLayerNames('raster'):
+            data['mode']['surface']['value'].append(name)
+            data['mode']['surface']['show'].append(True)
+        
+    def SetVectorFromCmd(self, item, data):
+        """!Set 3D view properties from cmd (d.vect)
+
+        @param item Layer Tree item
+        @param nviz data
+        """
+        cmd = self.tree.GetPyData(item)[0]['cmd']
+        if cmd[0] != 'd.vect':
+            return
+        for opt in cmd[1:]:
+            try:
+                key, value = opt.split('=')
+            except ValueError:
+                continue
+            if key == 'color':
+                data['lines']['color']['value'] = value
+                data['points']['color']['value'] = value
+
+    def SetMapObjProperties(self, item, id, nvizType):
+        """!Set map object properties
+        
+        Properties must be afterwards updated by
+        UpdateMapObjProperties().
+        
+        @param item layer item
+        @param id nviz layer id (or -1)
+        @param nvizType nviz data type (surface, points, vector)
+        """
+        if nvizType != 'constant':
+            mapType = self.tree.GetPyData(item)[0]['maplayer'].type
+            # reference to original layer properties (can be None)
+            data = self.tree.GetPyData(item)[0]['nviz']
+        else:
+            mapType = nvizType
+            data = self.constants[item]
+        
+        if not data:
+            # init data structure
+            if nvizType != 'constant':
+                self.tree.GetPyData(item)[0]['nviz'] = {}
+                data = self.tree.GetPyData(item)[0]['nviz']
+            
+            if mapType ==  'raster':
+                # reset to default properties
+                data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp()
+                        
+            elif mapType ==  'vector':
+                # reset to default properties (lines/points)
+                data['vector'] = self.nvizDefault.SetVectorDefaultProp()
+                self.SetVectorFromCmd(item, data['vector'])
+                self.SetVectorSurface(data['vector']['points'])
+                self.SetVectorSurface(data['vector']['lines'])
+                
+            elif mapType ==  '3d-raster':
+                # reset to default properties 
+                data[nvizType] = self.nvizDefault.SetVolumeDefaultProp()
+                
+            elif mapType == 'constant':
+                data['constant'] = self.nvizDefault.SetConstantDefaultProp()
+        
+        else:
+            # complete data (use default values), not sure if this is necessary
+            if mapType ==  'raster':
+                if not data['surface']:
+                    data['surface'] = self.nvizDefault.SetSurfaceDefaultProp()
+            if mapType ==  'vector':
+                if not data['vector']['lines']:
+                    self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
+                if not data['vector']['points']:
+                    self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])     
+            # set updates
+            for sec in data.keys():
+                for sec1 in data[sec].keys():
+                    if sec1 == 'position':
+                        data[sec][sec1]['update'] = None
+                        continue
+                    if type(data[sec][sec1]) == types.DictType:
+                        for sec2 in data[sec][sec1].keys():
+                            if sec2 not in ('all', 'init', 'id'):
+                                data[sec][sec1][sec2]['update'] = None
+                    elif type(data[sec][sec1]) == types.ListType:
+                        for i in range(len(data[sec][sec1])):
+                            for sec2 in data[sec][sec1][i].keys():
+                                data[sec][sec1][i][sec2]['update'] = None
+            event = wxUpdateProperties(data = data)
+            wx.PostEvent(self, event)
+        
+        # set id
+        if id > 0:
+            if mapType in ('raster', '3d-raster'):
+                data[nvizType]['object'] = { 'id' : id,
+                                            'init' : False }
+            elif mapType ==  'vector':
+                data['vector'][nvizType]['object'] = { 'id' : id,
+                                                       'init' : False }
+            elif mapType ==  'constant':
+                data[nvizType]['object'] = { 'id' : id,
+                                             'init' : False }
+        
+        return data
+
+    def LoadRaster(self, item):
+        """!Load 2d raster map and set surface attributes
+        
+        @param layer item
+        """
+        return self._loadRaster(item)
+    
+    def LoadRaster3d(self, item):
+        """!Load 3d raster map and set surface attributes
+        
+        @param layer item
+        """
+        return self._loadRaster(item)
+    
+    def _loadRaster(self, item):
+        """!Load 2d/3d raster map and set its attributes
+        
+        @param layer item
+        """
+        layer = self.tree.GetPyData(item)[0]['maplayer']
+        
+        if layer.type not in ('raster', '3d-raster'):
+            return
+        
+        if layer.type ==  'raster':
+            id = self._display.LoadSurface(str(layer.name), None, None)
+            nvizType = 'surface'
+            errorMsg = _("Loading raster map")
+        elif layer.type ==  '3d-raster':
+            id = self._display.LoadVolume(str(layer.name), None, None)
+            nvizType = 'volume'
+            errorMsg = _("Loading 3d raster map")
+        else:
+            id = -1
+        
+        if id < 0:
+            if layer.type in ('raster', '3d-raster'):
+                self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed")))
+            else:
+                self.log.WriteError(_("Unsupported layer type '%s'") % layer.type)
+        
+        self.layers.append(item)
+        
+        # set default/workspace layer properties
+        data = self.SetMapObjProperties(item, id, nvizType)
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self, event)
+        
+        # update tools window
+        if hasattr(self.lmgr, "nviz") and \
+                item ==  self.GetSelectedLayer(type = 'item'):
+            toolWin = self.lmgr.nviz
+            if layer.type ==  'raster':
+                win = toolWin.FindWindowById( \
+                    toolWin.win['vector']['lines']['surface'])
+                win.SetItems(self.GetLayerNames(layer.type))
+            
+            #toolWin.UpdatePage(nvizType)
+            #toolWin.SetPage(nvizType)
+        
+        return id
+    
+    def NewConstant(self):
+        """!Create new constant"""
+        index = len(self.constants)
+        try:
+            name = self.constants[-1]['constant']['object']['name'] + 1
+        except IndexError:
+            name = 1
+        data = dict()
+        self.constants.append(data)
+        data = self.SetMapObjProperties(item = index, id = -1, nvizType = 'constant')
+        self.AddConstant(data, name)
+        return name
+        
+    def AddConstant(self, data, name):
+        """!Add new constant"""
+        id = self._display.AddConstant(value = data['constant']['value'], color = data['constant']['color'])
+        self._display.SetSurfaceRes(id, data['constant']['resolution'], data['constant']['resolution'])
+        data['constant']['object'] = { 'id' : id,
+                                       'name': name,
+                                       'init' : False }
+    
+    def DeleteConstant(self, index):
+        """!Delete constant layer"""
+        id = self.constants[index]['constant']['object']['id']
+        self._display.UnloadSurface(id)
+        del self.constants[index]
+    
+    def SelectCPlane(self, index):
+        """!Select cutting plane"""
+        for plane in range (self._display.GetCPlanesCount()):
+            if plane == index:
+                self._display.SelectCPlane(plane)
+                self.cplanes[plane]['on'] = True
+                self._display.SetFenceColor(self.cplanes[plane]['shading'])
+            else:
+                self._display.UnselectCPlane(plane)
+                try:
+                    self.cplanes[plane]['on'] = False
+                except IndexError:
+                    pass
+                    
+    def UpdateCPlane(self, event):
+        """!Change cutting plane settings"""
+        current = event.current
+        for each in event.update:
+            if each == 'rotation':
+                self._display.SetCPlaneRotation(0, self.cplanes[current]['rotation']['tilt'],
+                                                   self.cplanes[current]['rotation']['rot'])
+            if each == 'position':
+                self._display.SetCPlaneTranslation(self.cplanes[current]['position']['x'],
+                                                   self.cplanes[current]['position']['y'],
+                                                   self.cplanes[current]['position']['z'])
+            if each == 'shading':
+                self._display.SetFenceColor(self.cplanes[current]['shading'])
+            
+    def UnloadRaster(self, item):
+        """!Unload 2d raster map
+        
+        @param layer item
+        """
+        return self._unloadRaster(item)
+    
+    def UnloadRaster3d(self, item):
+        """!Unload 3d raster map
+        
+        @param layer item
+        """
+        return self._unloadRaster(item)
+    
+    def _unloadRaster(self, item):
+        """!Unload 2d/3d raster map
+        
+        @param item layer item
+        """
+        layer = self.tree.GetPyData(item)[0]['maplayer']
+        
+        if layer.type not in ('raster', '3d-raster'):
+            return
+        
+        data = self.tree.GetPyData(item)[0]['nviz']
+        
+        if layer.type ==  'raster':
+            nvizType = 'surface'
+            unloadFn = self._display.UnloadSurface
+            errorMsg = _("Unable to unload raster map")
+            successMsg = _("Raster map")
+        else:
+            nvizType = 'volume'
+            unloadFn = self._display.UnloadVolume
+            errorMsg = _("Unable to unload 3d raster map")
+            successMsg = _("3d raster map")
+        
+        try:
+            id = data[nvizType]['object']['id']
+        except KeyError:
+            return
+        
+        if unloadFn(id) ==  0:
+            self.log.WriteError("%s <%s>" % (errorMsg, layer.name))
+        else:
+            self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully")))
+        
+        data[nvizType].pop('object')
+        
+        self.layers.remove(item)
+        
+        # update tools window
+        if hasattr(self.lmgr, "nviz"):
+            toolWin = self.lmgr.nviz
+            if layer.type ==  'raster':
+                win = toolWin.FindWindowById(toolWin.win['vector']['lines']['surface'])
+                win.SetItems(self.GetLayerNames(layer.type))
+                win = toolWin.FindWindowById(toolWin.win['surface']['map'])
+                win.SetValue('')
+            if layer.type ==  '3d-raster':
+                win = toolWin.FindWindowById(toolWin.win['volume']['map'])
+                win.SetValue('')
+            if layer.type ==  'vector':
+                win = toolWin.FindWindowById(toolWin.win['vector']['map'])
+                win.SetValue('')
+        
+    def LoadVector(self, item, points = None, append = True):
+        """!Load 2D or 3D vector map overlay
+        
+        @param item layer item
+        @param points True to load points, False to load lines, None
+        to load both
+        @param append append vector to layer list
+        """
+        layer = self.tree.GetPyData(item)[0]['maplayer']
+        if layer.type !=  'vector':
+            return
+        
+        # set default properties
+        if points is None:
+            self.SetMapObjProperties(item, -1, 'lines')
+            self.SetMapObjProperties(item, -1, 'points')
+            vecTypes = ('points', 'lines')
+        elif points:
+            self.SetMapObjProperties(item, -1, 'points')
+            vecTypes = ('points', )
+        else:
+            self.SetMapObjProperties(item, -1, 'lines')
+            vecTypes = ('lines', )
+        
+        id = -1
+        for vecType in vecTypes:
+            if vecType == 'lines':
+                id, baseId = self._display.LoadVector(str(layer.GetName()), False)
+            else:
+                id, baseId = self._display.LoadVector(str(layer.GetName()), True)
+            if id < 0:
+                self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \
+                    { 'name' : layer.name, 'type' : vecType })
+            # update layer properties
+            self.SetMapObjProperties(item, id, vecType)
+        if baseId > 0:
+            self.baseId = baseId # id of base surface (when no surface is loaded)
+        if append:
+            self.layers.append(item)
+        
+        # update properties
+        data = self.tree.GetPyData(item)[0]['nviz']
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self, event)
+        
+        # update tools window
+        if hasattr(self.lmgr, "nviz") and \
+                item ==  self.GetSelectedLayer(type = 'item'):
+            toolWin = self.lmgr.nviz
+            
+            toolWin.UpdatePage('vector')
+            ### toolWin.SetPage('vector')
+        
+        return id
+
+    def UnloadVector(self, item, points = None, remove = True):
+        """!Unload vector map overlay
+        
+        @param item layer item
+        @param points,lines True to unload given feature type
+        @param remove remove layer from list
+        """
+        layer = self.tree.GetPyData(item)[0]['maplayer']
+        data = self.tree.GetPyData(item)[0]['nviz']['vector']
+        
+        # if vecType is None:
+        #     vecType = []
+        #     for v in ('lines', 'points'):
+        #         if UserSettings.Get(group = 'nviz', key = 'vector',
+        #                             subkey = [v, 'show']):
+        #             vecType.append(v)
+        
+        if points is None:
+            vecTypes = ('points', 'lines')
+        elif points:
+            vecTypes = ('points', )
+        else:
+            vecTypes = ('lines', )
+        
+        for vecType in vecTypes:
+            if 'object' not in data[vecType]:
+                continue
+
+            id = data[vecType]['object']['id']
+            
+            if vecType ==  'lines':
+                ret = self._display.UnloadVector(id, False)
+            else:
+                ret = self._display.UnloadVector(id, True)
+            if ret ==  0:
+                self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \
+                    { 'name': layer.name, 'type' : vecType })
+            else:
+                self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
+                    { 'name' : layer.name, 'type' : vecType })
+            
+            data[vecType].pop('object')
+            
+        if remove and item in self.layers:
+            self.layers.remove(item)
+
+    def ResetView(self):
+        """!Reset to default view"""
+        self.iview['z-exag']['original'], \
+            self.iview['height']['value'], \
+            self.iview['height']['min'], \
+            self.iview['height']['max'] = self._display.SetViewDefault()
+            
+        ## set initial z-exag value at 1X    
+        self.view['z-exag']['value'] = 1.0
+        
+        self.view['z-exag']['min'] = UserSettings.Get(group = 'nviz', key = 'view',
+                                                      subkey = ('z-exag', 'min'))        
+        zexagMax = UserSettings.Get(group = 'nviz', key = 'view',
+                                    subkey = ('z-exag', 'max'))        
+        
+        self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view',
+                                                 subkey = ('position', 'x'))
+        self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view',
+                                                 subkey = ('position', 'y'))
+        self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
+                                                       subkey = ('persp', 'value'))
+        
+        self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
+                                                       subkey = ('twist', 'value'))
+        self._display.ResetRotation()
+        self.iview['rotation'] = None
+        self._display.LookAtCenter()
+        focus = self.iview['focus']
+        focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
+        
+        self.PostViewEvent()
+        
+    def UpdateMapObjProperties(self, event):
+        """!Generic method to update data layer properties"""
+        data = event.data
+        
+        if 'surface' in data:
+            try:
+                id = data['surface']['object']['id']
+            except KeyError:
+                return
+            self.UpdateSurfaceProperties(id, data['surface'])
+            # -> initialized
+            data['surface']['object']['init'] = True
+            
+        elif 'constant' in data:
+            id = data['constant']['object']['id']
+            self.UpdateConstantProperties(id, data['constant'])
+            # -> initialized
+            data['constant']['object']['init'] = True  
+              
+        elif 'volume' in data:
+            id = data['volume']['object']['id']
+            self.UpdateVolumeProperties(id, data['volume'])
+            # -> initialized
+            data['volume']['object']['init'] = True
+            
+        elif 'vector' in data:
+            for type in ('lines', 'points'):
+                if 'object' in data['vector'][type]:
+                    id = data['vector'][type]['object']['id']
+                    self.UpdateVectorProperties(id, data['vector'], type)
+                    # -> initialized
+                    data['vector'][type]['object']['init'] = True
+    
+    def UpdateConstantProperties(self, id, data):
+        """!Update surface map object properties"""
+        self._display.SetSurfaceColor(id = id, map = False, value = data['color'])
+        self._display.SetSurfaceTopo(id = id, map = False, value = data['value'])
+        self._display.SetSurfaceRes(id, data['resolution'], data['resolution'])
+        if data['transp'] == 0:
+            self._display.UnsetSurfaceTransp(id)
+        else:
+            self._display.SetSurfaceTransp(id, map = False, value = data['transp'])
+            
+    def UpdateSurfaceProperties(self, id, data):
+        """!Update surface map object properties"""
+        # surface attributes
+        for attrb in ('color', 'mask',
+                     'transp', 'shine'):
+            if attrb not in data['attribute'] or \
+                    'update' not in data['attribute'][attrb]:
+                continue
+            
+            map = data['attribute'][attrb]['map']
+            value = data['attribute'][attrb]['value']
+            
+            if map is None: # unset
+                # only optional attributes
+                if attrb ==  'mask':
+                    # TODO: invert mask
+                    # TODO: broken in NVIZ
+                    self._display.UnsetSurfaceMask(id)
+                elif attrb ==  'transp':
+                    self._display.UnsetSurfaceTransp(id) 
+            else:
+                if type(value) == types.StringType and \
+                        len(value) <=  0: # ignore empty values (TODO: warning)
+                    continue
+                if attrb ==  'color':
+                    self._display.SetSurfaceColor(id, map, str(value))
+                elif attrb ==  'mask':
+                    # TODO: invert mask
+                    # TODO: broken in NVIZ
+                    self._display.SetSurfaceMask(id, False, str(value))
+                elif attrb ==  'transp':
+                    self._display.SetSurfaceTransp(id, map, str(value)) 
+                elif attrb ==  'shine':
+                    self._display.SetSurfaceShine(id, map, str(value)) 
+            data['attribute'][attrb].pop('update')
+        
+        # draw res
+        if 'update' in data['draw']['resolution']:
+            coarse = data['draw']['resolution']['coarse']
+            fine   = data['draw']['resolution']['fine']
+            
+            if data['draw']['all']:
+                self._display.SetSurfaceRes(-1, fine, coarse)
+            else:
+                self._display.SetSurfaceRes(id, fine, coarse)
+            data['draw']['resolution'].pop('update')
+        
+        # draw style
+        if 'update' in data['draw']['mode']:
+            if data['draw']['mode']['value'] < 0: # need to calculate
+                data['draw']['mode']['value'] = \
+                    self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'],
+                                                 style = data['draw']['mode']['desc']['style'],
+                                                 shade = data['draw']['mode']['desc']['shading'],
+                                                 string = True)
+            style = data['draw']['mode']['value']
+            if data['draw']['all']:
+                self._display.SetSurfaceStyle(-1, style)
+            else:
+                self._display.SetSurfaceStyle(id, style)
+            data['draw']['mode'].pop('update')
+        
+        # wire color
+        if 'update' in data['draw']['wire-color']:
+            color = data['draw']['wire-color']['value']
+            if data['draw']['all']:
+                self._display.SetWireColor(-1, str(color))
+            else:
+                self._display.SetWireColor(id, str(color))
+            data['draw']['wire-color'].pop('update')
+        
+        # position
+        if 'update' in data['position']:
+            x = data['position']['x']
+            y = data['position']['y']
+            z = data['position']['z']
+            self._display.SetSurfacePosition(id, x, y, z)
+            data['position'].pop('update')
+        data['draw']['all'] = False
+        
+    def UpdateVolumeProperties(self, id, data, isosurfId = None):
+        """!Update volume (isosurface/slice) map object properties"""
+        if 'update' in data['draw']['resolution']:
+            if data['draw']['mode']['value'] == 0:
+                self._display.SetIsosurfaceRes(id, data['draw']['resolution']['isosurface']['value'])
+            else:
+                self._display.SetSliceRes(id, data['draw']['resolution']['slice']['value'])                
+            data['draw']['resolution'].pop('update')
+        
+        if 'update' in data['draw']['shading']:
+            if data['draw']['mode']['value'] == 0:
+                if data['draw']['shading']['isosurface']['value'] < 0: # need to calculate
+                    mode = data['draw']['shading']['isosurface']['value'] = \
+                        self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['isosurface'],
+                                                     string = False)
+                    self._display.SetIsosurfaceMode(id, mode)
+            else:
+                if data['draw']['shading']['slice']['value'] < 0: # need to calculate
+                    mode = data['draw']['shading']['slice']['value'] = \
+                        self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['slice'],
+                                                     string = False)
+                    self._display.SetSliceMode(id, mode)
+            data['draw']['shading'].pop('update')
+        
+        #
+        # isosurface attributes
+        #
+        isosurfId = 0
+        for isosurf in data['isosurface']:
+            self._display.AddIsosurface(id, 0, isosurf_id = isosurfId)
+            for attrb in ('topo', 'color', 'mask',
+                          'transp', 'shine'):
+                if attrb not in isosurf or \
+                        'update' not in isosurf[attrb]:
+                    continue
+                map = isosurf[attrb]['map']
+                value = isosurf[attrb]['value']
+                
+                if map is None: # unset
+                    # only optional attributes
+                    if attrb == 'topo' :
+                        self._display.SetIsosurfaceTopo(id, isosurfId, map, str(value))
+                    elif attrb ==  'mask':
+                        # TODO: invert mask
+                        # TODO: broken in NVIZ
+                        self._display.UnsetIsosurfaceMask(id, isosurfId)
+                    elif attrb ==  'transp':
+                        self._display.UnsetIsosurfaceTransp(id, isosurfId) 
+                else:
+                    if type(value) == types.StringType and \
+                            len(value) <=  0: # ignore empty values (TODO: warning)
+                        continue
+                    elif attrb ==  'color':
+                        self._display.SetIsosurfaceColor(id, isosurfId, map, str(value))
+                    elif attrb ==  'mask':
+                        # TODO: invert mask
+                        # TODO: broken in NVIZ
+                        self._display.SetIsosurfaceMask(id, isosurfId, False, str(value))
+                    elif attrb ==  'transp':
+                        self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value)) 
+                    elif attrb ==  'shine':
+                        self._display.SetIsosurfaceShine(id, isosurfId, map, str(value))  
+                isosurf[attrb].pop('update')
+            isosurfId +=  1
+        #
+        # slice attributes
+        #
+        sliceId = 0
+        for slice in data['slice']:
+            ret = self._display.AddSlice(id, slice_id = sliceId)
+            if 'update' in slice['position']:
+                pos = slice['position']
+                ret = self._display.SetSlicePosition(id, sliceId, pos['x1'], pos['x2'],
+                                               pos['y1'], pos['y2'], pos['z1'], pos['z2'], pos['axis'])
+                
+                slice['position'].pop('update')
+            if 'update' in slice['transp']:
+                tr = slice['transp']['value']
+                self._display.SetSliceTransp(id, sliceId, tr)
+            sliceId += 1
+                
+        # position
+        if 'update' in data['position']:
+            x = data['position']['x']
+            y = data['position']['y']
+            z = data['position']['z']
+            self._display.SetVolumePosition(id, x, y, z)
+            data['position'].pop('update')
+            
+    def UpdateVectorProperties(self, id, data, type):
+        """!Update vector layer properties
+        
+        @param id layer id
+        @param data properties
+        @param type lines/points
+        """
+        if type ==  'points':
+            self.UpdateVectorPointsProperties(id, data[type])
+        else:
+            self.UpdateVectorLinesProperties(id, data[type])
+        
+    def UpdateVectorLinesProperties(self, id, data):
+        """!Update vector line map object properties"""
+        # mode
+        if 'update' in data['color'] or \
+                'update' in data['width'] or \
+                'update' in data['mode']:
+            width = data['width']['value']
+            color = data['color']['value']
+            if data['mode']['type'] ==  'flat':
+                flat = True
+                if 'surface' in data['mode']:
+                    data['mode'].pop('surface')
+            else:
+                flat = False
+            
+            self._display.SetVectorLineMode(id, color,
+                                            width, flat)
+            
+            if 'update' in data['color']:
+                data['color'].pop('update')
+            if 'update' in data['width']:
+                data['width'].pop('update')
+        
+        # height
+        if 'update' in data['height']:
+            self._display.SetVectorLineHeight(id,
+                                              data['height']['value'])
+            data['height'].pop('update')
+            
+        # thematic
+        if 'update' in data['thematic']:
+            color = width = None
+            colorTable = False
+            if data['thematic']['usecolor'] or data['thematic']['usewidth']:
+                if data['thematic']['usecolor']:
+                    color = data['thematic']['rgbcolumn']
+                    if self._display.CheckColorTable(id = id, type = 'lines'):
+                        colorTable = True
+                if data['thematic']['usewidth']:
+                    width = data['thematic']['sizecolumn']
+                self._display.SetLinesStyleThematic(id = id, layer = data['thematic']['layer'],
+                                                     color = color,
+                                                     colorTable = colorTable, 
+                                                     width = width)
+            else:
+                self._display.UnsetLinesStyleThematic(id = id)
+            data['thematic'].pop('update')
+        # surface
+        if 'surface' in data['mode'] and 'update' in data['mode']:
+            for item in range(len(data['mode']['surface']['value'])):
+                for type in ('raster', 'constant'):
+                    sid = self.GetLayerId(type = type,
+                                          name = data['mode']['surface']['value'][item])
+                    if sid > -1:
+                        if data['mode']['surface']['show'][item]:
+                            self._display.SetVectorLineSurface(id, sid)
+                        else:
+                            self._display.UnsetVectorLineSurface(id, sid)
+                        break
+                
+        if 'update' in data['mode']:
+                data['mode'].pop('update')
+        
+    def UpdateVectorPointsProperties(self, id, data):
+        """!Update vector point map object properties"""
+        if 'update' in data['size'] or \
+                'update' in data['width'] or \
+                'update' in data['marker'] or \
+                'update' in data['color']:
+                
+            ret = self._display.SetVectorPointMode(id, data['color']['value'],
+                                                   data['width']['value'], float(data['size']['value']),
+                                                   data['marker']['value'] + 1)
+            
+            error = None
+            if ret ==  -1:
+                error = _("Vector point layer not found (id = %d)") % id
+            elif ret ==  -2:
+                error = _("Unable to set data layer properties (id = %d)") % id
+
+            if error:
+                raise GException(_("Setting data layer properties failed.\n\n%s") % error)
+            
+            for prop in ('size', 'width', 'marker', 'color'):
+                if 'update' in data[prop]:
+                    data[prop].pop('update')
+        
+        # height
+        if 'update' in data['height']:
+            self._display.SetVectorPointHeight(id,
+                                               data['height']['value'])
+            data['height'].pop('update')
+        
+        # thematic
+        if 'update' in data['thematic']:
+            color = size = None
+            colorTable = False
+            if data['thematic']['usecolor'] or data['thematic']['usesize']:
+                if data['thematic']['usecolor']:
+                    color = data['thematic']['rgbcolumn']
+                    if self._display.CheckColorTable(id = id, type = 'points'):
+                        colorTable = True
+                if data['thematic']['usesize']:
+                    size = data['thematic']['sizecolumn']
+                self._display.SetPointsStyleThematic(id = id, layer = data['thematic']['layer'],
+                                                     color = color,
+                                                     colorTable = colorTable, 
+                                                     size = size)
+            else:
+                self._display.UnsetPointsStyleThematic(id = id)
+            data['thematic'].pop('update')
+            
+        # surface
+        if 'update' in data['mode'] and 'surface' in data['mode']:
+            for item in range(len(data['mode']['surface']['value'])):
+                for type in ('raster', 'constant'):
+                    sid = self.GetLayerId(type = type,
+                                          name = data['mode']['surface']['value'][item])
+                    if sid > -1:
+                        if data['mode']['surface']['show'][item]:
+                            self._display.SetVectorPointSurface(id, sid)
+                        else:
+                            self._display.UnsetVectorPointSurface(id, sid)   
+                        break
+            data['mode'].pop('update')
+            
+    def GetLayerNames(self, type):
+        """!Return list of map layer names of given type"""
+        layerName = []
+        
+        if type == 'constant':
+            for item in self.constants:
+                layerName.append(_("constant#") + str(item['constant']['object']['name']))
+        else:    
+            for item in self.layers:
+                mapLayer = self.tree.GetPyData(item)[0]['maplayer']
+                if type !=  mapLayer.GetType():
+                    continue
+                
+                layerName.append(mapLayer.GetName())
+        
+        return layerName
+    
+    def GetLayerId(self, type, name, vsubtyp = None):
+        """!Get layer object id or -1"""
+        if len(name) < 1:
+            return -1
+        
+        if type == 'constant':
+            for item in self.constants:
+                if _("constant#") + str(item['constant']['object']['name']) == name:
+                    return item['constant']['object']['id']
+                
+        
+        for item in self.layers:
+            mapLayer = self.tree.GetPyData(item)[0]['maplayer']
+            if type !=  mapLayer.GetType() or \
+                    name !=  mapLayer.GetName():
+                continue
+            
+            data = self.tree.GetPyData(item)[0]['nviz']
+            
+            try:
+                if type ==  'raster':
+                    return data['surface']['object']['id']
+                elif type ==  'vector':
+                    if vsubtyp == 'vpoint':
+                        return data['vector']['points']['object']['id']
+                    elif vsubtyp ==  'vline':
+                        return data['vector']['lines']['object']['id']
+                elif type ==  '3d-raster':
+                    return data['volume']['object']['id']
+            except KeyError:
+                return -1
+        return -1
+    
+    def ReloadLayersData(self):
+        """!Delete nviz data of all loaded layers and reload them from current settings"""
+        for item in self.layers:
+            type = self.tree.GetPyData(item)[0]['type']
+            layer = self.tree.GetPyData(item)[0]['maplayer']
+            data = self.tree.GetPyData(item)[0]['nviz']
+            
+            if type == 'raster':
+                self.nvizDefault.SetSurfaceDefaultProp(data['surface'])
+            if type == 'vector':
+                npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
+                if npoints > 0:
+                    self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
+                if nlines > 0:
+                    self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
+            
+    def NvizCmdCommand(self):
+        """!Generate command for m.nviz.image according to current state"""
+        cmd = 'm.nviz.image '
+        
+        rasters = []
+        vectors = []
+        volumes = []
+        for item in self.layers:
+            if self.tree.GetPyData(item)[0]['type'] == 'raster':
+                rasters.append(item)
+            elif self.tree.GetPyData(item)[0]['type'] == '3d-raster':
+                volumes.append(item)
+            elif self.tree.GetPyData(item)[0]['type'] == 'vector':
+                vectors.append(item)
+        if not rasters and not self.constants:
+            return _("At least one raster map required")
+        # elevation_map/elevation_value
+        if self.constants:
+            subcmd = "elevation_value="
+            for constant in self.constants:
+                subcmd += "%d," % constant['constant']['value']
+            subcmd = subcmd.strip(', ') + ' '
+            cmd += subcmd
+        if rasters:
+            subcmd = "elevation_map="
+            for item in rasters:
+                subcmd += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
+            subcmd = subcmd.strip(', ') + ' '
+            cmd += subcmd
+            #
+            # draw mode
+            #
+            cmdMode = "mode="
+            cmdFine = "resolution_fine="
+            cmdCoarse = "resolution_coarse="
+            cmdShading = "shading="
+            cmdStyle = "style="
+            cmdWire = "wire_color="
+            # test -a flag
+            flag_a = "-a "
+            nvizDataFirst = self.tree.GetPyData(rasters[0])[0]['nviz']['surface']['draw']
+            for item in rasters:
+                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
+                if nvizDataFirst != nvizData:
+                    flag_a = ""
+            cmd += flag_a
+            for item in rasters:
+                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
+                
+                cmdMode += "%s," % nvizData['mode']['desc']['mode']
+                cmdFine += "%s," % nvizData['resolution']['fine']
+                cmdCoarse += "%s," % nvizData['resolution']['coarse']
+                cmdShading += "%s," % nvizData['mode']['desc']['shading']
+                cmdStyle += "%s," % nvizData['mode']['desc']['style']
+                cmdWire += "%s," % nvizData['wire-color']['value']
+            for item in self.constants:
+                cmdMode += "fine,"
+                cmdFine += "%s," % item['constant']['resolution']
+                cmdCoarse += "%s," % item['constant']['resolution']
+                cmdShading += "gouraud,"
+                cmdStyle += "surface,"
+                cmdWire += "0:0:0,"
+            mode = []
+            for subcmd in (cmdMode, cmdFine, cmdCoarse, cmdShading, cmdStyle, cmdWire):
+                if flag_a:
+                    mode.append(subcmd.split(',')[0] + ' ')
+                else:
+                    subcmd = subcmd.strip(', ') + ' '
+                    cmd += subcmd
+            if flag_a:# write only meaningful possibilities
+                cmd += mode[0]
+                if 'fine' in mode[0]:
+                    cmd += mode[1]
+                elif 'coarse' in mode[0]:
+                    cmd += mode[2]            
+                elif 'both' in mode[0]:
+                    cmd += mode[2]
+                    cmd += mode[1]
+                if 'flat' in mode[3]:
+                    cmd += mode[3]
+                if 'wire' in mode[4]:
+                    cmd += mode[4]
+                if 'coarse' in mode[0] or 'both' in mode[0] and 'wire' in mode[3]:
+                    cmd += mode[5]
+            #
+            # attributes
+            #
+            cmdColorMap = "color_map="
+            cmdColorVal = "color="
+            for item in rasters:
+                nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['attribute']
+                if 'color' not in nvizData:
+                    cmdColorMap += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
+                else:
+                    if nvizData['color']['map']:
+                        cmdColorMap += "%s," % nvizData['color']['value']
+                    else:
+                        cmdColorVal += "%s," % nvizData['color']['value']
+                        #TODO
+                        # transparency, shine, mask
+            for item in self.constants:
+                cmdColorVal += "%s," % item['constant']['color']
+            if cmdColorMap.split("=")[1]:
+                cmd += cmdColorMap.strip(', ') + ' '
+            if cmdColorVal.split("=")[1]:
+                cmd += cmdColorVal.strip(', ') + ' '
+            cmd += "\\\n"
+        #
+        # vlines
+        #
+        if vectors:
+            cmdLines = cmdLWidth = cmdLHeight = cmdLColor = cmdLMode = cmdLPos = \
+            cmdPoints = cmdPWidth = cmdPSize = cmdPColor = cmdPMarker = cmdPPos = cmdPLayer = ""
+            markers = ['x', 'box', 'sphere', 'cube', 'diamond',
+                       'dec_tree', 'con_tree', 'aster', 'gyro', 'histogram']
+            for vector in vectors:
+                npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(
+                                                      self.tree.GetPyData(vector)[0]['maplayer'])
+                nvizData = self.tree.GetPyData(vector)[0]['nviz']['vector']
+                if nlines > 0:
+                    cmdLines += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
+                    cmdLWidth += "%d," % nvizData['lines']['width']['value']
+                    cmdLHeight += "%d," % nvizData['lines']['height']['value']
+                    cmdLColor += "%s," % nvizData['lines']['color']['value']
+                    cmdLMode += "%s," % nvizData['lines']['mode']['type']
+                    cmdLPos += "0,0,%d," % nvizData['lines']['height']['value']
+                if npoints > 0:    
+                    cmdPoints += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
+                    cmdPWidth += "%d," % nvizData['points']['width']['value']
+                    cmdPSize += "%d," % nvizData['points']['size']['value']
+                    cmdPColor += "%s," % nvizData['points']['color']['value']
+                    cmdPMarker += "%s," % markers[nvizData['points']['marker']['value']]
+                    cmdPPos += "0,0,%d," % nvizData['points']['height']['value']
+                    cmdPLayer += "1,1,"
+            if cmdLines:
+                cmd += "vline=" + cmdLines.strip(',') + ' '
+                cmd += "vline_width=" + cmdLWidth.strip(',') + ' '
+                cmd += "vline_color=" + cmdLColor.strip(',') + ' '
+                cmd += "vline_height=" + cmdLHeight.strip(',') + ' '
+                cmd += "vline_mode=" + cmdLMode.strip(',') + ' '
+                cmd += "vline_position=" + cmdLPos.strip(',') + ' '
+            if cmdPoints:
+                cmd += "vpoint=" + cmdPoints.strip(',') + ' '
+                cmd += "vpoint_width=" + cmdPWidth.strip(',') + ' '
+                cmd += "vpoint_color=" + cmdPColor.strip(',') + ' '
+                cmd += "vpoint_size=" + cmdPSize.strip(',') + ' '
+                cmd += "vpoint_marker=" + cmdPMarker.strip(',') + ' '
+                cmd += "vpoint_position=" + cmdPPos.strip(',') + ' '
+                cmd += "vpoint_layer=" + cmdPLayer.strip(',') + ' '
+            cmd += "\\\n"
+            
+        #
+        # volumes
+        #
+        if volumes:
+            cmdName = cmdShade = cmdRes = cmdPos = cmdIso = ""
+            cmdIsoColorMap = cmdIsoColorVal = cmdIsoTrMap = cmdIsoTrVal = ""
+            cmdSlice = cmdSliceTransp = cmdSlicePos = ""
+            for i, volume in enumerate(volumes):
+                nvizData = self.tree.GetPyData(volume)[0]['nviz']['volume']
+                cmdName += "%s," % self.tree.GetPyData(volume)[0]['maplayer'].GetName()
+                cmdShade += "%s," % nvizData['draw']['shading']['isosurface']['desc']
+                cmdRes += "%d," % nvizData['draw']['resolution']['isosurface']['value']
+                if nvizData['position']:
+                    cmdPos += "%d,%d,%d," % (nvizData['position']['x'], nvizData['position']['y'],
+                                            nvizData['position']['z'])
+                for iso in nvizData['isosurface']:
+                    level = iso['topo']['value']
+                    cmdIso += "%d:%s," % (i + 1, level)
+                    if iso['color']['map']:
+                        cmdIsoColorMap += "%s," % iso['color']['value']
+                    else:
+                        cmdIsoColorVal += "%s," % iso['color']['value']
+                    if 'transp' in iso:
+                        if iso['transp']['map']:
+                            cmdIsoTrMap += "%s," % iso['transp']['value']
+                        else:
+                            cmdIsoTrVal += "%s," % iso['transp']['value']     
+                            
+                for slice in nvizData['slice']:
+                    axis = ('x','y','z')[slice['position']['axis']]
+                    cmdSlice += "%d:%s," % (i + 1, axis)
+                    for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
+                        cmdSlicePos += "%f," % slice['position'][coord]
+                    cmdSliceTransp += "%s," % slice['transp']['value']
+                        
+            cmd += "volume=" + cmdName.strip(',') + ' '
+            cmd += "volume_shading=" + cmdShade.strip(',') + ' '
+            cmd += "volume_resolution=" + cmdRes.strip(',') + ' '
+            if nvizData['position']:
+                cmd += "volume_position=" + cmdPos.strip(',') + ' '
+            if cmdIso:
+                cmd += "isosurf_level=" + cmdIso.strip(',') + ' '
+                if cmdIsoColorMap:
+                    cmd += "isosurf_color_map=" + cmdIsoColorMap.strip(',') + ' '
+                if cmdIsoColorVal:
+                    cmd += "isosurf_color_value=" + cmdIsoColorVal.strip(',') + ' ' 
+                if cmdIsoTrMap:
+                    cmd += "isosurf_transp_map=" + cmdIsoTrMap.strip(',') + ' '
+                if cmdIsoTrVal:
+                    cmd += "isosurf_transp_value=" + cmdIsoTrVal.strip(',') + ' '
+            if cmdSlice:
+                cmd += "slice=" + cmdSlice.strip(',') + ' '
+                cmd += "slice_position=" + cmdSlicePos.strip(',') + ' '
+                cmd += "slice_transparency=" + cmdSliceTransp.strip(',') + ' '
+                
+        #
+        # cutting planes
+        #
+        cplane = self.lmgr.nviz.FindWindowById(self.lmgr.nviz.win['cplane']['planes']).GetStringSelection()
+        try:
+            planeIndex = int(cplane.split()[-1]) - 1
+        except (IndexError, ValueError):
+            planeIndex = None
+        if planeIndex is not None:
+            shading = ['clear', 'top', 'bottom', 'blend', 'shaded']
+            cmd += "cplane=%d " % planeIndex
+            cmd += "cplane_rotation=%d " % self.cplanes[planeIndex]['rotation']['rot']
+            cmd += "cplane_tilt=%d " % self.cplanes[planeIndex]['rotation']['tilt']
+            cmd += "cplane_position=%d,%d,%d " % (self.cplanes[planeIndex]['position']['x'],
+                                           self.cplanes[planeIndex]['position']['y'],
+                                           self.cplanes[planeIndex]['position']['z'])
+            cmd += "cplane_shading=%s " % shading[self.cplanes[planeIndex]['shading']]
+            cmd += "\\\n"                                        
+        # 
+        # viewpoint
+        #
+        subcmd  = "position=%.2f,%.2f " % (self.view['position']['x'], self.view['position']['y'])
+        subcmd += "height=%d " % (self.iview['height']['value'])
+        subcmd += "perspective=%d " % (self.view['persp']['value'])
+        subcmd += "twist=%d " % (self.view['twist']['value'])
+        subcmd += "zexag=%d " % (self.view['z-exag']['value'] * self.iview['z-exag']['original'])
+        subcmd += "focus=%d,%d,%d " % (self.iview['focus']['x'],self.iview['focus']['y'],self.iview['focus']['z'])
+        cmd += subcmd
+        
+        # background
+        subcmd  = "bgcolor=%d:%d:%d " % (self.view['background']['color'][:3])
+        if self.view['background']['color'] != (255, 255, 255):
+            cmd += subcmd
+        cmd += "\\\n"
+        # light
+        subcmd  = "light_position=%.2f,%.2f,%.2f " % (self.light['position']['x'],
+                                                      self.light['position']['y'],
+                                                      self.light['position']['z']/100.)
+        subcmd += "light_brightness=%d " % (self.light['bright'])
+        subcmd += "light_ambient=%d " % (self.light['ambient'])
+        subcmd += "light_color=%d:%d:%d " % (self.light['color'][:3])
+        cmd += subcmd
+        cmd += "\\\n"
+        # fringe
+        toolWindow = self.lmgr.nviz
+        direction = ''
+        for dir in ('nw', 'ne', 'sw', 'se'):
+            if toolWindow.FindWindowById(toolWindow.win['fringe'][dir]).IsChecked():
+                direction += "%s," % dir
+        if direction:
+            subcmd = "fringe=%s " % (direction.strip(','))
+            color = toolWindow.FindWindowById(toolWindow.win['fringe']['color']).GetValue()
+            subcmd += "fringe_color=%d:%d:%d " % (color[0], color[1], color[2])
+            subcmd += "fringe_elevation=%d " % (toolWindow.FindWindowById(toolWindow.win['fringe']['elev']).GetValue())
+            cmd += subcmd
+            cmd += "\\\n"
+        # north arrow
+        if self.decoration['arrow']['show']:
+            subcmd = "arrow_position=%d,%d " % (self.decoration['arrow']['position']['x'],
+                                                self.decoration['arrow']['position']['y'])
+            subcmd += "arrow_color=%s " % self.decoration['arrow']['color']
+            subcmd += "arrow_size=%d " % self.decoration['arrow']['size']
+            cmd += subcmd
+            
+        # output
+        subcmd = 'output=nviz_output '
+        subcmd += 'format=ppm '
+        subcmd += 'size=%d,%d ' % self.GetClientSizeTuple()
+        cmd += subcmd
+        
+        return cmd
+    
+    def OnNvizCmd(self):
+        """!Generate and write command to command output"""
+        self.log.WriteLog(self.NvizCmdCommand(), switchPage = True)
+        
+    def SaveToFile(self, FileName, FileType, width, height):
+        """!This draws the DC to a buffer that can be saved to a file.
+        
+        @todo fix BufferedPaintDC
+        
+        @param FileName file name
+        @param FileType type of bitmap
+        @param width image width
+        @param height image height
+        """
+        self._display.SaveToFile(FileName, width, height, FileType)
+                
+        # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
+        # dc = wx.BufferedPaintDC(self, pbuffer)
+        # dc.Clear()
+        # self.SetCurrent()
+        # self._display.Draw(False, -1)
+        # pbuffer.SaveFile(FileName, FileType)
+        # self.SwapBuffers()
+        
+    def GetDisplay(self):
+        """!Get display instance"""
+        return self._display
+        
+    def ZoomToMap(self, layers):
+        """!Reset view
+        
+        @param layers so far unused
+        """
+        self.lmgr.nviz.OnResetView(None)
+        
+    def TextBounds(self, textinfo):
+        """!Return text boundary data
+        
+        @param textinfo text metadata (text, font, color, rotation)
+        """
+        return self.parent.MapWindow2D.TextBounds(textinfo, relcoords = True)

Copied: grass/trunk/gui/wxpython/nviz/preferences.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/nviz_preferences.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/preferences.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,628 @@
+"""
+ at package nviz.preferences
+
+ at brief Nviz (3D view) preferences window
+
+Classes:
+ - NvizPreferencesDialog
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Enhancements by Michael Barton <michael.barton asu.edu>
+ at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
+"""
+
+import copy
+
+import wx
+import wx.lib.colourselect as csel
+
+from core                 import globalvar
+from core.settings        import UserSettings
+from gui_core.preferences import PreferencesBaseDialog
+
+class NvizPreferencesDialog(PreferencesBaseDialog):
+    """!Nviz preferences dialog"""
+    def __init__(self, parent, title = _("3D view settings"),
+                 settings = UserSettings):
+        PreferencesBaseDialog.__init__(self, parent = parent, title = title,
+                                       settings = settings)
+        self.toolWin = self.parent.nviz
+        
+        # create notebook pages
+        self._createViewPage(self.notebook)
+        self._createFlyPage(self.notebook)
+        self._createLightPage(self.notebook)
+        self._createSurfacePage(self.notebook)
+        self._createVectorPage(self.notebook)
+        
+        self.SetMinSize(self.GetBestSize())
+        self.SetSize(self.size)
+        self.btnDefault.SetToolTipString(_("Revert settings to default, changes are not applied"))
+        
+    def _createViewPage(self, notebook):
+        """!Create notebook page for view settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("View"))
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("View")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        row = 0
+        # perspective
+        pvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'persp')
+        ipvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'persp', internal = True)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Perspective:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("value:")),
+                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        pval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = pvals['value'],
+                           min = ipvals['min'],
+                           max = ipvals['max'])
+        self.winId['nviz:view:persp:value'] = pval.GetId()
+        gridSizer.Add(item = pval, pos = (row, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("step:")),
+                      pos = (row, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        pstep = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = pvals['step'],
+                           min = ipvals['min'],
+                           max = ipvals['max']-1)
+        self.winId['nviz:view:persp:step'] = pstep.GetId()
+        gridSizer.Add(item = pstep, pos = (row, 4),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1
+        
+        # position
+        posvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'position')
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Position:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("x:")),
+                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        px = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = posvals['x'] * 100,
+                           min = 0,
+                           max = 100)
+        self.winId['nviz:view:position:x'] = px.GetId()
+        gridSizer.Add(item = px, pos = (row, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "y:"),
+                      pos = (row, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        py = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = posvals['y'] * 100,
+                           min = 0,
+                           max = 100)
+        self.winId['nviz:view:position:y'] = py.GetId()
+        gridSizer.Add(item = py, pos = (row, 4),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1
+        
+        # height is computed dynamically
+        
+        # twist
+        tvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'twist')
+        itvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'twist', internal = True)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Twist:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("value:")),
+                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        tval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = tvals['value'],
+                           min = itvals['min'],
+                           max = itvals['max'])
+        self.winId['nviz:view:twist:value'] = tval.GetId()
+        gridSizer.Add(item = tval, pos = (row, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        row += 1
+        
+        # z-exag
+        zvals = UserSettings.Get(group = 'nviz', key = 'view', subkey = 'z-exag')
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Z-exag:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("value:")),
+                      pos = (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        zval = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = zvals['value'],
+                           min = -1e6,
+                           max = 1e6)
+        self.winId['nviz:view:z-exag:value'] = zval.GetId()
+        gridSizer.Add(item = zval, pos = (row, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+
+        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                           label = " %s " % (_("Image Appearance")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        # background color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Background color:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = UserSettings.Get(group = 'nviz', key = 'view',
+                                                            subkey = ['background', 'color']),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        color.SetName('GetColour')
+        self.winId['nviz:view:background:color'] = color.GetId()
+        gridSizer.Add(item = color, pos = (0, 1))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+        
+    def _createFlyPage(self, notebook):
+        """!Create notebook page for view settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("Fly-through"))
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        # fly throuhg mode
+        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                           label = " %s " % (_("Fly-through mode")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        # move exag
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Move exag:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        moveExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
+                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
+                                                             subkey = ['exag', 'move']),
+                                  size = (65, -1))
+        self.winId['nviz:fly:exag:move'] = moveExag.GetId()
+        gridSizer.Add(item = moveExag, pos = (0, 1))
+        
+        # turn exag
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Turn exag:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        turnExag = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 20, 
+                                  initial = UserSettings.Get(group = 'nviz', key = 'fly',
+                                                             subkey = ['exag', 'turn']),
+                                  size = (65, -1))
+        self.winId['nviz:fly:exag:turn'] = turnExag.GetId()
+        gridSizer.Add(item = turnExag, pos = (1, 1))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+        
+    def _createLightPage(self, notebook):
+        """!Create notebook page for light settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("Lighting"))
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Light")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+
+        
+        # position
+        posvals = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'position')
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Position:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("x:")),
+                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        px = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = posvals['x'] * 100,
+                           min = -100,
+                           max = 100)
+        self.winId['nviz:light:position:x'] = px.GetId()
+        gridSizer.Add(item = px, pos = (0, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = "y:"),
+                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        py = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = posvals['y'] * 100,
+                           min = -100,
+                           max = 100)
+        self.winId['nviz:light:position:y'] = py.GetId()
+        gridSizer.Add(item = py, pos = (0, 4),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+                    
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("z:")),
+                      pos = (0, 5), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        
+        pz = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = posvals['z'],
+                           min = 0,
+                           max = 100)
+        self.winId['nviz:light:position:z'] = pz.GetId()
+        gridSizer.Add(item = pz, pos = (0, 6),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+                    
+        # brightness
+        brightval = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'bright')
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Brightness:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        bright = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = brightval,
+                           min = 0,
+                           max = 100)
+        self.winId['nviz:light:bright'] = bright.GetId()
+        gridSizer.Add(item = bright, pos = (1, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+                    
+        # ambient
+        ambval = UserSettings.Get(group = 'nviz', key = 'light', subkey = 'ambient')
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Ambient:")),
+                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        amb = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = ambval,
+                           min = 0,
+                           max = 100)
+        self.winId['nviz:light:ambient'] = amb.GetId()
+        gridSizer.Add(item = amb, pos = (2, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+                    
+        # light color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Color:")),
+                      pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = UserSettings.Get(group = 'nviz', key = 'light',
+                                                            subkey = 'color'),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        color.SetName('GetColour')
+        self.winId['nviz:light:color'] = color.GetId()
+        gridSizer.Add(item = color, pos = (3, 2))
+        
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+    
+    def _createSurfacePage(self, notebook):
+        """!Create notebook page for surface settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("Surface"))
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # draw
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Draw")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        # mode
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                        label = _("Mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
+                        pos = (0, 0))
+        mode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                          choices = [_("coarse"),
+                                     _("fine"),
+                                     _("both")])
+        self.winId['nviz:surface:draw:mode'] = mode.GetId()
+        mode.SetName('GetSelection')
+        mode.SetSelection(UserSettings.Get(group = 'nviz', key = 'surface',
+                                            subkey = ['draw', 'mode']))
+        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 1))
+                    
+        # fine
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                        label = _("Fine mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
+                        pos = (1, 0))
+        res = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['draw','res-fine'])
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                        label = _("resolution:")), flag = wx.ALIGN_CENTER_VERTICAL,
+                        pos = (1, 1))
+        fine = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = res,
+                           min = 1,
+                           max = 100)
+        self.winId['nviz:surface:draw:res-fine'] = fine.GetId()
+        
+        gridSizer.Add(item = fine, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1, 2))
+                    
+        # coarse
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                        label = _("Coarse mode:")), flag = wx.ALIGN_CENTER_VERTICAL,
+                        pos = (2, 0))
+        res = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['draw','res-coarse'])
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                        label = _("resolution:")), flag = wx.ALIGN_CENTER_VERTICAL,
+                        pos = (2, 1))
+        coarse = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = res,
+                           min = 1,
+                           max = 100)
+        self.winId['nviz:surface:draw:res-coarse'] = coarse.GetId()
+        
+        gridSizer.Add(item = coarse, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 2))
+        #style
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+            label = _("style:")), flag = wx.ALIGN_CENTER_VERTICAL,
+            pos = (3, 1))
+        style = wx.Choice(parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                          choices = [_("wire"),
+                                     _("surface")])
+        self.winId['nviz:surface:draw:style'] = style.GetId()
+        style.SetName('GetSelection')
+        style.SetSelection(UserSettings.Get(group = 'nviz', key = 'surface',
+                                            subkey = ['draw', 'style']))
+        self.winId['nviz:surface:draw:style'] = style.GetId()
+        
+        gridSizer.Add(item = style, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (3, 2))
+        #wire color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+            label = _("wire color:")), flag = wx.ALIGN_CENTER_VERTICAL,
+            pos = (4, 1))
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = UserSettings.Get(group = 'nviz', key = 'surface',
+                                                            subkey = ['draw', 'wire-color']),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        color.SetName('GetColour')
+        self.winId['nviz:surface:draw:wire-color'] = color.GetId() 
+        gridSizer.Add(item = color, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (4, 2))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)            
+        pageSizer.Add(item = boxSizer, proportion = 0,
+              flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+              border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+    
+    def _createVectorPage(self, notebook):
+        """!Create notebook page for vector settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        
+        notebook.AddPage(page = panel,
+                         text = " %s " % _("Vector"))
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # vector lines
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Vector lines")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        row = 0
+        # icon size
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Width:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        iwidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                            initial = 12,
+                            min = 1,
+                            max = 100)
+        self.winId['nviz:vector:lines:width'] = iwidth.GetId()
+        iwidth.SetValue(UserSettings.Get(group = 'nviz', key = 'vector',
+                                        subkey = ['lines', 'width']))
+        gridSizer.Add(item = iwidth, pos = (row, 1),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        # icon color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Color:")),
+                      pos = (row, 4), flag = wx.ALIGN_CENTER_VERTICAL)
+        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        icolor.SetName('GetColour')
+        self.winId['nviz:vector:lines:color'] = icolor.GetId()
+        icolor.SetColour(UserSettings.Get(group = 'nviz', key = 'vector',
+                                          subkey = ['lines', 'color']))
+        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 5))
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 5)
+        
+        # vector points
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Vector points")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 5)
+        
+        row = 0
+        # icon size
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Size:")),
+                      pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        isize = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                            initial = 100,
+                            min = 1,
+                            max = 1e6)
+        self.winId['nviz:vector:points:size'] = isize.GetId()
+        isize.SetValue(UserSettings.Get(group = 'nviz', key = 'vector',
+                                        subkey = ['points', 'size']))
+        gridSizer.Add(item = isize, pos = (row, 1),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        # icon symbol
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Marker:")),
+                      pos = (row, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        isym = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                          choices = UserSettings.Get(group = 'nviz', key = 'vector',
+                                                   subkey = ['points', 'marker'], internal = True))
+        isym.SetName("GetSelection")
+        self.winId['nviz:vector:points:marker'] = isym.GetId()
+        isym.SetSelection(UserSettings.Get(group = 'nviz', key = 'vector',
+                                           subkey = ['points', 'marker']))
+        gridSizer.Add(item = isym, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 3))
+        
+        # icon color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Color:")),
+                      pos = (row, 4), flag = wx.ALIGN_CENTER_VERTICAL)
+        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        icolor.SetName('GetColour')
+        self.winId['nviz:vector:points:color'] = icolor.GetId()
+        icolor.SetColour(UserSettings.Get(group = 'nviz', key = 'vector',
+                                          subkey = ['points', 'color']))
+        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (row, 5))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 5)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+
+    def OnDefault(self, event):
+        """!Button 'Set to default' pressed"""
+        self.settings.userSettings = copy.deepcopy(self.settings.defaultSettings)
+        
+        # update widgets
+        for gks in self.winId.keys():
+            subkey1 = None
+            try:
+                group, key, subkey = gks.split(':')
+                value = self.settings.Get(group, key, subkey)
+            except ValueError:
+                group, key, subkey, subkey1 = gks.split(':')
+                value = self.settings.Get(group, key, [subkey, subkey1])
+            if subkey == 'position':
+                if subkey1 in ('x', 'y'):
+                    value = float(value) * 100
+            win = self.FindWindowById(self.winId[gks])
+            if win.GetName() == 'GetSelection':
+                value = win.SetSelection(value)
+            else:
+                value = win.SetValue(value)        
+        
+    def OnApply(self, event):
+        """Apply Nviz settings for current session"""
+        for item in self.winId.keys():
+            try:
+                group, key, subkey = item.split(':')
+                subkey1 = None
+            except ValueError:
+                group, key, subkey, subkey1 = item.split(':')
+            
+            id = self.winId[item]
+            win = self.FindWindowById(id)
+            if win.GetName() == 'GetSelection':
+                value = win.GetSelection()
+            elif win.GetName() == 'GetColour':
+                value = tuple(win.GetValue())
+            else:
+                value = win.GetValue()
+            
+            if subkey == 'position':
+                if subkey1 in ('x', 'y'):
+                    value = float(value) / 100
+            if subkey1:
+                self.settings.Set(group, value, key, [subkey, subkey1])
+            else:
+                self.settings.Set(group, value, key, subkey)
+                
+        self.toolWin.LoadSettings()
+        
+        
+    def OnSave(self, event):
+        """!Save button pressed
+        
+        Apply changes and save settings to configuration file
+        """
+        self.OnApply(None)
+        fileSettings = {}
+        UserSettings.ReadSettingsFile(settings = fileSettings)
+        fileSettings['nviz'] = UserSettings.Get(group = 'nviz')
+        
+        UserSettings.SaveToFile(fileSettings)
+        self.parent.goutput.WriteLog(
+                _('3D view settings saved to file <%s>.') % UserSettings.filePath)
+        
+        self.Destroy()
+        

Copied: grass/trunk/gui/wxpython/nviz/tools.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/nviz_tools.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/tools.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/tools.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,5044 @@
+"""!
+ at package nviz.tools
+
+ at brief Nviz (3D view) tools window
+
+Classes:
+ - NvizToolWindow
+ - PositionWindow
+ - ViewPositionWindow
+ - LightPositionWindow
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Enhancements by Michael Barton <michael.barton asu.edu>
+ at author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
+"""
+
+import os
+import copy
+import types
+
+import wx
+import wx.lib.colourselect  as csel
+import wx.lib.scrolledpanel as SP
+import wx.lib.filebrowsebutton as filebrowse
+try:
+    import wx.lib.agw.flatnotebook as FN
+except ImportError:
+    import wx.lib.flatnotebook as FN
+try:
+    from agw import foldpanelbar as fpb
+except ImportError: # if it's not there locally, try the wxPython lib.
+    try:
+        import wx.lib.agw.foldpanelbar as fpb
+    except ImportError:
+        import wx.lib.foldpanelbar as fpb # versions <=2.5.5.1
+        
+import grass.script as grass
+
+from core               import globalvar
+from gui_core.gselect   import VectorDBInfo
+from core.gcmd          import GMessage, RunCommand
+from modules.colorrules import ThematicVectorTable
+from core.settings      import UserSettings
+from nviz.animation     import EVT_ANIM_FIN, EVT_ANIM_UPDATE_IDX
+from gui_core.widgets   import ScrolledPanel, NumTextCtrl, FloatSlider, SymbolButton
+from core.debug         import Debug
+try:
+    from nviz.mapwindow import wxUpdateProperties
+    import nviz.main as wxnviz
+except ImportError:
+    pass
+
+class NvizToolWindow(FN.FlatNotebook):
+    """!Nviz (3D view) tools panel
+    """
+    def __init__(self, parent, display, id = wx.ID_ANY,
+                 style = globalvar.FNPageStyle|FN.FNB_NO_X_BUTTON,
+                 **kwargs):
+        Debug.msg(5, "NvizToolWindow.__init__()")
+        self.parent     = parent # GMFrame
+        self.mapDisplay = display
+        self.mapWindow  = display.GetWindow()
+        self._display   = self.mapWindow.GetDisplay()
+         
+        if globalvar.hasAgw:
+            kwargs['agwStyle'] = style
+        else:
+            kwargs['style'] = style
+        FN.FlatNotebook.__init__(self, parent, id, **kwargs)
+        self.SetTabAreaColour(globalvar.FNPageColor)
+        
+        self.win  = {} # window ids
+        self.page = {} # page ids
+
+        # view page
+        self.AddPage(page = self._createViewPage(),
+                     text = " %s " % _("View"))
+
+        # data page
+        self.AddPage(page = self._createDataPage(),
+                     text = " %s " % _("Data"))
+        
+        # appearance page
+        self.AddPage(page = self._createAppearancePage(),
+                     text = " %s " % _("Appearance"))
+                    
+        # analysis page
+        self.AddPage(page = self._createAnalysisPage(),
+                     text = " %s " % _("Analysis"))
+        # view page
+        self.AddPage(page = self._createAnimationPage(),
+                     text = " %s " % _("Animation"))
+        
+        self.UpdateSettings()
+        
+        self.mapWindow.SetToolWin(self)
+        
+        self.pageChanging = False
+        self.vetoGSelectEvt = False #when setting map, event is invoked
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+        
+        # bindings
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+        self.Bind(EVT_ANIM_FIN, self.OnAnimationFinished)
+        self.Bind(EVT_ANIM_UPDATE_IDX, self.OnAnimationUpdateIndex)
+        
+        Debug.msg(3, "NvizToolWindow.__init__()")
+        
+        self.Update()
+        wx.CallAfter(self.SetPage, 'view')
+        wx.CallAfter(self.UpdateScrolling, (self.foldpanelData, self.foldpanelAppear,
+                                            self.foldpanelAnalysis))       
+        wx.CallAfter(self.SetInitialMaps)
+        
+    def SetInitialMaps(self):
+        """!Set initial raster and vector map"""
+        for l_type in ('raster', 'vector', '3d-raster'):
+            selectedLayer = self.mapWindow.GetSelectedLayer()
+            layers = self.mapWindow.Map.GetListOfLayers(l_type = l_type, l_active = True)
+            if selectedLayer in layers:
+                selection = selectedLayer.GetName()
+            else:
+                try:
+                    selection = layers[0].GetName()
+                except:
+                    continue
+            if l_type == 'raster':
+                self.FindWindowById(self.win['surface']['map']).SetValue(selection)
+                self.FindWindowById(self.win['fringe']['map']).SetValue(selection)
+            elif l_type == 'vector':
+                self.FindWindowById(self.win['vector']['map']).SetValue(selection)
+            elif l_type == '3d-raster':
+                self.FindWindowById(self.win['volume']['map']).SetValue(selection)
+               
+    def UpdateState(self, **kwargs):
+        if 'view' in kwargs:
+            self.mapWindow.view = kwargs['view']
+            self.FindWindowById(self.win['view']['position']).data = kwargs['view']
+            self.FindWindowById(self.win['view']['position']).PostDraw()
+        if 'iview' in kwargs:
+            self.mapWindow.iview = kwargs['iview']
+        if 'light' in kwargs:
+            self.mapWindow.light = kwargs['light']  
+            self.FindWindowById(self.win['light']['position']).data = kwargs['light']  
+            self.FindWindowById(self.win['light']['position']).PostDraw()
+        if 'fly' in kwargs:
+            self.mapWindow.fly['exag'] = kwargs['fly']['exag']
+    
+    def LoadSettings(self):
+        """!Load Nviz settings and apply to current session"""
+        view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
+        light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
+        fly = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'fly')) # copy
+        self.UpdateState(view = view, light = light, fly = fly)
+        self.PostViewEvent(zExag = True)
+        self.PostLightEvent()
+        self.UpdatePage('view')
+        self.UpdatePage('light')
+        
+        self.mapWindow.ReloadLayersData()
+        self.UpdatePage('surface')
+        self.UpdatePage('vector')
+        self.UpdateSettings()
+               
+    def OnPageChanged(self, event):
+        new = event.GetSelection()
+        # self.ChangeSelection(new)
+        
+    def PostViewEvent(self, zExag = False):
+        """!Change view settings"""
+        event = wxUpdateView(zExag = zExag)
+        wx.PostEvent(self.mapWindow, event)
+        
+    def PostLightEvent(self, refresh = False): 
+        """!Change light settings"""   
+        event = wxUpdateLight(refresh = refresh)
+        wx.PostEvent(self.mapWindow, event)
+        
+    def OnSize(self, event):
+        """!After window is resized, update scrolling"""
+        # workaround to resize captionbars of foldpanelbar
+        wx.CallAfter(self.UpdateScrolling, (self.foldpanelData, self.foldpanelAppear,
+                                            self.foldpanelAnalysis)) 
+        event.Skip()
+           
+    def OnPressCaption(self, event):
+        """!When foldpanel item collapsed/expanded, update scrollbars"""
+        foldpanel = event.GetBar().GetGrandParent().GetParent()
+        wx.CallAfter(self.UpdateScrolling, (foldpanel,))
+        event.Skip()
+        
+    def UpdateScrolling(self, foldpanels):
+        """!Update scrollbars in foldpanel"""
+        for foldpanel in foldpanels:
+            length = foldpanel.GetPanelsLength(collapsed = 0, expanded = 0)
+            # virtual width is set to fixed value to suppress GTK warning
+            foldpanel.GetParent().SetVirtualSize((100, length[2]))
+            foldpanel.GetParent().Layout()
+        
+    def _createViewPage(self):
+        """!Create view settings page"""
+        panel = SP.ScrolledPanel(parent = self, id = wx.ID_ANY)
+        panel.SetupScrolling(scroll_x = False)
+        self.page['view'] = { 'id' : 0,
+                              'notebook' : self.GetId()}
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Control View")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 10)
+        
+        self.win['view'] = {}
+        
+        # position
+        posSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        self._createCompass(panel = panel, sizer = posSizer, type = 'view')
+        
+        view = ViewPositionWindow(panel, size = (175, 175),
+                                  mapwindow = self.mapWindow)
+        self.win['view']['position'] = view.GetId()
+        posSizer.Add(item = view,
+                     pos = (1, 1), flag = wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = posSizer, pos = (0, 0))
+                  
+        # perspective
+        # set initial defaults here (or perhaps in a default values file), not in user settings
+        #todo: consider setting an absolute max at 360 instead of undefined. (leave the default max value at pi)
+        self._createControl(panel, data = self.win['view'], name = 'persp',
+                            range = (1,180),
+                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
+        
+        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Perspective:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER)
+        gridSizer.Add(item = self.FindWindowById(self.win['view']['persp']['slider']), pos = (2, 0),
+                      flag = wx.ALIGN_CENTER)
+        gridSizer.Add(item = self.FindWindowById(self.win['view']['persp']['text']), pos = (3, 0),
+                      flag = wx.ALIGN_CENTER)        
+        
+        # twist
+        self._createControl(panel, data = self.win['view'], name = 'twist',
+                            range = (-180,180),
+                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
+        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Twist:")),
+                      pos = (1, 1), flag = wx.ALIGN_CENTER)
+        gridSizer.Add(item = self.FindWindowById(self.win['view']['twist']['slider']), pos = (2, 1))
+        gridSizer.Add(item = self.FindWindowById(self.win['view']['twist']['text']), pos = (3, 1),
+                      flag = wx.ALIGN_CENTER)        
+        
+        # height + z-exag
+        self._createControl(panel, data = self.win['view'], name = 'height', sliderHor = False,
+                            range = (0, 1),
+                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
+        self._createControl(panel, data = self.win['view'], name = 'z-exag', sliderHor = False,
+                            range = (0, 10), floatSlider = True,
+                            bind = (self.OnViewChange, self.OnViewChanged, self.OnViewChangedText))
+        self.FindWindowById(self.win['view']['z-exag']['slider']).SetValue(1)
+        self.FindWindowById(self.win['view']['z-exag']['text']).SetValue(1)
+        
+        heightSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:")),
+                      pos = (0, 0), flag = wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL, span = (1, 2))
+        heightSizer.Add(item = self.FindWindowById(self.win['view']['height']['slider']),
+                        flag = wx.ALIGN_RIGHT, pos = (1, 0))
+        heightSizer.Add(item = self.FindWindowById(self.win['view']['height']['text']),
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT, pos = (1, 1))
+        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Z-exag:")),
+                      pos = (0, 2), flag = wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL, span = (1, 2))
+        heightSizer.Add(item = self.FindWindowById(self.win['view']['z-exag']['slider']),
+                        flag = wx.ALIGN_RIGHT, pos = (1, 2))
+        heightSizer.Add(item = self.FindWindowById(self.win['view']['z-exag']['text']),
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.TOP |
+                        wx.BOTTOM | wx.RIGHT, pos = (1, 3))
+        
+        gridSizer.Add(item = heightSizer, pos = (0, 1), flag = wx.ALIGN_CENTER)
+        
+        # view setup + reset
+        viewSizer = wx.BoxSizer(wx.HORIZONTAL)
+        viewSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY,
+                                           label = _("Look:")),
+                      flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL,
+                      border = 5)
+        here = wx.ToggleButton(panel, id = wx.ID_ANY, label = _("here"))
+        here.Bind(wx.EVT_TOGGLEBUTTON, self.OnLookAt)
+        here.SetName('here')
+        viewSizer.Add(item = here, flag = wx.TOP|wx.BOTTOM|wx.LEFT|wx.ALIGN_CENTER_VERTICAL,
+                      border = 5)
+                    
+        center = wx.Button(panel, id = wx.ID_ANY, label = _("center"))
+        center.Bind(wx.EVT_BUTTON, self.OnLookAt)
+        center.SetName('center')
+        viewSizer.Add(item = center, flag = wx.TOP|wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL,
+                      border = 5)
+                    
+        top = wx.Button(panel, id = wx.ID_ANY, label = _("top"))
+        top.Bind(wx.EVT_BUTTON, self.OnLookAt)
+        top.SetName('top')
+        viewSizer.Add(item = top, flag = wx.TOP|wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL,
+                      border = 5)
+                    
+        reset = wx.Button(panel, id = wx.ID_ANY, label = _("reset"))
+        reset.SetToolTipString(_("Reset to default view"))
+        reset.Bind(wx.EVT_BUTTON, self.OnResetView)
+        viewSizer.Add(item = reset, proportion = 0,
+                      flag = wx.TOP|wx.BOTTOM|wx.RIGHT| wx.ALIGN_RIGHT,
+                      border = 5)
+        
+        gridSizer.AddGrowableCol(2)
+        gridSizer.Add(item = viewSizer, pos = (4, 0), span = (1, 3),
+                      flag = wx.EXPAND)
+        
+        # body
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 2)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 3)
+        
+        box = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+                           label = " %s " % (_("Image Appearance")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(0)
+        
+        # background color
+        self.win['view']['background'] = {}
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Background color:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = UserSettings.Get(group = 'nviz', key = 'view',
+                                                            subkey = ['background', 'color']),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        self.win['view']['background']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnBgColor)
+        gridSizer.Add(item = color, pos = (0, 1))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT,
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+        
+    def _createAnimationPage(self):
+        """!Create view settings page"""
+        panel = SP.ScrolledPanel(parent = self, id = wx.ID_ANY)
+        panel.SetupScrolling(scroll_x = False)
+        self.page['animation'] = { 'id' : 0,
+                                   'notebook' : self.GetId()}
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Animation")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        self.win['anim'] = {}
+        # animation help text
+        help = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                             label = _("Press 'Record' button and start changing the view. "
+                                       "It is recommended to use fly-through mode "
+                                       "(Map Display toolbar) to achieve smooth motion."))
+        self.win['anim']['help'] = help.GetId()
+        hSizer.Add(item = help, proportion = 0)
+        boxSizer.Add(item = hSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 5)
+                     
+        # animation controls
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        record = SymbolButton(parent = panel, id = wx.ID_ANY,
+                              usage = "record", label = _("Record"))
+        play = SymbolButton(parent = panel, id = wx.ID_ANY,
+                            usage = "play", label = _("Play"))
+        pause = SymbolButton(parent = panel, id = wx.ID_ANY,
+                             usage = "pause", label = _("Pause"))
+        stop = SymbolButton(parent = panel, id = wx.ID_ANY,
+                            usage = "stop", label = _("Stop"))
+        
+        self.win['anim']['record'] = record.GetId()
+        self.win['anim']['play'] = play.GetId()
+        self.win['anim']['pause'] = pause.GetId()
+        self.win['anim']['stop'] = stop.GetId()
+                            
+        self._createControl(panel, data = self.win['anim'], name = 'frameIndex',
+                            range = (0, 1), floatSlider = False,
+                            bind = (self.OnFrameIndex, None, self.OnFrameIndexText))
+        frameSlider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
+        frameText = self.FindWindowById(self.win['anim']['frameIndex']['text'])
+        infoLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Total number of frames :"))
+        info = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        self.win['anim']['info'] = info.GetId()
+        
+        fpsLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Frame rate (FPS):"))
+        fps = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = UserSettings.Get(group = 'nviz', key = 'animation', subkey = 'fps'),
+                           min = 1,
+                           max = 50)
+        self.win['anim']['fps'] = fps.GetId()
+        fps.SetToolTipString(_("Frames are recorded with given frequency (FPS). "))
+                            
+        record.Bind(wx.EVT_BUTTON, self.OnRecord)
+        play.Bind(wx.EVT_BUTTON, self.OnPlay)
+        stop.Bind(wx.EVT_BUTTON, self.OnStop)
+        pause.Bind(wx.EVT_BUTTON, self.OnPause)
+        fps.Bind(wx.EVT_SPINCTRL, self.OnFPS)
+        
+        hSizer.Add(item = record, proportion = 0)
+        hSizer.Add(item = play, proportion = 0)
+        hSizer.Add(item = pause, proportion = 0)
+        hSizer.Add(item = stop, proportion = 0)
+        boxSizer.Add(item = hSizer, proportion = 0,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        sliderBox = wx.BoxSizer(wx.HORIZONTAL)
+        sliderBox.Add(item = frameSlider, proportion = 1, border = 5, flag = wx.EXPAND | wx.RIGHT)
+        sliderBox.Add(item = frameText, proportion = 0, border = 5, flag = wx.EXPAND| wx.RIGHT | wx.LEFT)
+        boxSizer.Add(item = sliderBox, proportion = 0, flag = wx.EXPAND)
+        
+        # total number of frames
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer.Add(item = infoLabel, proportion = 0, flag = wx.RIGHT, border = 5)
+        hSizer.Add(item = info, proportion = 0, flag = wx.LEFT, border = 5)
+        
+        boxSizer.Add(item = hSizer, proportion = 0,
+                     flag = wx.ALL | wx.EXPAND, border = 5)
+                     
+        # frames per second
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer.Add(item = fpsLabel, proportion = 0, flag = wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border = 5)
+        hSizer.Add(item = fps, proportion = 0, flag = wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border = 5)
+        
+        boxSizer.Add(item = hSizer, proportion = 0,
+                     flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+                      
+        # save animation
+        self.win['anim']['save'] = {}
+        self.win['anim']['save']['image'] = {}
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Save image sequence")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 10)
+        
+        pwd = os.getcwd()
+        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+                                         labelText = _("Choose a directory:"),
+                                         dialogTitle = _("Choose a directory for images"),
+                                         buttonText = _('Browse'),
+                                         startDirectory = pwd)
+        dir.SetValue(pwd)
+        prefixLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("File prefix:"))
+        prefixCtrl = wx.TextCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
+                                 value = UserSettings.Get(group = 'nviz',
+                                                          key = 'animation', subkey = 'prefix'))
+        prefixCtrl.SetToolTipString(_("Generated files names will look like this: prefix_1.ppm, prefix_2.ppm, ..."))
+        fileTypeLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("File format:"))
+        fileTypeCtrl = wx.Choice(parent = panel, id = wx.ID_ANY, choices = ["PPM", "TIF"])
+        
+        save = wx.Button(parent = panel, id = wx.ID_ANY,
+                         label = "Save")
+                         
+        self.win['anim']['save']['image']['dir'] = dir.GetId()
+        self.win['anim']['save']['image']['prefix'] = prefixCtrl.GetId()
+        self.win['anim']['save']['image']['format'] = fileTypeCtrl.GetId()
+        self.win['anim']['save']['image']['confirm'] = save.GetId()
+        
+        boxSizer.Add(item = dir, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        gridSizer.Add(item = prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        gridSizer.Add(item = prefixCtrl, pos = (0, 1), flag = wx.EXPAND )
+        gridSizer.Add(item = fileTypeLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        gridSizer.Add(item = fileTypeCtrl, pos = (1, 1), flag = wx.EXPAND )
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 5)
+        boxSizer.Add(item = save, proportion = 0, flag = wx.ALL | wx.ALIGN_RIGHT, border = 5)
+        
+        save.Bind(wx.EVT_BUTTON, self.OnSaveAnimation)
+        
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+        
+        return panel
+        
+    def _createDataPage(self):
+        """!Create data (surface, vector, volume) settings page"""
+
+        self.mainPanelData = ScrolledPanel(parent = self)
+        self.mainPanelData.SetupScrolling(scroll_x = False)
+        try:# wxpython <= 2.8.10
+            self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,
+                                                  style = fpb.FPB_DEFAULT_STYLE,
+                                                  extraStyle = fpb.FPB_SINGLE_FOLD)
+        except:
+            try:# wxpython >= 2.8.11
+                self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,                               
+                                                      agwStyle = fpb.FPB_SINGLE_FOLD)
+            except: # to be sure
+                self.foldpanelData = fpb.FoldPanelBar(parent = self.mainPanelData, id = wx.ID_ANY,                               
+                                                      style = fpb.FPB_SINGLE_FOLD)
+            
+                     
+        self.foldpanelData.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
+
+
+        
+        # surface page
+        self.surfacePanel = self.foldpanelData.AddFoldPanel(_("Surface"), collapsed = False)
+        self.foldpanelData.AddFoldPanelWindow(self.surfacePanel, 
+            window = self._createSurfacePage(parent = self.surfacePanel), flags = fpb.FPB_ALIGN_WIDTH)
+        self.EnablePage("surface", enabled = False)
+        
+        # constant page
+        constantPanel = self.foldpanelData.AddFoldPanel(_("Constant surface"), collapsed = True)
+        self.foldpanelData.AddFoldPanelWindow(constantPanel,
+            window = self._createConstantPage(parent = constantPanel), flags = fpb.FPB_ALIGN_WIDTH)
+        self.EnablePage("constant", enabled = False)
+        # vector page
+        vectorPanel = self.foldpanelData.AddFoldPanel(_("Vector"), collapsed = True)
+        self.foldpanelData.AddFoldPanelWindow(vectorPanel, 
+            window = self._createVectorPage(parent = vectorPanel), flags = fpb.FPB_ALIGN_WIDTH)
+        self.EnablePage("vector", enabled = False)
+        
+        # volume page
+        volumePanel = self.foldpanelData.AddFoldPanel(_("Volume"), collapsed = True)
+        self.foldpanelData.AddFoldPanelWindow(volumePanel,
+            window = self._createVolumePage(parent = volumePanel), flags = fpb.FPB_ALIGN_WIDTH)
+        self.EnablePage("volume", enabled = False)
+        
+##        self.foldpanelData.ApplyCaptionStyleAll(style)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.foldpanelData, proportion = 1, flag = wx.EXPAND)
+        self.mainPanelData.SetSizer(sizer)
+        self.mainPanelData.Layout()
+        self.mainPanelData.Fit()
+        
+        return self.mainPanelData
+        
+        
+    def _createAppearancePage(self):
+        """!Create data (surface, vector, volume) settings page"""
+        self.mainPanelAppear = ScrolledPanel(parent = self)
+        self.mainPanelAppear.SetupScrolling(scroll_x = False)
+        
+        try:# wxpython <= 2.8.10
+            self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,
+                                                  style = fpb.FPB_DEFAULT_STYLE,
+                                                  extraStyle = fpb.FPB_SINGLE_FOLD)
+        except:
+            try:# wxpython >= 2.8.11
+                self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,                               
+                                                      agwStyle = fpb.FPB_SINGLE_FOLD)
+            except: # to be sure
+                self.foldpanelAppear = fpb.FoldPanelBar(parent = self.mainPanelAppear, id = wx.ID_ANY,                               
+                                                      style = fpb.FPB_SINGLE_FOLD)
+            
+        self.foldpanelAppear.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
+        # light page
+        lightPanel = self.foldpanelAppear.AddFoldPanel(_("Lighting"), collapsed = False)
+        self.foldpanelAppear.AddFoldPanelWindow(lightPanel, 
+            window = self._createLightPage(parent = lightPanel), flags = fpb.FPB_ALIGN_WIDTH)
+    
+        # fringe page
+        fringePanel = self.foldpanelAppear.AddFoldPanel(_("Fringe"), collapsed = True)
+        self.foldpanelAppear.AddFoldPanelWindow(fringePanel, 
+            window = self._createFringePage(parent = fringePanel), flags = fpb.FPB_ALIGN_WIDTH)
+        
+        self.EnablePage('fringe', False)
+        
+        # decoration page
+        decorationPanel = self.foldpanelAppear.AddFoldPanel(_("Decorations"), collapsed = True)
+        self.foldpanelAppear.AddFoldPanelWindow(decorationPanel, 
+            window = self._createDecorationPage(parent = decorationPanel), flags = fpb.FPB_ALIGN_WIDTH)
+        
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.foldpanelAppear, proportion = 1, flag = wx.EXPAND)
+        self.mainPanelAppear.SetSizer(sizer)
+        self.mainPanelAppear.Layout()
+        self.mainPanelAppear.Fit()
+        return self.mainPanelAppear
+    
+    def _createAnalysisPage(self):
+        """!Create data analysis (cutting planes, ...) page"""
+        self.mainPanelAnalysis = ScrolledPanel(parent = self)
+        self.mainPanelAnalysis.SetupScrolling(scroll_x = False)
+        self.foldpanelAnalysis = fpb.FoldPanelBar(parent = self.mainPanelAnalysis, id = wx.ID_ANY,
+                                                  style = fpb.FPB_SINGLE_FOLD)
+        self.foldpanelAnalysis.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption)
+        # cutting planes page
+        cplanePanel = self.foldpanelAnalysis.AddFoldPanel(_("Cutting planes"), collapsed = False)
+        self.foldpanelAnalysis.AddFoldPanelWindow(cplanePanel, 
+            window = self._createCPlanePage(parent = cplanePanel), flags = fpb.FPB_ALIGN_WIDTH)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.foldpanelAnalysis, proportion = 1, flag = wx.EXPAND)
+        self.mainPanelAnalysis.SetSizer(sizer)
+        self.mainPanelAnalysis.Layout()
+        self.mainPanelAnalysis.Fit()
+        return self.mainPanelAnalysis
+        
+    def _createSurfacePage(self, parent):
+        """!Create view settings page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        self.page['surface'] = { 'id' : 0,
+                                 'notebook' : self.foldpanelData.GetId() }
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        self.win['surface'] = {}
+        
+        # selection
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Raster map")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        rmaps = Select(parent = panel, type = 'raster',
+                       onPopup = self.GselectOnPopup)
+        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetRaster)
+        self.win['surface']['map'] = rmaps.GetId()
+        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        self.win['surface']['desc'] = desc.GetId()
+        boxSizer.Add(item = rmaps, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        boxSizer.Add(item = desc, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        #
+        # draw
+        #
+        self.win['surface']['draw'] = {}
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Draw")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(3)
+        
+        # mode
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Mode:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        mode = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                          choices = [_("coarse"),
+                                     _("fine"),
+                                     _("both")])
+        mode.SetName("selection")
+        mode.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
+        self.win['surface']['draw']['mode'] = mode.GetId()
+        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND,
+                      pos = (0, 1),span = (1, 2))
+        
+        # shading
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Shading:")),
+                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
+        shade = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                           choices = [_("flat"),
+                                      _("gouraud")])
+        shade.SetName("selection")
+        self.win['surface']['draw']['shading'] = shade.GetId()
+        shade.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
+        gridSizer.Add(item = shade, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 4))
+        
+        # set to all
+        all = wx.Button(panel, id = wx.ID_ANY, label = _("Set to all"))
+        all.SetToolTipString(_("Use draw settings for all loaded surfaces"))
+        all.Bind(wx.EVT_BUTTON, self.OnSurfaceModeAll)
+        gridSizer.Add(item = all, flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                      pos = (3, 4))
+        self.win['surface']['all'] = all.GetId()
+        
+        # resolution coarse
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Coarse mode:")),
+                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                        label = _("resolution:")),
+                     pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        resC = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = 6,
+                           min = 1,
+                           max = 100)
+        resC.SetName("value")
+        self.win['surface']['draw']['res-coarse'] = resC.GetId()
+        resC.Bind(wx.EVT_SPINCTRL, self.OnSurfaceResolution)
+        gridSizer.Add(item = resC, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
+        
+        # Coarse style
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("style:")),
+                      pos = (3, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        style = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                          choices = [_("wire"),
+                                     _("surface")])
+        style.SetName("selection")
+        self.win['surface']['draw']['style'] = style.GetId()
+        style.Bind(wx.EVT_CHOICE, self.OnSurfaceMode)
+        gridSizer.Add(item = style, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (3, 2))
+        
+        # color
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        color.SetName("colour")
+        color.Bind(csel.EVT_COLOURSELECT, self.OnSurfaceWireColor)
+        color.SetToolTipString(_("Change wire color"))
+        self.win['surface']['draw']['wire-color'] = color.GetId()
+        gridSizer.Add(item = color, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
+                      pos = (3, 3))
+        
+        # resolution fine
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Fine mode:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                        label = _("resolution:")),
+                     pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        resF = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = 3,
+                           min = 1,
+                           max = 100)
+        resF.SetName("value")
+        self.win['surface']['draw']['res-fine'] = resF.GetId()
+        resF.Bind(wx.EVT_SPINCTRL, self.OnSurfaceResolution)
+        gridSizer.Add(item = resF, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        #
+        # surface attributes
+        #
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Surface attributes")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(2)
+        
+        # type 
+        self.win['surface']['attr'] = {}
+        row = 0
+        for code, attrb in (('color', _("Color")),
+                           ('mask', _("Mask")),
+                           ('transp', _("Transparency")),
+                           ('shine', _("Shininess"))):
+            self.win['surface'][code] = {} 
+            gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                             label = attrb + ':'),
+                          pos = (row, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+            use = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                             choices = [_("map")])
+            
+            if code not in ('color', 'shine'):
+                use.Insert(item = _("unset"), pos = 0)
+                self.win['surface'][code]['required'] = False
+            else:
+                self.win['surface'][code]['required'] = True
+            if code != 'mask':
+                use.Append(item = _('constant'))
+            self.win['surface'][code]['use'] = use.GetId()
+            use.Bind(wx.EVT_CHOICE, self.OnMapObjUse)
+            gridSizer.Add(item = use, flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 1))
+            
+            map = Select(parent = panel, id = wx.ID_ANY,
+                         # size = globalvar.DIALOG_GSELECT_SIZE,
+                         size = (-1, -1),
+                         type = "raster")
+            self.win['surface'][code]['map'] = map.GetId() - 1 # FIXME
+            map.Bind(wx.EVT_TEXT, self.OnSurfaceMap)
+            gridSizer.Add(item = map, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND,
+                          pos = (row, 2))
+            
+            if code == 'color':
+                color = UserSettings.Get(group = 'nviz', key = 'surface', subkey = ['color', 'value'])
+                value = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                          colour = color,
+                                          size = globalvar.DIALOG_COLOR_SIZE)
+                value.Bind(csel.EVT_COLOURSELECT, self.OnSurfaceMap)
+            elif code == 'mask':
+                value = None
+            else:
+                value = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                                    initial = 0)
+                value.SetRange(minVal = 0, maxVal = 100)
+                value.Bind(wx.EVT_TEXT, self.OnSurfaceMap)
+            
+            if value:
+                self.win['surface'][code]['const'] = value.GetId()
+                value.Enable(False)
+                gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
+                              pos = (row, 3))
+            else:
+                self.win['surface'][code]['const'] = None
+            
+            self.SetMapObjUseMap(nvizType = 'surface',
+                                 attrb = code) # -> enable map / disable constant
+                
+            row += 1
+        boxSizer.Add(item = gridSizer, proportion = 0,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 3)
+        #
+        # position
+        #
+        self.win['surface']['position'] = {}
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Position")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(3)
+        
+        # position
+        self._createControl(panel, data = self.win['surface'], name = 'position',
+                            range = (-10000, 10000), floatSlider = True,
+                            bind = (self.OnSurfacePosition, self.OnSurfacePositionChanged, self.OnSurfacePositionText))
+        
+        axis = wx.Choice (parent = panel, id = wx.ID_ANY, size = (75, -1),
+                          choices = ["X",
+                                     "Y",
+                                     "Z"])
+                                    
+        reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
+        reset.SetToolTipString(_("Reset to default position"))
+        reset.Bind(wx.EVT_BUTTON, self.OnResetSurfacePosition)
+        self.win['surface']['position']['reset'] = reset.GetId()
+        
+        self.win['surface']['position']['axis'] = axis.GetId()
+        axis.SetSelection(0)
+        axis.Bind(wx.EVT_CHOICE, self.OnSurfaceAxis)
+        
+        pslide = self.FindWindowById(self.win['surface']['position']['slider'])
+        ptext = self.FindWindowById(self.win['surface']['position']['text'])
+        ptext.SetValue('0')
+        
+        gridSizer.Add(item = axis, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        gridSizer.Add(item = pslide, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
+        gridSizer.Add(item = ptext, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 2))
+        gridSizer.Add(item = reset, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, pos = (0, 3))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        box.SetSizer(boxSizer)
+        box.Layout()
+        
+        pageSizer.Add(item = boxSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        #
+        # mask
+        #
+##        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+##                            label = " %s " % (_("Mask")))
+##        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+##        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+##        
+##        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+##                                         label = _("Mask zeros:")),
+##                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+##        
+##        elev = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+##                           label = _("by elevation"))
+##        elev.Enable(False) # TODO: not implemented yet
+##        gridSizer.Add(item = elev, pos = (0, 1))
+##        
+##        color = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+##                           label = _("by color"))
+##        color.Enable(False) # TODO: not implemented yet
+##        gridSizer.Add(item = color, pos = (0, 2))
+##        
+##        boxSizer.Add(item = gridSizer, proportion = 1,
+##                  flag = wx.ALL | wx.EXPAND, border = 3)
+##        pageSizer.Add(item = boxSizer, proportion = 0,
+##                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+##                      border = 3)
+        
+        
+        panel.SetSizer(pageSizer)
+
+        panel.Layout()
+        panel.Fit()
+        
+        return panel
+    def _createCPlanePage(self, parent):
+        """!Create cutting planes page"""  
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        self.page['cplane'] = { 'id' : 4, 
+                                'notebook' : self.foldpanelData.GetId() }
+        self.win['cplane'] = {}
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Cutting planes")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        horSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        # planes
+        horSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Active cutting plane:")),
+                     flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        choice = wx.Choice(parent = panel, id = wx.ID_ANY, choices = [])
+        self.win['cplane']['planes'] = choice.GetId()
+        choice.Bind(wx.EVT_CHOICE, self.OnCPlaneSelection)
+        horSizer.Add(item = choice, flag = wx.ALL, border = 5)
+        
+        # shading
+        horSizer.Add(item = wx.Size(-1, -1), proportion = 1)
+        horSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Shading:")),
+                     flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        choices = [_("clear"),
+                   _("top color"),
+                   _("bottom color"),
+                   _("blend"),
+                   _("shaded")]
+        choice = wx.Choice(parent = panel, id = wx.ID_ANY, choices = choices)
+        self.win['cplane']['shading'] = choice.GetId()
+        choice.Bind(wx.EVT_CHOICE, self.OnCPlaneShading)
+        horSizer.Add(item = choice, flag = wx.ALL, border = 5)
+        boxSizer.Add(item = horSizer, flag = wx.EXPAND)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        # cutting plane horizontal x position
+        self.win['cplane']['position'] = {}
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Horizontal X:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self._createControl(panel, data = self.win['cplane']['position'], name = 'x', size = 250,
+                            range = (-1000, 1000), sliderHor = True, floatSlider = True,
+                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
+        self.FindWindowById(self.win['cplane']['position']['x']['slider']).SetValue(0)
+        self.FindWindowById(self.win['cplane']['position']['x']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['x']['slider']),
+                      pos = (0, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['x']['text']),
+                      pos = (0, 2),
+                      flag = wx.ALIGN_CENTER)   
+        
+        # cutting plane horizontal y position
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Horizontal Y:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self._createControl(panel, data = self.win['cplane']['position'], name = 'y', size = 250,
+                            range = (-1000, 1000), sliderHor = True, floatSlider = True,
+                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
+        self.FindWindowById(self.win['cplane']['position']['y']['slider']).SetValue(0)
+        self.FindWindowById(self.win['cplane']['position']['y']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['y']['slider']),
+                      pos = (1, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['y']['text']),
+                      pos = (1, 2),
+                      flag = wx.ALIGN_CENTER)                         
+        
+        # cutting plane rotation
+        self.win['cplane']['rotation'] = {}
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Rotation:")),
+                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self._createControl(panel, data = self.win['cplane']['rotation'], name = 'rot', size = 250,
+                            range = (0, 360), sliderHor = True,
+                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
+        self.FindWindowById(self.win['cplane']['rotation']['rot']['slider']).SetValue(0)
+        self.FindWindowById(self.win['cplane']['rotation']['rot']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['rot']['slider']),
+                      pos = (2, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['rot']['text']),
+                      pos = (2, 2),
+                      flag = wx.ALIGN_CENTER)
+
+        # cutting plane tilt        
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Tilt:")),
+                      pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL)                    
+        self._createControl(panel, data = self.win['cplane']['rotation'], name = 'tilt', size = 250,
+                            range = (0, 360), sliderHor = True,
+                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
+        self.FindWindowById(self.win['cplane']['rotation']['tilt']['slider']).SetValue(0)
+        self.FindWindowById(self.win['cplane']['rotation']['tilt']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['tilt']['slider']),
+                      pos = (3, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['rotation']['tilt']['text']),
+                      pos = (3, 2),
+                      flag = wx.ALIGN_CENTER)          
+        
+        # cutting pland height
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Height:")),
+                      pos = (4, 0), flag = wx.ALIGN_CENTER_VERTICAL)        
+        self._createControl(panel, data = self.win['cplane']['position'], name = 'z', size = 250,
+                            range = (-1000, 1000), sliderHor = True,
+                            bind = (self.OnCPlaneChanging, self.OnCPlaneChangeDone, self.OnCPlaneChangeText))
+        self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetValue(0)
+        self.FindWindowById(self.win['cplane']['position']['z']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['z']['slider']),
+                      pos = (4, 1),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['cplane']['position']['z']['text']),
+                      pos = (4, 2),
+                      flag = wx.ALIGN_CENTER)
+        
+        boxSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
+                    
+        horSizer = wx.BoxSizer(wx.HORIZONTAL)
+        horSizer.Add(item = wx.Size(-1, -1), proportion = 1, flag = wx.ALL, border = 5)  
+        # reset
+        reset = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Reset"))
+        self.win['cplane']['reset'] = reset.GetId()
+        reset.Bind(wx.EVT_BUTTON, self.OnCPlaneReset)
+        horSizer.Add(item = reset, flag = wx.ALL, border = 5)
+        boxSizer.Add(horSizer, proportion = 0, flag = wx.EXPAND)            
+        
+        
+        pageSizer.Add(boxSizer, proportion = 0, flag = wx.EXPAND)
+        
+        panel.SetSizer(pageSizer)
+        panel.Fit()    
+        
+        return panel
+        
+    def _createConstantPage(self, parent):
+        """!Create constant page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        self.page['constant'] = { 'id' : 1, 
+                                'notebook' : self.foldpanelData.GetId() }
+        self.win['constant'] = {}
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Constant surface")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        horsizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        surface = wx.ComboBox(parent = panel, id = wx.ID_ANY, 
+                              style = wx.CB_SIMPLE | wx.CB_READONLY,
+                              choices = [])
+        self.win['constant']['surface'] = surface.GetId()
+        surface.Bind(wx.EVT_COMBOBOX, self.OnConstantSelection)
+        horsizer.Add(surface, proportion = 1, flag = wx.EXPAND|wx.RIGHT, border = 20)
+
+        addNew = wx.Button(panel, id = wx.ID_ANY, label = _("New"))
+        addNew.Bind(wx.EVT_BUTTON, self.OnNewConstant)
+        self.win['constant']['new'] = addNew.GetId()
+
+        delete = wx.Button(panel, id = wx.ID_ANY, label = _("Delete"))
+        delete.Bind(wx.EVT_BUTTON, self.OnDeleteConstant)
+        self.win['constant']['delete'] = delete.GetId()
+        
+        horsizer.Add(item = addNew, proportion = 0, flag = wx.RIGHT|wx.LEFT, border = 3)
+        horsizer.Add(item = delete, proportion = 0, flag = wx.RIGHT|wx.LEFT, border = 3)
+    
+        boxSizer.Add(item = horsizer, proportion = 0, flag = wx.ALL|wx.EXPAND,
+                      border = 5)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        # fine resolution
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Fine resolution:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        resF = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           initial = 3,
+                           min = 1,
+                           max = 100)
+        resF.SetName("value")
+        self.win['constant']['resolution'] = resF.GetId()
+        resF.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
+        gridSizer.Add(item = resF, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
+        # value 
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Value:")), pos = (1, 0),
+                                         flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        value = wx.SpinCtrl(panel, id = wx.ID_ANY,
+                                  min = -1e9, max = 1e9,
+                                  size = (65, -1))
+        self.win['constant']['value'] = value.GetId()
+        value.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
+        gridSizer.Add(item = value, pos = (1, 1))
+        
+        # transparency 
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Transparency:")), pos = (2, 0),
+                                         flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        transp = wx.SpinCtrl(panel, id = wx.ID_ANY,
+                                  min = 0, max = 100,
+                                  size = (65, -1))
+        self.win['constant']['transp'] = transp.GetId()
+        transp.Bind(wx.EVT_SPINCTRL, self.OnSetConstantProp)
+        gridSizer.Add(item = transp, pos = (2, 1))
+        
+        # color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Color:")), pos = (3, 0),
+                                         flag = wx.ALIGN_CENTER_VERTICAL)
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = (0,0,0),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        self.win['constant']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnSetConstantProp)
+        gridSizer.Add(item = color, pos = (3, 1))
+        boxSizer.Add(item = gridSizer, proportion = 0, flag = wx.ALL,
+                      border = 5)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+        panel.Fit()    
+        
+        return panel
+        
+    def _createVectorPage(self, parent):
+        """!Create view settings page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        self.page['vector'] = { 'id' : 2,
+                                'notebook' : self.foldpanelData.GetId() }
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        self.win['vector'] = {}
+        
+        # selection
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Vector map")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        vmaps = Select(parent = panel, type = 'vector',
+                       onPopup = self.GselectOnPopup)
+        vmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetVector)
+        self.win['vector']['map'] = vmaps.GetId()
+        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        self.win['vector']['desc'] = desc.GetId()
+        boxSizer.Add(item = vmaps, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        boxSizer.Add(item = desc, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        #
+        # vector lines
+        #
+        self.win['vector']['lines'] = {}
+        
+        showLines = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                label = _("Show vector lines"))
+        showLines.SetValue(True)
+        
+        self.win['vector']['lines']['show'] = showLines.GetId()
+        showLines.Bind(wx.EVT_CHECKBOX, self.OnVectorShow)
+        
+        pageSizer.Add(item = showLines, proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Vector lines")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        gridSizer.AddGrowableCol(5)
+        
+        # width
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Line:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("width:")),
+                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL | 
+                      wx.ALIGN_RIGHT)
+        
+        width = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                            initial = 1,
+                            min = 0,
+                            max = 100)
+        width.SetValue(1)
+        self.win['vector']['lines']['width'] = width.GetId()
+        width.Bind(wx.EVT_SPINCTRL, self.OnVectorLines)
+        gridSizer.Add(item = width, pos = (0, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        
+        # color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("color:")),
+                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALIGN_RIGHT)
+        
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = (0,0,0),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        self.win['vector']['lines']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnVectorLines)
+
+        gridSizer.Add(item = color, pos = (0, 4), flag = wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALIGN_LEFT)
+        
+        # thematic mapping
+        self.win['vector']['lines']['thematic'] = {}
+        checkThematicColor = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                         label = _("use color for thematic mapping"))
+        checkThematicWidth = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                         label = _("use width for thematic mapping"))
+        self.win['vector']['lines']['thematic']['checkcolor'] = checkThematicColor.GetId()
+        self.win['vector']['lines']['thematic']['checkwidth'] = checkThematicWidth.GetId()
+        checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
+        checkThematicWidth.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
+        checkThematicColor.SetValue(False)
+        checkThematicWidth.SetValue(False)
+        
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer.Add(item = checkThematicColor, flag = wx.ALIGN_CENTER_VERTICAL,
+                    border = 5)
+        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
+                                         label = _("Set options..."))
+        self.win['vector']['lines']['thematic']['buttoncolor'] = setThematic.GetId()
+        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
+        hSizer.Add(item = wx.Size(-1, -1), proportion = 1)
+        hSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
+                    border = 5, proportion = 0)
+        vSizer.Add(hSizer, flag = wx.EXPAND)
+                    
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer.Add(item = checkThematicWidth, flag = wx.ALIGN_CENTER_VERTICAL,
+                    border = 5)
+        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
+                                         label = _("Set options..."))
+        self.win['vector']['lines']['thematic']['buttonwidth'] = setThematic.GetId()
+        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
+        hSizer.Add(item = wx.Size(-1, -1), proportion = 1)
+        hSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
+                    border = 5, proportion = 0)
+        
+        vSizer.Add(hSizer, flag = wx.EXPAND)
+        gridSizer.Add(item = vSizer, flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+                      pos = (1, 1), span = (1, 5))
+        
+        # display
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Display")),
+                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALIGN_LEFT)
+        
+        display = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                             choices = [_("on surface(s):"),
+                                        _("flat")])
+        self.win['vector']['lines']['flat'] = display.GetId()
+        display.Bind(wx.EVT_CHOICE, self.OnVectorDisplay)
+        
+        gridSizer.Add(item = display, flag = wx.ALIGN_CENTER_VERTICAL | 
+                      wx.ALIGN_LEFT|wx.EXPAND, pos = (2, 1), span = (1,4))
+        
+        # height
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Height above surface:")),
+                      pos = (3, 5), flag = wx.ALIGN_BOTTOM|wx.EXPAND)
+        
+        surface = wx.CheckListBox(parent = panel, id = wx.ID_ANY, size = (-1, 60),
+                                  choices = [], style = wx.LB_NEEDED_SB)
+        surface.Bind(wx.EVT_CHECKLISTBOX, self.OnVectorSurface)
+        
+        self.win['vector']['lines']['surface'] = surface.GetId()
+        gridSizer.Add(item = surface, 
+                      pos = (3, 0), span = (3, 5),
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        
+        self._createControl(panel, data = self.win['vector']['lines'], name = 'height', size = -1,
+                            range = (0, 500), sliderHor = True,
+                            bind = (self.OnVectorHeight, self.OnVectorHeightFull, self.OnVectorHeightText))
+        self.FindWindowById(self.win['vector']['lines']['height']['slider']).SetValue(0)
+        self.FindWindowById(self.win['vector']['lines']['height']['text']).SetValue(0)
+        gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['slider']),
+                      pos = (4, 5),  flag = wx.EXPAND|wx.ALIGN_RIGHT)
+        gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['text']),
+                      pos = (5, 5),
+                      flag = wx.ALIGN_CENTER)
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        #
+        # vector points
+        #
+        self.win['vector']['points'] = {}
+        
+        showPoints = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                 label = _("Show vector points"))
+        showPoints.SetValue(True)
+        self.win['vector']['points']['show'] = showPoints.GetId()
+        showPoints.Bind(wx.EVT_CHECKBOX, self.OnVectorShow)
+        
+        pageSizer.Add(item = showPoints, proportion = 0,
+                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Vector points")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        vertSizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        gridSizer.AddGrowableCol(0)
+        gridSizer.AddGrowableCol(2)
+        gridSizer.AddGrowableCol(4)
+        gridSizer.AddGrowableCol(6)
+        
+        # icon size
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Icon:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("size:")),
+                      pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALIGN_RIGHT)
+        
+        isize = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                            initial = 1,
+                            min = 1,
+                            max = 1e6)
+        isize.SetName('value')
+        isize.SetValue(100)
+        self.win['vector']['points']['size'] = isize.GetId()
+        isize.Bind(wx.EVT_SPINCTRL, self.OnVectorPoints)
+        isize.Bind(wx.EVT_TEXT, self.OnVectorPoints)
+        gridSizer.Add(item = isize, pos = (0, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        
+        # icon color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("color:")),
+                      pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL |
+                      wx.ALIGN_RIGHT)
+        icolor = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                   size = globalvar.DIALOG_COLOR_SIZE)
+        icolor.SetName("color")
+        icolor.SetColour((0,0,255))
+        self.win['vector']['points']['color'] = icolor.GetId()
+        icolor.Bind(csel.EVT_COLOURSELECT, self.OnVectorPoints)
+        gridSizer.Add(item = icolor, flag = wx.ALIGN_CENTER_VERTICAL | 
+                      wx.ALIGN_LEFT,
+                      pos = (0, 4))
+
+        # icon width - seems to do nothing
+##        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+##                                           label = _("width")),
+##                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL |
+##                      wx.ALIGN_RIGHT)
+##        
+##        iwidth = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+##                             initial = 1,
+##                             min = 1,
+##                             max = 1e6)
+##        iwidth.SetName('value')
+##        iwidth.SetValue(100)
+##        self.win['vector']['points']['width'] = iwidth.GetId()
+##        iwidth.Bind(wx.EVT_SPINCTRL, self.OnVectorPoints)
+##        iwidth.Bind(wx.EVT_TEXT, self.OnVectorPoints)
+##        gridSizer.Add(item = iwidth, pos = (1, 2),
+##                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        # icon symbol
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("symbol:")),
+                      pos = (0, 5), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+        isym = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                          choices = UserSettings.Get(group = 'nviz', key = 'vector',
+                                                   subkey = ['points', 'marker'], internal = True))
+        isym.SetName("selection")
+        self.win['vector']['points']['marker'] = isym.GetId()
+        isym.Bind(wx.EVT_CHOICE, self.OnVectorPoints)
+        gridSizer.Add(item = isym, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
+                      pos = (0, 6))
+        # thematic mapping
+        self.win['vector']['points']['thematic'] = {}
+        checkThematicColor = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                         label = _("use color for thematic mapping"))
+        checkThematicSize = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                         label = _("use size for thematic mapping"))
+        self.win['vector']['points']['thematic']['checkcolor'] = checkThematicColor.GetId()
+        self.win['vector']['points']['thematic']['checksize'] = checkThematicSize.GetId()
+        checkThematicColor.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
+        checkThematicSize.Bind(wx.EVT_CHECKBOX, self.OnCheckThematic)
+        checkThematicColor.SetValue(False)
+        checkThematicSize.SetValue(False)
+        
+        gridSizer.Add(item = checkThematicColor, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
+                      pos = (1, 1), span = (1, 5))
+        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
+                                         label = _("Set options..."))
+        self.win['vector']['points']['thematic']['buttoncolor'] = setThematic.GetId()
+        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
+        gridSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (1, 6))
+                    
+        gridSizer.Add(item = checkThematicSize, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT,
+                      pos = (2, 1), span = (1, 5))
+        setThematic = wx.Button(parent = panel, id = wx.ID_ANY,
+                                         label = _("Set options..."))
+        self.win['vector']['points']['thematic']['buttonsize'] = setThematic.GetId()
+        setThematic.Bind(wx.EVT_BUTTON, self.OnSetThematic)
+        gridSizer.Add(item = setThematic, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (2, 6))                   
+        vertSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+        # high
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        gridSizer.AddGrowableCol(1)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Display on surface(s):")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Height above surface:")),
+                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        surface = wx.CheckListBox(parent = panel, id = wx.ID_ANY, size = (-1, 60),
+                                  choices = [], style = wx.LB_NEEDED_SB)
+        surface.Bind(wx.EVT_CHECKLISTBOX, self.OnVectorSurface)
+        self.win['vector']['points']['surface'] = surface.GetId()
+        gridSizer.Add(item = surface, 
+                      pos = (1, 0), span = (3, 1),
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
+        
+        self._createControl(panel, data = self.win['vector']['points'], name = 'height', size = -1,
+                            range = (0, 500),
+                            bind = (self.OnVectorHeight, self.OnVectorHeightFull, self.OnVectorHeightText))
+        
+        self.FindWindowById(self.win['vector']['points']['height']['slider']).SetValue(0)
+        self.FindWindowById(self.win['vector']['points']['height']['text']).SetValue(0)
+        
+        gridSizer.Add(item = self.FindWindowById(self.win['vector']['points']['height']['slider']),
+                      pos = (2, 1),flag = wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.FindWindowById(self.win['vector']['points']['height']['text']),
+                      pos = (3, 1),
+                      flag = wx.ALIGN_CENTER)
+                    
+        vertSizer.Add(gridSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+        boxSizer.Add(item = vertSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+        panel.Fit()
+
+        return panel
+
+    def GselectOnPopup(self, ltype, exclude = False):
+        """Update gselect.Select() items"""
+        maps = list()
+        for layer in self.mapWindow.Map.GetListOfLayers(l_type = ltype, l_active = True):
+            maps.append(layer.GetName())
+        return maps, exclude
+    
+    def _createVolumePage(self, parent):
+        """!Create view settings page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        self.page['volume'] = { 'id' : 3,
+                                'notebook' : self.foldpanelData.GetId() }
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        self.win['volume'] = {}
+        
+        # selection
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("3D raster map")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        rmaps = Select(parent = panel, type = '3d-raster',
+                       onPopup = self.GselectOnPopup)
+        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetRaster3D)
+        self.win['volume']['map'] = rmaps.GetId()
+        desc = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        self.win['volume']['desc'] = desc.GetId()
+        boxSizer.Add(item = rmaps, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        boxSizer.Add(item = desc, proportion = 0,
+                     flag = wx.ALL,
+                     border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+                
+        #
+        # draw
+        #
+        self.win['volume']['draw'] = {}
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Draw")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+##        gridSizer.AddGrowableCol(4)
+        
+        # mode
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Mode:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        mode = wx.Choice (parent = panel, id = wx.ID_ANY, size = (-1, -1),
+                          choices = [_("isosurfaces"),
+                                     _("slices")])
+        mode.SetSelection(0)
+        mode.SetName("selection")
+        mode.Bind(wx.EVT_CHOICE, self.OnVolumeMode)
+        self.win['volume']['draw']['mode'] = mode.GetId()
+        gridSizer.Add(item = mode, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 1))
+        
+        # shading
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Shading:")),
+                      pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        shade = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                           choices = [_("flat"),
+                                      _("gouraud")])
+        shade.SetName("selection")
+        self.win['volume']['draw']['shading'] = shade.GetId()
+        shade.Bind(wx.EVT_CHOICE, self.OnVolumeDrawMode)
+        gridSizer.Add(item = shade, flag = wx.ALIGN_CENTER_VERTICAL,
+                      pos = (0, 3))
+        
+        # resolution (mode)
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                         label = _("Resolution:")),
+                      pos = (0, 4), flag = wx.ALIGN_CENTER_VERTICAL)
+        resol = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                            initial = 1,
+                            min = 1,
+                            max = 100)
+        resol.SetName("value")
+        self.win['volume']['draw']['resolution'] = resol.GetId()
+        resol.Bind(wx.EVT_SPINCTRL, self.OnVolumeResolution)
+        resol.Bind(wx.EVT_TEXT, self.OnVolumeResolution)
+        gridSizer.Add(item = resol, pos = (0, 5))
+        
+        boxSizer.Add(item = gridSizer, proportion = 0,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 3)
+        
+        #
+        # manage isosurfaces
+        #
+        box = wx.StaticBox(parent = panel, id = wx.ID_ANY, 
+                           label = " %s " % (_("List of isosurfaces")))
+        box.SetName('listStaticBox')
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        # list
+        isolevel = wx.CheckListBox(parent = panel, id = wx.ID_ANY,
+                                   size = (300, 150))
+        self.Bind(wx.EVT_CHECKLISTBOX, self.OnVolumeCheck, isolevel)
+        self.Bind(wx.EVT_LISTBOX, self.OnVolumeSelect, isolevel)
+        
+        self.win['volume']['isosurfs'] = isolevel.GetId()
+        self.win['volume']['slices'] = isolevel.GetId()
+        gridSizer.Add(item = isolevel, pos = (0, 0), span = (4, 1))
+        
+        # buttons (add, delete, move up, move down)
+        btnAdd = wx.Button(parent = panel, id = wx.ID_ADD)
+        self.win['volume']['btnAdd'] = btnAdd.GetId()
+        btnAdd.Bind(wx.EVT_BUTTON, self.OnVolumeAdd)
+        gridSizer.Add(item = btnAdd,
+                      pos = (0, 1))
+        btnDelete = wx.Button(parent = panel, id = wx.ID_DELETE)
+        self.win['volume']['btnDelete'] = btnDelete.GetId()
+        btnDelete.Bind(wx.EVT_BUTTON, self.OnVolumeDelete)
+        btnDelete.Enable(False)
+        gridSizer.Add(item = btnDelete,
+                      pos = (1, 1))
+        btnMoveUp = wx.Button(parent = panel, id = wx.ID_UP)
+        self.win['volume']['btnMoveUp'] = btnMoveUp.GetId()
+        btnMoveUp.Bind(wx.EVT_BUTTON, self.OnVolumeMoveUp)
+        btnMoveUp.Enable(False)
+        gridSizer.Add(item = btnMoveUp,
+                      pos = (2, 1))
+        btnMoveDown = wx.Button(parent = panel, id = wx.ID_DOWN)
+        self.win['volume']['btnMoveDown'] = btnMoveDown.GetId()
+        btnMoveDown.Bind(wx.EVT_BUTTON, self.OnVolumeMoveDown)
+        btnMoveDown.Enable(False)
+        gridSizer.Add(item = btnMoveDown,
+                      pos = (3, 1))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        # isosurface/slice 
+        sizer = wx.BoxSizer()
+        self.isoPanel = self._createIsosurfacePanel(panel)
+        self.slicePanel = self._createSlicePanel(panel)
+        sizer.Add(self.isoPanel, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
+        sizer.Add(self.slicePanel, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
+        sizer.Hide(self.slicePanel)
+        pageSizer.Add(item = sizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL,
+                      border = 3)
+        #
+        # position
+        #
+        self.win['volume']['position'] = {}
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Position")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(3)
+        
+        # position
+        self._createControl(panel, data = self.win['volume'], name = 'position',
+                            range = (-10000, 10000), floatSlider = True,
+                            bind = (self.OnVolumePosition, self.OnVolumePositionChanged, self.OnVolumePositionText))
+        
+        axis = wx.Choice (parent = panel, id = wx.ID_ANY, size = (75, -1),
+                          choices = ["X",
+                                     "Y",
+                                     "Z"])
+                                    
+        reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
+        reset.SetToolTipString(_("Reset to default position"))
+        reset.Bind(wx.EVT_BUTTON, self.OnResetVolumePosition)
+        self.win['volume']['position']['reset'] = reset.GetId()
+        
+        self.win['volume']['position']['axis'] = axis.GetId()
+        axis.SetSelection(0)
+        axis.Bind(wx.EVT_CHOICE, self.OnVolumeAxis)
+        
+        pslide = self.FindWindowById(self.win['volume']['position']['slider'])
+        ptext = self.FindWindowById(self.win['volume']['position']['text'])
+        ptext.SetValue('0')
+        
+        gridSizer.Add(item = axis, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        gridSizer.Add(item = pslide, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
+        gridSizer.Add(item = ptext, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 2))
+        gridSizer.Add(item = reset, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, pos = (0, 3))
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        panel.SetSizer(pageSizer)
+        panel.Fit()
+        
+        return panel
+       
+        
+    def _createLightPage(self, parent):
+        """!Create light page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        
+        self.page['light'] = { 'id' : 0, 
+                               'notebook' : self.foldpanelAppear.GetId() }
+        self.win['light'] = {}
+        
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        show = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                           label = _("Show light model"))
+        show.Bind(wx.EVT_CHECKBOX, self.OnShowLightModel)
+        show.SetValue(True)
+        self._display.showLight = True
+        pageSizer.Add(item = show, proportion = 0,
+                      flag = wx.ALL, border = 3)
+##        surface = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+##                              label = _("Follow source viewpoint"))
+##        pageSizer.Add(item = surface, proportion = 0,
+##                      flag = wx.ALL, border = 3)
+        
+        # position
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Light source position")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        posSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        self._createCompass(panel = panel, sizer = posSizer, type = 'light')
+        
+        pos = LightPositionWindow(panel, id = wx.ID_ANY, size = (175, 175),
+                                  mapwindow = self.mapWindow)
+        self.win['light']['position'] = pos.GetId()
+        posSizer.Add(item = pos,
+                     pos = (1, 1), flag = wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = posSizer, pos = (0, 0))
+        
+        # height
+        self._createControl(panel, data = self.win['light'], name = 'z', sliderHor = False,
+                            range = (0, 100),
+                            bind = (self.OnLightChange, self.OnLightChanged, self.OnLightChange))
+        
+        heightSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        heightSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:")),
+                      pos = (0, 0), flag = wx.ALIGN_LEFT, span = (1, 2))
+        heightSizer.Add(item = self.FindWindowById(self.win['light']['z']['slider']),
+                        flag = wx.ALIGN_RIGHT, pos = (1, 0))
+        heightSizer.Add(item = self.FindWindowById(self.win['light']['z']['text']),
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.TOP |
+                        wx.BOTTOM | wx.RIGHT, pos = (1, 1))
+        
+        gridSizer.Add(item = heightSizer, pos = (0, 2), flag = wx.ALIGN_RIGHT)
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 2)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        # position
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Light color and intensity")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+
+        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:")),
+                      pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                  colour = UserSettings.Get(group = 'nviz', key = 'light',
+                                                            subkey = 'color'),
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        self.win['light']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnLightColor)
+        gridSizer.Add(item = color, pos = (0, 2))
+
+        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Brightness:")),
+                      pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self._createControl(panel, data = self.win['light'], name = 'bright', size = 300,
+                            range = (0, 100),
+                            bind = (self.OnLightValue, self.OnLightChanged, self.OnLightValue))
+        gridSizer.Add(item = self.FindWindowById(self.win['light']['bright']['slider']),
+                      pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.FindWindowById(self.win['light']['bright']['text']),
+                      pos = (1, 2),
+                      flag = wx.ALIGN_CENTER)
+        gridSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Ambient:")),
+                      pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self._createControl(panel, data = self.win['light'], name = 'ambient', size = 300,
+                            range = (0, 100),
+                            bind = (self.OnLightValue, self.OnLightChanged, self.OnLightValue))
+        gridSizer.Add(item = self.FindWindowById(self.win['light']['ambient']['slider']),
+                      pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = self.FindWindowById(self.win['light']['ambient']['text']),
+                      pos = (2, 2),
+                      flag = wx.ALIGN_CENTER)
+
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 2)
+        pageSizer.Add(item = boxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        # reset = wx.Button(panel, id = wx.ID_ANY, label = _("Reset"))
+        # reset.SetToolTipString(_("Reset to default view"))
+        # # self.win['reset'] = reset.GetId()
+        # reset.Bind(wx.EVT_BUTTON, self.OnResetView)
+        
+        # viewSizer.Add(item = reset, proportion = 1,
+        #               flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT,
+        #               border = 5)
+        
+        # gridSizer.AddGrowableCol(3)
+        # gridSizer.Add(item = viewSizer, pos = (4, 0), span = (1, 2),
+        #               flag = wx.EXPAND)
+        
+        panel.SetSizer(pageSizer)
+        panel.Layout()
+        panel.Fit()
+        
+        return panel
+
+    def _createFringePage(self, parent):
+        """!Create fringe page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        
+        self.page['fringe'] = { 'id' : 1,
+                                'notebook' : self.foldpanelAppear.GetId() }
+        self.win['fringe'] = {}
+
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # selection
+        rbox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                             label = " %s " % (_("Surface")))
+        rboxSizer = wx.StaticBoxSizer(rbox, wx.VERTICAL)
+        rmaps = Select(parent = panel, type = 'raster',
+                       onPopup = self.GselectOnPopup)
+        rmaps.GetChildren()[0].Bind(wx.EVT_TEXT, self.OnSetSurface)
+        self.win['fringe']['map'] = rmaps.GetId()
+        rboxSizer.Add(item = rmaps, proportion = 0,
+                      flag = wx.ALL,
+                      border = 3)
+        pageSizer.Add(item = rboxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        ebox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                             label = " %s " % (_("Edges with fringe")))
+        eboxSizer = wx.StaticBoxSizer(ebox, wx.HORIZONTAL)
+        for edge in [(_("N && W"), "nw"),
+                     (_("N && E"), "ne"),
+                     (_("S && W"), "sw"),
+                     (_("S && E"), "se")]:
+            chkbox = wx.CheckBox(parent = panel,
+                                 label = edge[0],
+                                 name = edge[1])
+            self.win['fringe'][edge[1]] = chkbox.GetId()
+            eboxSizer.Add(item = chkbox, proportion = 0,
+                         flag = wx.ADJUST_MINSIZE | wx.LEFT | wx.RIGHT, border = 5)
+            chkbox.Bind(wx.EVT_CHECKBOX, self.OnFringe)
+        
+        pageSizer.Add(item = eboxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+
+        sbox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                             label = " %s " % (_("Settings")))
+        sboxSizer = wx.StaticBoxSizer(sbox, wx.HORIZONTAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        
+        # elevation
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Elevation of fringe from bottom:")),
+                      pos = (0, 0),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY,
+                           size = (65, -1), min = -1e6, max = 1e6)
+        spin.SetValue(UserSettings.Get(group = 'nviz', key = 'fringe', subkey = 'elev'))
+        spin.Bind(wx.EVT_SPINCTRL, self.OnFringe)
+        self.win['fringe']['elev'] = spin.GetId()
+        gridSizer.Add(item = spin, pos = (0, 1))
+        
+        # color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Color:")),
+                      pos = (1, 0),
+                      flag = wx.ALIGN_CENTER_VERTICAL)
+        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        color.SetColour(UserSettings.Get(group = 'nviz', key = 'fringe',
+                                         subkey = 'color'))
+        color.Bind(csel.EVT_COLOURSELECT, self.OnFringe)
+        self.win['fringe']['color'] = color.GetId()
+        gridSizer.Add(item = color, pos = (1, 1))
+        
+        sboxSizer.Add(item = gridSizer, proportion = 1,
+                      flag = wx.ALL | wx.EXPAND, border = 3)
+        pageSizer.Add(item = sboxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        panel.SetSizer(pageSizer)
+        panel.Layout()
+        panel.Fit()
+
+        return panel
+    
+    def _createDecorationPage(self, parent):
+        """!Create decoration (north arrow, scalebar, legend) page"""
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        
+        self.page['decoration'] = { 'id' : 2,
+                                    'notebook' : self.foldpanelAppear.GetId()}
+        self.win['decoration'] = {}
+
+        pageSizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # north arrow
+        self.win['decoration']['arrow'] = {}
+        nabox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                             label = " %s " % (_("North Arrow")))
+        naboxSizer = wx.StaticBoxSizer(nabox, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        # size
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Arrow length (in map units):")),
+                      pos = (0,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        sizeCtrl = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1), style = wx.TE_PROCESS_ENTER)
+        gridSizer.Add(sizeCtrl, pos = (0, 2))
+        self.win['decoration']['arrow']['size'] = sizeCtrl.GetId()
+        sizeCtrl.Bind(wx.EVT_TEXT_ENTER, self.OnDecorationProp)
+        sizeCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnDecorationProp)
+        
+        # color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Arrow color:")),
+                      pos = (1,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        gridSizer.Add(color, pos = (1, 2))
+        self.win['decoration']['arrow']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnDecorationProp)
+        
+        # control
+        toggle = wx.ToggleButton(parent = panel, id = wx.ID_ANY, label = _("Place arrow"))
+        gridSizer.Add(item = toggle, pos = (2, 0))
+        toggle.Bind(wx.EVT_TOGGLEBUTTON, self.OnDecorationPlacement)
+        self.win['decoration']['arrow']['place'] = toggle.GetId()
+        toggle.SetName('placeArrow')
+
+        delete = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Delete"))
+        gridSizer.Add(item = delete, pos = (2, 1))
+        delete.Bind(wx.EVT_BUTTON, self.OnArrowDelete)
+        naboxSizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND, border = 3)
+        pageSizer.Add(item = naboxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)
+        
+        
+        # north arrow
+        self.win['decoration']['scalebar'] = {}
+        nabox = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                             label = " %s " % (_("Scale bar")))
+        naboxSizer = wx.StaticBoxSizer(nabox, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        # size
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Scale bar length (in map units):")),
+                      pos = (0,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        sizeCtrl = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1), style = wx.TE_PROCESS_ENTER)
+        gridSizer.Add(sizeCtrl, pos = (0, 2))
+        self.win['decoration']['scalebar']['size'] = sizeCtrl.GetId()
+        sizeCtrl.Bind(wx.EVT_TEXT_ENTER, self.OnDecorationProp)
+        sizeCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnDecorationProp)
+        
+        # color
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = _("Scale bar color:")),
+                      pos = (1,0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+        color = csel.ColourSelect(parent = panel, id = wx.ID_ANY,
+                                  size = globalvar.DIALOG_COLOR_SIZE)
+        gridSizer.Add(color, pos = (1, 2))
+        self.win['decoration']['scalebar']['color'] = color.GetId()
+        color.Bind(csel.EVT_COLOURSELECT, self.OnDecorationProp)
+        
+        # control
+        toggle = wx.ToggleButton(parent = panel, id = wx.ID_ANY, label = _("Place scalebar"))
+        gridSizer.Add(item = toggle, pos = (2, 0))
+        toggle.Bind(wx.EVT_TOGGLEBUTTON, self.OnDecorationPlacement)
+        self.win['decoration']['scalebar']['place'] = toggle.GetId()
+        toggle.SetName('placeScalebar')
+
+        delete = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Delete last"))
+        gridSizer.Add(item = delete, pos = (2, 1))
+        delete.Bind(wx.EVT_BUTTON, self.OnScalebarDelete)
+        naboxSizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND, border = 3)
+        pageSizer.Add(item = naboxSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
+                      border = 3)      
+        panel.SetSizer(pageSizer)
+        panel.Layout()
+        panel.Fit()
+
+        return panel
+    
+    def GetLayerData(self, nvizType, nameOnly = False):
+        """!Get nviz data"""
+        name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
+        if nameOnly:
+            return name
+        
+        if nvizType == 'surface' or nvizType == 'fringe':
+            return self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
+        elif nvizType == 'vector':
+            return self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'nviz')
+        elif nvizType == 'volume':
+            return self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
+        
+        return None
+        
+    def OnRecord(self, event):
+        """!Animation: start recording"""
+        anim = self.mapWindow.GetAnimation()
+        if not anim.IsPaused():
+            if anim.Exists() and not anim.IsSaved():
+                msg = _("Do you want to record new animation without saving the previous one?")
+                dlg = wx.MessageDialog(parent = self,
+                                       message = msg,
+                                       caption =_("Animation already axists"),
+                                       style = wx.YES_NO | wx.CENTRE)
+                if dlg.ShowModal() == wx.ID_NO:
+                    dlg.Destroy()
+                    return
+                
+        
+            anim.Clear()
+            self.UpdateFrameIndex(0)
+            self.UpdateFrameCount()
+            
+        anim.SetPause(False)
+        anim.SetMode(mode = 'record')
+        anim.Start()
+        
+        self.FindWindowById(self.win['anim']['play']).Disable()
+        self.FindWindowById(self.win['anim']['record']).Disable()
+        self.FindWindowById(self.win['anim']['pause']).Enable()
+        self.FindWindowById(self.win['anim']['stop']).Enable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        
+    def OnPlay(self, event):
+        """!Animation: replay"""
+        anim = self.mapWindow.GetAnimation()
+        anim.SetPause(False)
+        anim.SetMode(mode = 'play')
+        anim.Start()
+        
+        self.FindWindowById(self.win['anim']['play']).Disable()
+        self.FindWindowById(self.win['anim']['record']).Disable()
+        self.FindWindowById(self.win['anim']['pause']).Enable()
+        self.FindWindowById(self.win['anim']['stop']).Enable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Enable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Enable()
+        
+    def OnStop(self, event):
+        """!Animation: stop recording/replaying"""
+        anim = self.mapWindow.GetAnimation()
+        anim.SetPause(False)
+        if anim.GetMode() == 'save':
+            anim.StopSaving()
+        if anim.IsRunning():
+            anim.Stop()
+        
+        self.UpdateFrameIndex(0)
+        
+        self.FindWindowById(self.win['anim']['play']).Enable()
+        self.FindWindowById(self.win['anim']['record']).Enable()
+        self.FindWindowById(self.win['anim']['pause']).Disable()
+        self.FindWindowById(self.win['anim']['stop']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        
+    def OnPause(self, event):
+        """!Pause animation"""
+        anim = self.mapWindow.GetAnimation()
+        
+        anim.SetPause(True)
+        mode = anim.GetMode()
+        if anim.IsRunning():
+            anim.Pause()
+            
+        if mode == "record":
+            self.FindWindowById(self.win['anim']['play']).Disable()
+            self.FindWindowById(self.win['anim']['record']).Enable()
+            self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+            self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        elif mode == 'play':
+            self.FindWindowById(self.win['anim']['record']).Disable()
+            self.FindWindowById(self.win['anim']['play']).Enable()
+            self.FindWindowById(self.win['anim']['frameIndex']['slider']).Enable()
+            self.FindWindowById(self.win['anim']['frameIndex']['text']).Enable()
+        
+        self.FindWindowById(self.win['anim']['pause']).Disable()
+        self.FindWindowById(self.win['anim']['stop']).Enable()
+
+        
+    def OnFrameIndex(self, event):
+        """!Frame index changed (by slider)"""
+        index = event.GetInt()
+        self.UpdateFrameIndex(index = index, sliderWidget = False)
+        
+    def OnFrameIndexText(self, event):
+        """!Frame index changed by (textCtrl)"""
+        index = event.GetValue()
+        self.UpdateFrameIndex(index = index, textWidget = False)
+        
+    def OnFPS(self, event):
+        """!Frames per second changed"""
+        anim = self.mapWindow.GetAnimation()
+        anim.SetFPS(event.GetInt())
+        
+    def UpdateFrameIndex(self, index, sliderWidget = True, textWidget = True, goToFrame = True):
+        """!Update frame index"""
+        anim = self.mapWindow.GetAnimation()
+        
+        # check index
+        frameCount = anim.GetFrameCount()
+        if index >= frameCount:
+            index = frameCount - 1
+        if index < 0:
+            index = 0
+            
+        if sliderWidget:
+            slider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
+            slider.SetValue(index)
+        if textWidget:
+            text = self.FindWindowById(self.win['anim']['frameIndex']['text'])
+            text.SetValue(int(index))
+        
+        # if called from tool window, update frame
+        if goToFrame:
+            anim.GoToFrame(int(index))
+            
+    def UpdateFrameCount(self):
+        """!Update frame count label"""
+        anim = self.mapWindow.GetAnimation()
+        count = anim.GetFrameCount()
+        self.FindWindowById(self.win['anim']['info']).SetLabel(str(count))
+        
+    def OnAnimationFinished(self, event):
+        """!Animation finished"""
+        anim = self.mapWindow.GetAnimation()
+        self.UpdateFrameIndex(index = 0)
+        
+        slider = self.FindWindowById(self.win['anim']['frameIndex']['slider'])
+        text = self.FindWindowById(self.win['anim']['frameIndex']['text'])
+        
+        if event.mode == 'record':
+            count = anim.GetFrameCount()
+            slider.SetMax(count)
+            self.UpdateFrameCount()
+            
+        self.FindWindowById(self.win['anim']['pause']).Disable()
+        self.FindWindowById(self.win['anim']['stop']).Disable()
+        self.FindWindowById(self.win['anim']['record']).Enable()
+        self.FindWindowById(self.win['anim']['play']).Enable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        self.FindWindowById(self.win['anim']['save']['image']['confirm']).Enable()
+        
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+        
+    def OnAnimationUpdateIndex(self, event):
+        """!Animation: frame index changed"""
+        if event.mode == 'record':
+            self.UpdateFrameCount()
+        elif event.mode == 'play':
+            self.UpdateFrameIndex(index = event.index, goToFrame = False)
+        
+    def OnSaveAnimation(self, event):
+        """!Save animation as a sequence of images"""
+        anim = self.mapWindow.GetAnimation()
+        
+        prefix = self.FindWindowById(self.win['anim']['save']['image']['prefix']).GetValue()
+        format = self.FindWindowById(self.win['anim']['save']['image']['format']).GetSelection()
+        dir = self.FindWindowById(self.win['anim']['save']['image']['dir']).GetValue()
+        
+        if not prefix:
+            GMessage(parent = self,
+                          message = _("No file prefix given."))
+            return
+        elif not os.path.exists(dir):
+            GMessage(parent = self,
+                          message = _("Directory %s does not exist.") % dir)
+            return
+            
+        self.FindWindowById(self.win['anim']['pause']).Disable()
+        self.FindWindowById(self.win['anim']['stop']).Enable()
+        self.FindWindowById(self.win['anim']['record']).Disable()
+        self.FindWindowById(self.win['anim']['play']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        
+        self.FindWindowById(self.win['anim']['save']['image']['confirm']).Disable()
+        
+        anim.SaveAnimationFile(path = dir, prefix = prefix, format = format)
+        
+    def OnNewConstant(self, event):
+        """!Create new surface with constant value"""
+        #TODO settings
+        name = self.mapWindow.NewConstant()
+        win = self.FindWindowById(self.win['constant']['surface'])
+        name = _("constant#") + str(name)
+        win.Append(name)
+        win.SetStringSelection(name)
+        self.OnConstantSelection(None)
+        self.EnablePage(name = 'constant', enabled = True)
+        
+        self.mapWindow.Refresh(eraseBackground = False)
+        
+        # need to update list of surfaces in vector page
+        for vtype in ('points', 'lines'):
+            checklist = self.FindWindowById(self.win['vector'][vtype]['surface'])
+            checklist.Append(name)
+        win = self.FindWindowById(self.win['vector']['map'])
+        win.SetValue(win.GetValue())
+                
+
+    def OnDeleteConstant(self, event):
+        """!Delete selected constant surface"""
+        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
+        if layerIdx == wx.NOT_FOUND:
+            return
+        name = self.FindWindowById(self.win['constant']['surface']).GetStringSelection()
+        self.mapWindow.DeleteConstant(layerIdx)
+        win = self.FindWindowById(self.win['constant']['surface'])
+        win.Delete(layerIdx)
+        if win.IsEmpty():
+            win.SetValue("")
+            self.EnablePage(name = 'constant', enabled = False)
+        else:
+            win.SetSelection(0)
+            self.OnConstantSelection(None)
+            
+        # need to update list of surfaces in vector page
+        for vtype in ('points', 'lines'):
+            checklist = self.FindWindowById(self.win['vector'][vtype]['surface'])
+            checklist.Delete(checklist.FindString(name))
+            
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+    
+    def OnConstantSelection(self, event):
+        """!Constant selected"""
+        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
+        if layerIdx == wx.NOT_FOUND:
+            return
+        name = _("constant#") + str(layerIdx + 1)
+        data = self.mapWindow.constants[layerIdx]
+        for attr, value in data['constant'].iteritems():
+            if attr == 'color':
+                value = self._getColorFromString(value)
+            if attr in ('color', 'value', 'resolution', 'transp'):
+                if attr == 'transp':
+                    self.FindWindowById(self.win['constant'][attr]).SetValue(self._getPercent(value))
+                self.FindWindowById(self.win['constant'][attr]).SetValue(value)
+        
+    def OnSetConstantProp(self, event):
+        """!Change properties (color, value, resolution)
+            of currently selected constant surface"""
+        layerIdx = self.FindWindowById(self.win['constant']['surface']).GetSelection()
+        if layerIdx == wx.NOT_FOUND:
+            return
+        data = self.mapWindow.constants[layerIdx]
+        for attr in ('resolution', 'value', 'transp'):
+            data['constant'][attr] = self.FindWindowById(self.win['constant'][attr]).GetValue()
+        data['constant']['color'] = self._getColorString(
+                self.FindWindowById(self.win['constant']['color']).GetValue())
+        data['constant']['transp'] = self._getPercent(data['constant']['transp'], toPercent = False)
+        
+       # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event) 
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnFringe(self, event):
+        """!Show/hide fringe"""
+        data = self.GetLayerData('fringe')['surface']
+        
+        sid = data['object']['id']
+        elev = self.FindWindowById(self.win['fringe']['elev']).GetValue()
+        color = self.FindWindowById(self.win['fringe']['color']).GetValue()
+        
+        self._display.SetFringe(sid, color, elev,
+                                self.FindWindowById(self.win['fringe']['nw']).IsChecked(),
+                                self.FindWindowById(self.win['fringe']['ne']).IsChecked(),
+                                self.FindWindowById(self.win['fringe']['sw']).IsChecked(),
+                                self.FindWindowById(self.win['fringe']['se']).IsChecked())
+        self.mapWindow.Refresh(False)
+        
+    def OnScroll(self, event, win, data):
+        """!Generic scrolling handler"""
+        winName = self.__GetWindowName(win, event.GetId())
+        if not winName:
+            return
+        data[winName] = self.FindWindowById(event.GetId()).GetValue()
+        for w in win[winName].itervalues():
+            self.FindWindowById(w).SetValue(data[winName])
+        
+        event.Skip()
+        
+    def AdjustSliderRange(self, slider, value):
+        minim, maxim = slider.GetRange()
+        if not (minim <= value <= maxim):
+            slider.SetRange(min(minim, value), max(maxim, value))
+    
+    def _createIsosurfacePanel(self, parent):
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        
+        vSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Isosurface attributes")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        
+        self.win['volume']['attr'] = {}
+        inout = wx.CheckBox(parent = panel, id = wx.ID_ANY, 
+                            label = _("toggle normal direction"))
+        gridSizer.Add(item = inout, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL)
+        inout.Bind(wx.EVT_CHECKBOX, self.OnInOutMode)
+        self.win['volume']['inout'] = inout.GetId()
+        
+        row = 1
+        for code, attrb in (('topo', _("Isosurface value")),
+                            ('color', _("Color")),
+                            ('mask', _("Mask")),
+                            ('transp', _("Transparency")),
+                            ('shine', _("Shininess"))):
+            self.win['volume'][code] = {} 
+            # label
+            colspan = 1
+            if code == 'topo':
+                colspan = 2
+            gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                             label = attrb + ':'),
+                          pos = (row, 0), span = (1, colspan),flag = wx.ALIGN_CENTER_VERTICAL)
+            if code != 'topo':
+                use = wx.Choice (parent = panel, id = wx.ID_ANY, size = (100, -1),
+                                 choices = [_("map")])
+            else:
+                use = None
+            # check for required properties
+            if code not in ('topo', 'color', 'shine'):
+                use.Insert(item = _("unset"), pos = 0)
+                self.win['volume'][code]['required'] = False
+            else:
+                self.win['volume'][code]['required'] = True
+            if use and code != 'mask':
+                use.Append(item = _('constant'))
+            if use:
+                self.win['volume'][code]['use'] = use.GetId()
+                use.Bind(wx.EVT_CHOICE, self.OnMapObjUse)
+                gridSizer.Add(item = use, flag = wx.ALIGN_CENTER_VERTICAL,
+                              pos = (row, 1))
+                    
+            if code != 'topo':
+                map = Select(parent = panel, id = wx.ID_ANY,
+                             # size = globalvar.DIALOG_GSELECT_SIZE,
+                             size = (200, -1),
+                             type = "grid3")
+                self.win['volume'][code]['map'] = map.GetId() - 1 # FIXME
+                map.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
+                gridSizer.Add(item = map, flag = wx.ALIGN_CENTER_VERTICAL,
+                              pos = (row, 2))
+            else:
+                map = None
+            
+            if code == 'color':
+                color = UserSettings.Get(group = 'nviz', key = 'volume', subkey = ['color', 'value'])
+                value = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                          colour = color,
+                                          size = globalvar.DIALOG_COLOR_SIZE)
+                value.Bind(csel.EVT_COLOURSELECT, self.OnVolumeIsosurfMap)
+                value.SetName('color')
+            elif code == 'mask':
+                value = None
+            elif code == 'topo':
+                value = NumTextCtrl(parent = panel, id = wx.ID_ANY, size = (200, -1),
+                            style = wx.TE_PROCESS_ENTER)
+                value.Bind(wx.EVT_TEXT_ENTER, self.OnVolumeIsosurfMap)
+                value.Bind(wx.EVT_KILL_FOCUS, self.OnVolumeIsosurfMap)
+##                value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
+            else:
+                size = (65, -1)
+                value = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = size,
+                                    initial = 0)
+                if code == 'topo':
+                    value.SetRange(minVal = -1e9, maxVal = 1e9)
+                elif code in ('shine', 'transp'):
+                    value.SetRange(minVal = 0, maxVal = 100)
+                
+                value.Bind(wx.EVT_SPINCTRL, self.OnVolumeIsosurfMap)
+                value.Bind(wx.EVT_TEXT, self.OnVolumeIsosurfMap)
+            
+            if value:
+                self.win['volume'][code]['const'] = value.GetId()
+                if code == 'topo':
+                    gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
+                                  pos = (row, 2))
+                else:
+                    value.Enable(False)
+                    gridSizer.Add(item = value, flag = wx.ALIGN_CENTER_VERTICAL,
+                                  pos = (row, 3))
+            else:
+                self.win['volume'][code]['const'] = None
+            
+            if code != 'topo':
+                self.SetMapObjUseMap(nvizType = 'volume',
+                                     attrb = code) # -> enable map / disable constant
+            
+            row += 1
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        vSizer.Add(item = boxSizer, proportion = 1,
+                     flag = wx.EXPAND, border = 0)
+        panel.SetSizer(vSizer)
+        
+        return panel
+    
+    def _createSlicePanel(self, parent):
+        panel = wx.Panel(parent = parent, id = wx.ID_ANY)
+        
+        vSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                            label = " %s " % (_("Slice attributes")))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        hSizer = wx.BoxSizer()
+        
+        self.win['volume']['slice'] = {}
+        hSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                      label = _("Slice parallel to axis:")), proportion = 0,
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 3)
+        axes = wx.Choice(parent = panel, id = wx.ID_ANY, size = (65, -1), choices = ("X", "Y", "Z"))
+        hSizer.Add(axes, proportion = 0, flag = wx.ALIGN_LEFT|wx.LEFT, border = 3)
+        self.win['volume']['slice']['axes'] = axes.GetId()
+        axes.Bind(wx.EVT_CHOICE, self.OnVolumeSliceAxes)
+        boxSizer.Add(hSizer, proportion = 0, flag = wx.ALL|wx.EXPAND, border = 3)
+        
+        gridSizer = wx.GridBagSizer(vgap = 3, hgap = 3)
+        gridSizer.AddGrowableCol(0,1)
+        gridSizer.AddGrowableCol(1,2)
+        gridSizer.AddGrowableCol(2,2)
+        
+        # text labels
+        for i in range(2):
+            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
+            label.SetName('label_edge_' + str(i))
+            gridSizer.Add(item = label, pos = (0, i + 1),
+                          flag = wx.ALIGN_CENTER)
+        for i in range(2,4):
+            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
+            label.SetName('label_edge_' + str(i))
+            gridSizer.Add(item = label, pos = (3, i -1),
+                          flag = wx.ALIGN_CENTER)
+        for i in range(2):
+            label = wx.StaticText(parent = panel, id = wx.ID_ANY)
+            label.SetName('label_coord_' + str(i))
+            gridSizer.Add(item = label, pos = (i + 1, 0),
+                          flag = wx.ALIGN_CENTER_VERTICAL)
+        label = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        label.SetName('label_coord_2')
+        gridSizer.Add(item = label, pos = (4, 0), 
+                          flag = wx.ALIGN_CENTER_VERTICAL)
+        # sliders
+        for i, coord in enumerate(('x1', 'x2')):
+            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
+            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
+            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
+            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
+            gridSizer.Add(item = slider, pos = (1, i + 1), 
+                          flag = wx.ALIGN_CENTER|wx.EXPAND)
+                        
+        for i, coord in enumerate(('y1', 'y2')):
+            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
+            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
+            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
+            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
+            gridSizer.Add(item = slider, pos = (2, i + 1), 
+                          flag = wx.ALIGN_CENTER|wx.EXPAND)
+        
+        for i, coord in enumerate(('z1', 'z2')):
+            slider = wx.Slider(parent = panel, id = wx.ID_ANY, minValue = 0, maxValue = 100, value = 0)
+            self.win['volume']['slice']['slider_' + coord] = slider.GetId()
+            slider.Bind(wx.EVT_SPIN, self.OnSlicePositionChange)
+            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSlicePositionChanged)
+            gridSizer.Add(item = slider, pos = (4,i+1), 
+                          flag = wx.ALIGN_CENTER|wx.EXPAND)
+                        
+        
+        boxSizer.Add(item = gridSizer, proportion = 1,
+                     flag = wx.ALL | wx.EXPAND, border = 3)
+        
+        # transparency, reset
+        hSizer = wx.BoxSizer()
+        hSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                      label = _("Transparency:")), proportion = 0,
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, border = 7)
+        spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (65, -1),
+                           min = 0, max = 100, initial = 0)
+        spin.Bind(wx.EVT_SPINCTRL, self.OnSliceTransparency)
+        self.win['volume']['slice']['transp'] = spin.GetId()
+        hSizer.Add(item = spin, proportion = 0,
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP, border = 7)
+                    
+        hSizer.Add(item = wx.Size(-1, -1), proportion = 1,
+                      flag = wx.EXPAND)
+        reset = wx.Button(parent = panel, id = wx.ID_ANY, label = _("Reset"))
+        reset.Bind(wx.EVT_BUTTON, self.OnSliceReset)
+        self.win['volume']['slice']['reset'] = reset.GetId()
+        hSizer.Add(item = reset, proportion = 0,
+                      flag = wx.ALIGN_CENTER_VERTICAL|wx.TOP, border = 7)
+        
+        boxSizer.Add(hSizer, proportion = 0, flag = wx.ALL|wx.EXPAND, border = 3)
+        panel.SetSizer(boxSizer)
+        
+        return panel
+    
+    def _createControl(self, parent, data, name, range, bind = (None, None, None),
+                       sliderHor = True, size = 200, floatSlider = False):
+        """!Add control (Slider + TextCtrl)"""
+        data[name] = dict()
+        if sliderHor:
+            style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
+                wx.SL_BOTTOM
+            sizeW = (size, -1)
+        else:
+            style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | \
+                wx.SL_INVERSE
+            sizeW = (-1, size)
+        
+        kwargs = dict(parent = parent, id = wx.ID_ANY,
+                           minValue = range[0],
+                           maxValue = range[1],
+                           style = style,
+                           size = sizeW)
+        if floatSlider:
+            slider = FloatSlider(**kwargs)
+        else:
+            slider = wx.Slider(**kwargs)
+            
+        slider.SetName('slider')
+        if bind[0]:
+            #EVT_SCROLL emits event after slider is released, EVT_SPIN not
+            slider.Bind(wx.EVT_SPIN, bind[0])
+        
+        if bind[1]:
+            slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, bind[1]) 
+        data[name]['slider'] = slider.GetId()
+        
+        text = NumTextCtrl(parent = parent, id = wx.ID_ANY, size = (65, -1),
+                            style = wx.TE_PROCESS_ENTER)
+        
+        text.SetName('text')
+        if bind[2]:
+            text.Bind(wx.EVT_TEXT_ENTER, bind[2])
+            text.Bind(wx.EVT_KILL_FOCUS, bind[2])
+        
+        data[name]['text'] = text.GetId()
+        
+    def _createCompass(self, panel, sizer, type):
+        """!Create 'compass' widget for light and view page"""
+        w = wx.Button(panel, id = wx.ID_ANY, label = _("W"))
+        n = wx.Button(panel, id = wx.ID_ANY, label = _("N"))
+        s = wx.Button(panel, id = wx.ID_ANY, label = _("S"))
+        e = wx.Button(panel, id = wx.ID_ANY, label = _("E"))
+        nw = wx.Button(panel, id = wx.ID_ANY, label = _("NW"))
+        ne = wx.Button(panel, id = wx.ID_ANY, label = _("NE"))
+        se = wx.Button(panel, id = wx.ID_ANY, label = _("SE"))
+        sw = wx.Button(panel, id = wx.ID_ANY, label = _("SW"))
+        minWidth = sw.GetTextExtent(sw.GetLabel())[0] + 15
+        for win, name in zip((w, n, s, e, nw, ne, se, sw),
+                        ('w', 'n', 's', 'e', 'nw', 'ne', 'se', 'sw')):
+            win.SetMinSize((minWidth, -1))
+            win.Bind(wx.EVT_BUTTON, self.OnLookFrom)
+            win.SetName(type + '_' + name)
+        sizer.Add(item = nw, pos = (0, 0), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = n, pos = (0, 1), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = ne, pos = (0, 2), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = e, pos = (1, 2), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = se, pos = (2, 2), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = s, pos = (2, 1), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = sw, pos = (2, 0), flag = wx.ALIGN_CENTER)
+        sizer.Add(item = w, pos = (1, 0), flag = wx.ALIGN_CENTER)
+        
+        
+        
+    def __GetWindowName(self, data, id):
+        for name in data.iterkeys():
+            if type(data[name]) is type({}):
+                for win in data[name].itervalues():
+                    if win == id:
+                        return name
+            else:
+                if data[name] == id:
+                    return name
+        
+        return None
+
+    def UpdateSettings(self):
+        """!Update view from settings values 
+        stored in self.mapWindow.view dictionary"""
+        for control in ('height',
+                        'persp',
+                        'twist',
+                        'z-exag'):
+            for win in self.win['view'][control].itervalues():             
+                try:
+                    if control == 'height':
+                        value = int(self.mapWindow.iview[control]['value'])
+                    else:
+                        value = self.mapWindow.view[control]['value']
+                except KeyError:
+                    value = -1
+                        
+                self.FindWindowById(win).SetValue(value)
+        
+        viewWin = self.FindWindowById(self.win['view']['position'])
+        x, y = viewWin.UpdatePos(self.mapWindow.view['position']['x'],
+                                 self.mapWindow.view['position']['y'])
+        viewWin.Draw(pos = (x, y), scale = True)
+        viewWin.Refresh(False)
+        
+        color = self._getColorString(self.mapWindow.view['background']['color'])
+        self._display.SetBgColor(str(color))
+        
+        self.Update()
+        
+        self.mapWindow.Refresh(eraseBackground = False)
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(True)
+        
+    def OnShowLightModel(self, event):
+        """!Show light model"""
+        self._display.showLight = event.IsChecked()
+        self._display.DrawLightingModel()
+        
+    def OnLightChange(self, event):
+        """!Position of the light changing"""
+        winName = self.__GetWindowName(self.win['light'], event.GetId())
+        if not winName:
+            return
+        
+        value = self.FindWindowById(event.GetId()).GetValue()
+        
+        self.mapWindow.light['position']['z'] = value
+        for win in self.win['light'][winName].itervalues():
+            self.FindWindowById(win).SetValue(value)
+            
+        self.PostLightEvent()
+        
+        event.Skip()
+        
+    def OnLightChanged(self, event):
+        """!Light changed"""
+        self.PostLightEvent(refresh = True)
+        
+    def OnLightColor(self, event):
+        """!Color of the light changed"""
+        self.mapWindow.light['color'] = tuple(event.GetValue())
+        
+        self.PostLightEvent(refresh = True)
+        
+        event.Skip()
+        
+    def OnLightValue(self, event):
+        """!Light brightness/ambient changing"""
+        data = self.mapWindow.light
+        self.OnScroll(event, self.win['light'], data)
+        
+        self.PostLightEvent()
+        event.Skip()
+        
+    def OnBgColor(self, event):
+        """!Background color changed"""
+        color = event.GetValue()
+        self.mapWindow.view['background']['color'] = tuple(color)
+        color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
+        self._display.SetBgColor(str(color))
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnSetSurface(self, event):
+        """!Surface selected, currently used for fringes"""
+        name = event.GetString()
+        try:
+            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')['surface']
+        except:
+            self.EnablePage('fringe', False)
+            return
+        
+        layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
+        self.EnablePage('fringe', True)
+        
+    def OnSetRaster(self, event):
+        """!Raster map selected, update surface page"""
+        name = event.GetString()
+        try:
+            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')['surface']
+        except:
+            self.EnablePage('surface', False)
+            return
+
+        layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
+        self.EnablePage('surface', True)
+        self.UpdateSurfacePage(layer, data, updateName = False)
+        
+    def OnSetVector(self, event):
+        """!Vector map selected, update properties page"""
+        name = event.GetString()
+        try:
+            data = self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'nviz')['vector']
+        except:
+            self.EnablePage('vector', False)
+            return
+        layer = self.mapWindow.GetLayerByName(name, mapType = 'vector')
+        self.EnablePage('vector', True)
+        self.UpdateVectorPage(layer, data, updateName = False)
+
+    def OnSetRaster3D(self, event):
+        """!3D Raster map selected, update surface page"""
+        name = event.GetString()
+        try:
+            data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')['volume']
+        except:
+            self.EnablePage('volume', False)
+            return
+        
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        self.EnablePage('volume', True)
+        self.UpdateVolumePage(layer, data, updateName = False)
+        
+    def OnViewChange(self, event):
+        """!Change view, render in quick mode"""
+        # find control
+        winName = self.__GetWindowName(self.win['view'], event.GetId())
+        if not winName:
+            return
+        
+        value = self.FindWindowById(event.GetId()).GetValue()
+        slider = self.FindWindowById(self.win['view'][winName]['slider'])
+        self.AdjustSliderRange(slider = slider, value = value)
+        
+        if winName == 'height':
+            view = self.mapWindow.iview # internal
+        else:
+            view = self.mapWindow.view
+        
+        if winName == 'z-exag' and value >= 0:
+            self.PostViewEvent(zExag = True)
+        else:
+            self.PostViewEvent(zExag = False)
+        
+        if winName in ('persp', 'twist'):
+            convert = int
+        else:
+            convert = float
+        
+        view[winName]['value'] = convert(value)
+            
+        for win in self.win['view'][winName].itervalues():
+            self.FindWindowById(win).SetValue(value)
+
+        self.mapWindow.iview['dir']['use'] = False
+        self.mapWindow.render['quick'] = True
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+        
+    def OnViewChanged(self, event):
+        """!View changed, render in full resolution"""
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+        self.UpdateSettings()
+        try:# when calling event = None
+            event.Skip()
+        except AttributeError:
+            pass
+            
+    def OnViewChangedText(self, event):
+        """!View changed, render in full resolution""" 
+        self.mapWindow.render['quick'] = False
+        self.OnViewChange(event)
+        self.OnViewChanged(None)
+        self.Update()
+        
+        event.Skip()
+    
+    def OnLookAt(self, event):
+        """!Look here/center"""
+        name = self.FindWindowById(event.GetId()).GetName()
+        if name == 'center':
+            self._display.LookAtCenter()
+            focus = self.mapWindow.iview['focus']
+            focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
+            self.mapWindow.saveHistory = True
+            self.mapWindow.Refresh(False)
+        elif name == 'top':
+            self.mapWindow.view['position']['x'] = 0.5
+            self.mapWindow.view['position']['y'] = 0.5
+            self.PostViewEvent(zExag = True)
+            self.UpdateSettings()
+            self.mapWindow.Refresh(False)
+        else: # here
+            if self.FindWindowById(event.GetId()).GetValue():
+                self.mapDisplay.Raise()
+                self.mapWindow.mouse['use'] = 'lookHere'
+                self.mapWindow.SetCursor(self.mapWindow.cursors["cross"])
+            else:
+                self.mapWindow.mouse['use'] = 'default'
+                self.mapWindow.SetCursor(self.mapWindow.cursors['default'])
+            
+    def OnResetView(self, event):
+        """!Reset to default view (view page)"""
+        self.mapWindow.ResetView()
+        self.UpdateSettings()
+        self.mapWindow.Refresh(False)
+        
+    def OnResetSurfacePosition(self, event):
+        """!Reset position of surface"""
+        
+        for win in self.win['surface']['position'].itervalues():
+            if win == self.win['surface']['position']['axis']:
+                self.FindWindowById(win).SetSelection(0)
+            elif win == self.win['surface']['position']['reset']:
+                continue
+            else:
+                self.FindWindowById(win).SetValue(0)
+                
+        data = self.GetLayerData('surface')
+        data['surface']['position']['x'] = 0
+        data['surface']['position']['y'] = 0
+        data['surface']['position']['z'] = 0
+        data['surface']['position']['update'] = None
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+            
+    def OnLookFrom(self, event):
+        """!Position of view/light changed by buttons"""
+        name = self.FindWindowById(event.GetId()).GetName()
+        buttonName = name.split('_')[1]
+        if name.split('_')[0] == 'view':
+            type = 'view'
+            data = self.mapWindow.view
+        else:
+            type = 'light'
+            data = self.mapWindow.light
+        if buttonName == 'n': # north
+            data['position']['x'] = 0.5
+            data['position']['y'] = 0.0
+        elif buttonName == 's': # south
+            data['position']['x'] = 0.5
+            data['position']['y'] = 1.0
+        elif buttonName == 'e': # east
+            data['position']['x'] = 1.0
+            data['position']['y'] = 0.5
+        elif buttonName =='w': # west
+            data['position']['x'] = 0.0
+            data['position']['y'] = 0.5
+        elif buttonName == 'nw': # north-west
+            data['position']['x'] = 0.0
+            data['position']['y'] = 0.0
+        elif buttonName == 'ne': # north-east
+            data['position']['x'] = 1.0
+            data['position']['y'] = 0.0
+        elif buttonName == 'se': # south-east
+            data['position']['x'] = 1.0
+            data['position']['y'] = 1.0
+        elif buttonName == 'sw': # south-west
+            data['position']['x'] = 0.0
+            data['position']['y'] = 1.0
+        if type == 'view':    
+            self.PostViewEvent(zExag = True)
+            
+            self.UpdateSettings()
+        else:
+            self.PostLightEvent()
+            lightWin = self.FindWindowById(self.win['light']['position'])
+            x, y = lightWin.UpdatePos(self.mapWindow.light['position']['x'],
+                                     self.mapWindow.light['position']['y'])
+            lightWin.Draw(pos = (x, y), scale = True)
+            lightWin.Refresh(False)
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+
+    def OnMapObjUse(self, event):
+        """!Set surface attribute -- use -- map/constant"""
+        if not self.mapWindow.init:
+            return
+        
+        wx.Yield()
+        
+        # find attribute row
+        attrb = self.__GetWindowName(self.win['surface'], event.GetId())
+        if not attrb:
+            attrb = self.__GetWindowName(self.win['volume'], event.GetId())
+            nvizType = 'volume'
+        else:
+            nvizType = 'surface'
+        
+        selection = event.GetSelection()
+        if self.win[nvizType][attrb]['required']: # no 'unset'
+            selection += 1
+        if selection == 0: # unset
+            useMap = None
+            value = ''
+        elif selection == 1: # map
+            useMap = True
+            value = self.FindWindowById(self.win[nvizType][attrb]['map']).GetValue()
+        elif selection == 2: # constant
+            useMap = False
+            if attrb == 'color':
+                value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetColour()
+                value = self._getColorString(value)
+            else:
+                value = self._getPercent(self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue(), toPercent = False)
+        
+        self.SetMapObjUseMap(nvizType = nvizType,
+                             attrb = attrb, map = useMap)
+        
+        name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
+        if nvizType == 'surface':
+            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
+            data[nvizType]['attribute'][attrb] = { 'map' : useMap,
+                                                   'value' : str(value),
+                                                   'update' : None }
+        else: # volume / isosurface
+            data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
+            list = self.FindWindowById(self.win['volume']['isosurfs'])
+            id = list.GetSelection()
+            if id != -1:
+                data[nvizType]['isosurface'][id][attrb] = { 'map' : useMap,
+                                                            'value' : str(value),
+                                                            'update' : None }
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+ 
+    def EnablePage(self, name, enabled = True):
+        """!Enable/disable all widgets on page"""
+        for key, item in self.win[name].iteritems():
+            if key in ('map', 'surface', 'new','planes'):
+                continue
+            if type(item) == types.DictType:
+                for skey, sitem in self.win[name][key].iteritems():
+                    if type(sitem) == types.DictType:
+                        for ssitem in self.win[name][key][skey].itervalues():
+                            if type(ssitem) == types.IntType:
+                                self.FindWindowById(ssitem).Enable(enabled)
+                    else:
+                        if type(sitem) == types.IntType:
+                            self.FindWindowById(sitem).Enable(enabled)
+            else:
+                if type(item) == types.IntType:
+                    self.FindWindowById(item).Enable(enabled)
+        
+    def SetMapObjUseMap(self, nvizType, attrb, map = None):
+        """!Update dialog widgets when attribute type changed"""
+        if attrb in ('topo', 'color', 'shine'):
+            incSel = -1 # decrement selection (no 'unset')
+        else:
+            incSel = 0
+        if nvizType == 'volume' and attrb == 'topo':
+            return
+        if map is True: # map
+            if attrb != 'topo': # changing map topography not allowed
+                # not sure why, but here must be disabled both ids, should be fixed!
+                self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(True)
+            if self.win[nvizType][attrb]['const']:
+                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(False)
+            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(1 + incSel)
+        elif map is False: # const
+            self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(False)
+            if self.win[nvizType][attrb]['const']:
+                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(True)
+            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(2 + incSel)
+        else: # unset
+            self.FindWindowById(self.win[nvizType][attrb]['use']).SetSelection(0)
+            self.FindWindowById(self.win[nvizType][attrb]['map'] + 1).Enable(False)
+            if self.win[nvizType][attrb]['const']:
+                self.FindWindowById(self.win[nvizType][attrb]['const']).Enable(False)
+            
+        
+    def OnSurfaceMap(self, event):
+        """!Set surface attribute"""
+        if self.vetoGSelectEvt:
+            self.vetoGSelectEvt = False
+            return
+        self.SetMapObjAttrb(nvizType = 'surface', winId = event.GetId())
+        
+    def SetMapObjAttrb(self, nvizType, winId):
+        """!Set map object (surface/isosurface) attribute (map/constant)"""
+        if not self.mapWindow.init:
+            return
+        
+        attrb = self.__GetWindowName(self.win[nvizType], winId)
+        if not attrb:
+            return
+        
+        if not (nvizType == 'volume' and attrb == 'topo'):
+            selection = self.FindWindowById(self.win[nvizType][attrb]['use']).GetSelection()
+            if self.win[nvizType][attrb]['required']:
+                selection += 1
+
+            if selection == 0: # unset
+                useMap = None
+                value = ''
+            elif selection == 1: # map
+                value = self.FindWindowById(self.win[nvizType][attrb]['map']).GetValue()
+                useMap = True
+            else: # constant
+                if attrb == 'color':
+                    value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetColour()
+                    # tuple to string
+                    value = self._getColorString(value)
+                else:
+                    value = self._getPercent(
+                        self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue(), toPercent = False)
+                    
+                useMap = False
+        else:
+            useMap = None
+            value = self.FindWindowById(self.win[nvizType][attrb]['const']).GetValue()
+        if not self.pageChanging:
+            name = self.FindWindowById(self.win[nvizType]['map']).GetValue()
+            if nvizType == 'surface':
+                data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
+                data[nvizType]['attribute'][attrb] = { 'map' : useMap,
+                                                       'value' : str(value),
+                                                       'update' : None }
+            else:
+                data = self.mapWindow.GetLayerByName(name, mapType = '3d-raster', dataType = 'nviz')
+                list = self.FindWindowById(self.win['volume']['isosurfs'])
+                id = list.GetSelection()
+                if id > -1:
+                    data[nvizType]['isosurface'][id][attrb] = { 'map' : useMap,
+                                                                'value' : str(value),
+                                                                'update' : None }
+                    if attrb == 'topo':
+                        list = self.FindWindowById(self.win['volume']['isosurfs'])
+                        sel = list.GetSelection()
+                        list.SetString(sel, "%s %s" % (_("Level"), str(value)))
+                        list.Check(sel)
+            
+            # update properties
+            event = wxUpdateProperties(data = data)
+            wx.PostEvent(self.mapWindow, event)
+            
+            if self.mapDisplay.IsAutoRendered():
+                self.mapWindow.Refresh(False)
+        
+    def OnSurfaceResolution(self, event):
+        """!Draw resolution changed"""
+        self.SetSurfaceResolution()
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+    
+
+    def SetSurfaceResolution(self):
+        """!Set draw resolution"""
+        coarse = self.FindWindowById(self.win['surface']['draw']['res-coarse']).GetValue()
+        fine = self.FindWindowById(self.win['surface']['draw']['res-fine']).GetValue()
+        
+        data = self.GetLayerData('surface')
+        data['surface']['draw']['resolution'] = { 'coarse' : coarse,
+                                                  'fine' : fine,
+                                                  'update' : None }
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+    def SetSurfaceMode(self):
+        """!Set draw mode"""
+        mode = self.FindWindowById(self.win['surface']['draw']['mode']).GetSelection()
+        style = self.FindWindowById(self.win['surface']['draw']['style']).GetSelection()
+        if style == 0: # wire
+            self.FindWindowById(self.win['surface']['draw']['wire-color']).Enable(True)
+        elif style == 1: # surface
+            self.FindWindowById(self.win['surface']['draw']['wire-color']).Enable(False)
+        
+        shade = self.FindWindowById(self.win['surface']['draw']['shading']).GetSelection()
+        
+        value, desc = self.mapWindow.nvizDefault.GetDrawMode(mode, style, shade)
+        
+        return value, desc
+
+    def OnSurfaceMode(self, event):
+        """!Set draw mode"""
+        value, desc = self.SetSurfaceMode()
+        
+        data = self.GetLayerData('surface')
+        data['surface']['draw']['mode'] = { 'value' : value,
+                                            'desc' : desc,
+                                            'update' : None }
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+
+    def OnSurfaceModeAll(self, event):
+        """!Set draw mode (including wire color) for all loaded surfaces"""
+        value, desc = self.SetSurfaceMode()
+        coarse = self.FindWindowById(self.win['surface']['draw']['res-coarse']).GetValue()
+        fine = self.FindWindowById(self.win['surface']['draw']['res-fine']).GetValue()
+        color = self.FindWindowById(self.win['surface']['draw']['wire-color']).GetColour()
+        cvalue = self._getColorString(color)
+        
+        for name in self.mapWindow.GetLayerNames(type = 'raster'):
+            
+            data = self.mapWindow.GetLayerByName(name, mapType = 'raster', dataType = 'nviz')
+            if not data:
+                continue # shouldy no happen
+            
+            data['surface']['draw']['all'] = True
+            data['surface']['draw']['mode'] = { 'value' : value,
+                                                'desc' : desc,
+                                                'update' : None }
+            data['surface']['draw']['resolution'] = { 'coarse' : coarse,
+                                                      'fine' : fine,
+                                                      'update' : None }
+            data['surface']['draw']['wire-color'] = { 'value' : cvalue,
+                                                      'update' : None }
+            
+            # update properties
+            event = wxUpdateProperties(data = data)
+            wx.PostEvent(self.mapWindow, event)
+            
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def _getColorString(self, color):
+        """!Convert color tuple to R:G:B format
+
+        @param color tuple
+        
+        @return string R:G:B
+        """
+        return str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
+    
+    def _getColorFromString(self, color, delim = ':'):
+        """!Convert color string (R:G:B) to wx.Color
+
+        @param color string
+        @param delim delimiter
+
+        @return wx.Color instance
+        """
+        return wx.Color(*map(int, color.split(delim)))
+    
+    def _get3dRange(self, name):
+        """!Gelper func for getting range of 3d map"""
+        ret = RunCommand('r3.info', read = True, flags = 'r', map = name)
+        if ret:
+            range = []
+            for value in ret.strip('\n').split('\n'):
+                range.append(float(value.split('=')[1]))
+            return range
+        
+        return -1e6, 1e6
+    
+    def _getPercent(self, value, toPercent = True):
+        """!Convert values 0 - 255 to percents and vice versa"""
+        value = int(value)
+        if toPercent:
+            value = int(value/255. * 100)
+        else:
+            value = int(value/100. * 255)
+        return value
+    
+    def OnSurfaceWireColor(self, event):
+        """!Set wire color"""
+        data = self.GetLayerData('surface')
+        value = self._getColorString(event.GetValue())
+        data['surface']['draw']['wire-color'] = { 'value' : value,
+                                                  'update' : None }
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnSurfaceAxis(self, event):
+        """!Surface position, axis changed"""
+        data = self.GetLayerData('surface')
+        id = data['surface']['object']['id']
+        
+        axis = self.FindWindowById(self.win['surface']['position']['axis']).GetSelection()
+        slider = self.FindWindowById(self.win['surface']['position']['slider'])
+        text = self.FindWindowById(self.win['surface']['position']['text'])
+        xydim = self._display.GetLongDim()
+        zdim = self._display.GetZRange()
+        zdim = zdim[1] - zdim[0]
+        
+        x, y, z = self._display.GetSurfacePosition(id)
+        
+        if axis == 0: # x
+            slider.SetRange(-3 * xydim, 3 * xydim)
+            slider.SetValue(x)
+            text.SetValue(x)
+        elif axis == 1: # y
+            slider.SetRange(-3 * xydim, 3 * xydim)
+            slider.SetValue(y)
+            text.SetValue(y)
+        else: # z
+            slider.SetRange(-3 * zdim, 3 * zdim)
+            slider.SetValue(z)
+            text.SetValue(z)
+        
+    def OnSurfacePosition(self, event):
+        """!Surface position"""
+        winName = self.__GetWindowName(self.win['surface'], event.GetId())
+        if not winName:
+            return
+        axis = self.FindWindowById(self.win['surface']['position']['axis']).GetSelection()
+        
+        value = self.FindWindowById(event.GetId()).GetValue()
+        slider = self.FindWindowById(self.win['surface'][winName]['slider'])
+        self.AdjustSliderRange(slider = slider, value = value)
+        
+        for win in self.win['surface']['position'].itervalues():
+            if win in (self.win['surface']['position']['axis'],
+                       self.win['surface']['position']['reset']):
+                continue
+            else:
+                self.FindWindowById(win).SetValue(value)
+        
+        data = self.GetLayerData('surface')
+        id = data['surface']['object']['id']
+        x, y, z = self._display.GetSurfacePosition(id)
+        
+        if axis == 0: # x
+            x = value
+        elif axis == 1: # y
+            y = value
+        else: # z
+            z = value
+        
+        data['surface']['position']['x'] = x
+        data['surface']['position']['y'] = y
+        data['surface']['position']['z'] = z
+        data['surface']['position']['update'] = None
+        # update properties
+        
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        self.mapWindow.render['quick'] = True
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        #        self.UpdatePage('surface')
+        
+    def OnSurfacePositionChanged(self, event):
+        """!Surface position changed"""
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+
+    def OnSurfacePositionText(self, event):
+        """!Surface position changed by textctrl"""
+        self.OnSurfacePosition(event)
+        self.OnSurfacePositionChanged(None)
+        
+    def UpdateVectorShow(self, vecType, enabled):
+        """!Enable/disable lines/points widgets
+        
+        @param vecType vector type (lines, points)
+        """
+        if vecType != 'lines' and vecType != 'points':
+            return False
+        
+        for win in self.win['vector'][vecType].keys():
+            if win == 'show':
+                continue
+            if type(self.win['vector'][vecType][win]) == type({}):
+                for swin in self.win['vector'][vecType][win].keys():
+                    if enabled:
+                        self.FindWindowById(self.win['vector'][vecType][win][swin]).Enable(True)
+                    else:
+                        self.FindWindowById(self.win['vector'][vecType][win][swin]).Enable(False)
+            else:
+                if enabled:
+                    self.FindWindowById(self.win['vector'][vecType][win]).Enable(True)
+                else:
+                    self.FindWindowById(self.win['vector'][vecType][win]).Enable(False)
+        
+        return True
+    
+    def OnVectorShow(self, event):
+        """!Show vector lines/points"""
+        winId = event.GetId()
+        if winId == self.win['vector']['lines']['show']:
+            vecType = 'lines'
+            points = False
+        else: # points
+            vecType = 'points' 
+            points = True
+       
+        checked = event.IsChecked()
+        name = self.FindWindowById(self.win['vector']['map']).GetValue()
+        item = self.mapWindow.GetLayerByName(name, mapType = 'vector', dataType = 'item')
+        data = self.GetLayerData('vector')['vector']
+        
+        if checked:
+            self.mapWindow.LoadVector(item, points = points, append = False)
+        else:
+            self.mapWindow.UnloadVector(item, points = points, remove = False)
+        
+        self.UpdateVectorShow(vecType, checked)
+        
+        if checked:
+            try:
+                id = data[vecType]['object']['id']
+            except KeyError:
+                id = -1
+            
+            if id > 0:
+                self.mapWindow.SetMapObjProperties(item, id, vecType)
+                
+                # update properties
+                event = wxUpdateProperties(data = data)
+                wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+    
+    def OnVectorDisplay(self, event):
+        """!Display vector lines on surface/flat"""
+        rasters = self.mapWindow.GetLayerNames('raster')
+        if event.GetSelection() == 0: # surface
+            if len(rasters) < 1:
+                self.FindWindowById(self.win['vector']['lines']['surface']).Enable(False)
+                self.FindWindowById(self.win['vector']['lines']['flat']).SetSelection(1)
+                return
+            
+            self.FindWindowById(self.win['vector']['lines']['surface']).Enable(True)
+            # set first found surface
+            data = self.GetLayerData('vector')
+            data['vector']['lines']['mode']['surface'] = rasters[0]
+            self.FindWindowById(self.win['vector']['lines']['surface']).SetStringSelection( \
+                rasters[0])
+        else: # flat
+            self.FindWindowById(self.win['vector']['lines']['surface']).Enable(False)
+        
+        self.OnVectorLines(event)
+        
+        event.Skip()
+
+    def OnVectorLines(self, event):
+        """!Set vector lines mode, apply changes if auto-rendering is enabled"""
+        data = self.GetLayerData('vector')
+        width = self.FindWindowById(self.win['vector']['lines']['width']).GetValue()
+        
+        mode = {}
+        if self.FindWindowById(self.win['vector']['lines']['flat']).GetSelection() == 0:
+            mode['type'] = 'surface'
+            mode['surface'] = {}
+            checklist = self.FindWindowById(self.win['vector']['lines']['surface'])
+            value = list()
+            checked = list()
+            for surface in range(checklist.GetCount()):
+                value.append(checklist.GetString(surface))
+                checked.append(checklist.IsChecked(surface))
+                    
+            mode['surface']['value'] = value
+            mode['surface']['show'] = checked
+        else:
+            mode['type'] = 'flat'
+        
+        for attrb in ('width', 'mode'):
+            data['vector']['lines'][attrb]['update'] = None
+        data['vector']['lines']['width']['value'] = width
+        data['vector']['lines']['mode'] = mode
+        
+        color = self.FindWindowById(self.win['vector']['lines']['color']).GetColour()
+        
+        if isinstance(color, csel.ColourSelect):
+            pass #color picker not yet instantiated
+        else:
+            color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
+            data['vector']['lines']['color']['update'] = None
+            data['vector']['lines']['color']['value'] = color
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+                        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnVectorHeight(self, event):
+        id = event.GetId()
+        if id in self.win['vector']['lines']['height'].values():
+            vtype = 'lines'
+        else:
+            vtype = 'points'
+        
+        value = self.FindWindowById(id).GetValue()
+        slider = self.FindWindowById(self.win['vector'][vtype]['height']['slider'])
+        self.AdjustSliderRange(slider = slider, value = value)
+        
+        for win in self.win['vector'][vtype]['height'].itervalues():
+            self.FindWindowById(win).SetValue(value)
+        
+        data = self.GetLayerData('vector')
+        data['vector'][vtype]['height'] = { 'value' : value,
+                                            'update' : None }
+        
+        # update properties
+        
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        self.mapWindow.render['quick'] = True
+        self.mapWindow.render['v' + vtype] = True
+        self.mapWindow.Refresh(False)
+        
+        event.Skip()
+    
+    def OnVectorHeightFull(self, event):
+        """!Vector height changed, render in full resolution"""
+        self.OnVectorHeight(event)
+##        self.OnVectorSurface(event)
+        id = event.GetId()
+        if id in self.win['vector']['lines']['height'].values():
+            vtype = 'lines'
+        else:
+            vtype = 'points'
+        
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.render['v' + vtype] = False
+        self.mapWindow.Refresh(False)
+
+    def OnVectorHeightText(self, event):
+        """!Vector height changed, render in full resolution"""
+        
+        #        self.OnVectorHeight(event)
+        self.OnVectorHeightFull(event)
+    
+    def OnVectorSurface(self, event):
+        """!Reference surface for vector map (lines/points)"""   
+        id = event.GetId()
+        if id == self.win['vector']['lines']['surface']:
+            vtype = 'lines'
+        else:
+            vtype = 'points'
+        checkList = self.FindWindowById(self.win['vector'][vtype]['surface'])
+        checked = []
+        surfaces = []
+        for items in range(checkList.GetCount()):
+            checked.append(checkList.IsChecked(items))
+            surfaces.append(checkList.GetString(items))
+        
+        data = self.GetLayerData('vector')
+        data['vector'][vtype]['mode']['surface'] = { 'value' : surfaces,
+                                                     'show'  : checked}
+        data['vector'][vtype]['mode']['update'] = None 
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+            
+        
+    def OnVectorPoints(self, event):
+        """!Set vector points mode, apply changes if auto-rendering is enabled"""
+        data = self.GetLayerData('vector')
+        
+        size  = self.FindWindowById(self.win['vector']['points']['size']).GetValue()
+        marker = self.FindWindowById(self.win['vector']['points']['marker']).GetSelection()
+        #        width = self.FindWindowById(self.win['vector']['points']['width']).GetValue()
+        
+        for attrb in ('size', 'marker'):
+            data['vector']['points'][attrb]['update'] = None
+        data['vector']['points']['size']['value'] = size
+        #        data['vector']['points']['width']['value'] = width
+        data['vector']['points']['marker']['value'] = marker
+        
+        color = self.FindWindowById(self.win['vector']['points']['color']).GetColour()
+        if isinstance(color, csel.ColourSelect):
+            pass #color picker not yet instantiated
+        else:
+            color = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
+            data['vector']['points']['color']['update'] = None
+            data['vector']['points']['color']['value'] = color
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+
+    def OnCheckThematic(self, event):
+        """!Switch on/off thematic mapping"""
+        # can be called with no event to enable/disable button
+        if not event:
+            ids = (self.win['vector']['points']['thematic']['checkcolor'],
+                  self.win['vector']['lines']['thematic']['checkcolor'],
+                  self.win['vector']['points']['thematic']['checksize'],
+                  self.win['vector']['lines']['thematic']['checkwidth'])
+        else:
+            ids = (event.GetId(),)
+        for id in ids:
+            if id in self.win['vector']['points']['thematic'].values():
+                vtype = 'points'
+                if id == self.win['vector'][vtype]['thematic']['checkcolor']:
+                    attrType = 'color'
+                else:
+                    attrType = 'size'
+            else:
+                vtype = 'lines'
+                if id == self.win['vector'][vtype]['thematic']['checkcolor']:
+                    attrType = 'color'
+                else:
+                    attrType = 'width'
+                
+            check = self.win['vector'][vtype]['thematic']['check' + attrType]
+            button = self.win['vector'][vtype]['thematic']['button' + attrType]
+            if self.FindWindowById(check).GetValue():
+                checked = True
+            else:
+                checked = False
+            self.FindWindowById(button).Enable(checked)
+            
+            data = self.GetLayerData('vector')
+            
+            # decide if use GRASSRGB column
+            if attrType == 'color':
+                name = self.FindWindowById(self.win['vector']['map']).GetValue()
+                if not data['vector'][vtype]['thematic']['rgbcolumn']:
+                    try:
+                        id =  data['vector'][vtype]['object']['id']
+                    
+                        # if GRASSRGB exists and color table doesn't, use GRGB
+                        if self.HasGRASSRGB(name)  and \
+                            not self._display.CheckColorTable(id = id, type = vtype):
+                            data['vector'][vtype]['thematic']['rgbcolumn'] = 'GRASSRGB'
+                    except KeyError:
+                        pass
+                        
+            data['vector'][vtype]['thematic']['use' + attrType] = checked
+            data['vector'][vtype]['thematic']['update'] = None
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+            
+    def HasGRASSRGB(self, name):
+        """!Check if GRASSRGB column exist."""
+        column = False
+        
+        dbInfo = VectorDBInfo(name)
+        if len(dbInfo.layers):
+            table = dbInfo.layers[1]['table']
+            if 'GRASSRGB' in dbInfo.GetTableDesc(table):
+                column = True
+                
+        return column
+        
+    def OnSetThematic(self, event):
+        """!Set options for thematic points"""
+        if event.GetId() in self.win['vector']['points']['thematic'].values():
+            vtype = 'points'
+        else:
+            vtype = 'lines'
+        if event.GetId() == self.win['vector'][vtype]['thematic']['buttoncolor']:
+            attrType = 'color'
+        elif vtype == 'points':
+            attrType = 'size'
+        else:
+            attrType = 'width'
+        ctable = ThematicVectorTable(self, vtype, attributeType = attrType)
+        ctable.CentreOnScreen()
+        ctable.Show()
+        
+    def UpdateIsosurfButtons(self, list):
+        """!Enable/disable buttons 'add', 'delete',
+        'move up', 'move down'"""
+        nitems = list.GetCount()
+        add = self.parent.FindWindowById(self.win['volume']['btnAdd'])
+        delete = self.parent.FindWindowById(self.win['volume']['btnDelete'])
+        moveDown = self.parent.FindWindowById(self.win['volume']['btnMoveDown'])
+        moveUp = self.parent.FindWindowById(self.win['volume']['btnMoveUp'])
+        if nitems >= wxnviz.MAX_ISOSURFS:
+            # disable add button on max
+            add.Enable(False)
+        else:
+            add.Enable(True)
+        
+        if nitems < 1:
+            # disable 'delete' if only one item in the lis
+            delete.Enable(False)
+        else:
+            delete.Enable(True)
+        
+        if list.GetSelection() >= nitems - 1:
+            # disable 'move-down' if last
+            moveDown.Enable(False)
+        else:
+            moveDown.Enable(True)
+        
+        if list.GetSelection() < 1:
+            # disable 'move-up' if first
+            moveUp.Enable(False)
+        else:
+            moveUp.Enable(True)
+            
+    def OnVolumeMode(self, event):
+        """!Change mode isosurfaces/slices"""
+        mode = self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection()
+        data = self.GetLayerData('volume')['volume']
+        
+        sizer = self.isoPanel.GetContainingSizer()
+        sizer = self.slicePanel.GetContainingSizer()
+        listBox = self.FindWindowByName('listStaticBox')
+        if mode == 0:
+            sizer.Show(self.isoPanel)
+            sizer.Hide(self.slicePanel)
+            listBox.SetLabel(" %s " % _("List of isosurfaces"))
+            data['draw']['mode']['value'] = 0
+            data['draw']['mode']['desc'] = 'isosurface'
+        else:
+            sizer.Hide(self.isoPanel)
+            sizer.Show(self.slicePanel)
+            listBox.SetLabel(" %s " % _("List of slices"))
+            data['draw']['mode']['value'] = 1
+            data['draw']['mode']['desc'] = 'slice'
+        
+        if event:
+            name = self.FindWindowById(self.win['volume']['map']).GetValue()
+            layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+            self.UpdateVolumePage(layer, data, updateName = False)
+            
+        sizer.Layout()
+        listBox.GetParent().Fit()
+            
+    def OnVolumeDrawMode(self, event):
+        """!Set isosurface/slice draw mode"""
+        self.SetVolumeDrawMode(event.GetSelection())
+        
+    def SetVolumeDrawMode(self, selection):
+        """!Set isosurface draw mode"""
+        data = self.GetLayerData('volume')['volume']
+        id = data['object']['id']
+        
+        mode = 0
+        if selection == 0:
+            mode |= wxnviz.DM_FLAT
+        else:
+            mode |= wxnviz.DM_GOURAUD
+            
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            self._display.SetIsosurfaceMode(id, mode)
+            data['draw']['shading']['isosurface']['desc'] = 'gouraud'
+            data['draw']['shading']['isosurface']['value'] = mode
+        else:
+            self._display.SetSliceMode(id, mode)
+            data['draw']['shading']['slice']['desc'] = 'flat'
+            data['draw']['shading']['slice']['value'] = mode
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnVolumeResolution(self, event):
+        """!Set isosurface/slice draw resolution"""
+        self.SetVolumeResolution(event.GetInt())
+        
+    def SetVolumeResolution(self, res):
+        """!Set isosurface draw resolution"""
+        data = self.GetLayerData('volume')['volume']
+        id = data['object']['id']
+        
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            self._display.SetIsosurfaceRes(id, res)
+            data['draw']['resolution']['isosurface']['value'] = res
+        else:
+            self._display.SetSliceRes(id, res)
+            data['draw']['resolution']['slice']['value'] = res
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+    
+    def OnInOutMode(self, event):
+        """!Change isosurfaces mode inout"""
+        data = self.GetLayerData('volume')['volume']
+        id = data['object']['id']
+        isosurfId = self.FindWindowById(self.win['volume']['isosurfs']).GetSelection()
+        
+        ret = self._display.SetIsosurfaceInOut(id, isosurfId, event.GetInt())
+        if ret == 1:
+            data['isosurface'][isosurfId]['inout'] = event.GetInt()
+            
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+    
+        
+    def OnVolumeIsosurfMap(self, event):
+        """!Set surface attribute"""
+        if self.vetoGSelectEvt:
+            self.vetoGSelectEvt = False
+            return
+        self.SetMapObjAttrb(nvizType = 'volume', winId = event.GetId())
+        
+    def OnVolumeCheck(self, event):
+        """!Isosurface/slice checked (->load) or unchecked (->unload)"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+        index = event.GetSelection()
+        list = self.FindWindowById(self.win['volume'][mode + 's'])
+        
+        data = self.GetLayerData('volume')['volume']
+        vid = data['object']['id']
+        
+        id = event.GetSelection()
+        
+        if mode == 'isosurf':
+            if list.IsChecked(index):
+                if 'transp' in data['isosurface'][id] and\
+                    data['isosurface'][id]['transp']['map'] is not None:
+                    if data['isosurface'][id]['transp']['map']:
+                        map = True
+                        value = data['isosurface'][id]['transp']['value']
+                    elif data['isosurface'][id]['transp']['map'] is not None:
+                        map = False
+                        value = data['isosurface'][id]['transp']['value']
+                    self._display.SetIsosurfaceTransp(vid, id, map, value)
+                else:
+                    self._display.SetIsosurfaceTransp(vid, id, False, "0")
+            else:
+                # disable -> make transparent
+                self._display.SetIsosurfaceTransp(vid, id, False, "255")
+        else:
+            if list.IsChecked(index):
+                value = data['slice'][id]['transp']['value']
+                self._display.SetSliceTransp(vid, id, value)
+            else:
+                # disable -> make transparent
+                self._display.SetSliceTransp(vid, id, 255)
+                
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnVolumeSelect(self, event):
+        """!Isosurface/Slice item selected"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+            
+        winUp = self.FindWindowById(self.win['volume']['btnMoveUp'])
+        winDown = self.FindWindowById(self.win['volume']['btnMoveDown'])
+        selection = event.GetSelection()
+        if selection == -1:
+            return
+        elif selection == 0:
+            winUp.Enable(False)
+            if not winDown.IsEnabled():
+                winDown.Enable()
+        elif selection == self.FindWindowById(event.GetId()).GetCount() - 1:
+            winDown.Enable(False)
+            if not winUp.IsEnabled():
+                winUp.Enable()
+        else:
+            if not winDown.IsEnabled():
+                winDown.Enable()
+            if not winUp.IsEnabled():
+                winUp.Enable()
+        
+        # update dialog
+        name = self.FindWindowById(self.win['volume']['map']).GetValue()
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        
+        if mode == 'isosurf':
+            data = self.GetLayerData('volume')['volume']['isosurface'][selection]
+            self.UpdateVolumeIsosurfPage(data)
+        else:
+            data = self.GetLayerData('volume')['volume']['slice'][selection]
+            self.UpdateVolumeSlicePage(data)
+        
+        
+        
+    def OnVolumeAdd(self, event):
+        """!Add new isosurface/slice to the list"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+        list = self.FindWindowById(self.win['volume'][mode + 's'])
+        
+        name = self.FindWindowById(self.win['volume']['map']).GetValue()
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        data = self.GetLayerData('volume')['volume']
+        id = data['object']['id']
+        
+        sel = list.GetSelection()
+        if mode == 'isosurf':
+            isosurfData = self.mapWindow.nvizDefault.SetIsosurfaceDefaultProp()
+            if isosurfData['color']['map']:
+                isosurfData['color']['value'] = layer.name
+
+            level = isosurfData['topo']['value'] = round(self._get3dRange(name = layer.name)[0], 2)
+        
+            if sel < 0 or sel >= list.GetCount() - 1:
+                item = list.Append(item = "%s %s" % (_("Level"), str(level)))
+            else:
+                list.Insert(item = "%s %s" % (_("Level"), str(level)),
+                            pos = sel+1) # append
+                item = sel + 1
+        else:
+            sliceData = self.mapWindow.nvizDefault.SetSliceDefaultProp()
+            axis = ("X", "Y", "Z")[sliceData['position']['axis']]
+            if sel < 0 or sel >= list.GetCount() - 1:
+                item = list.Append(item = "%s %s" % (_("Slice parallel to"), axis))
+            else:
+                list.Insert(item = "%s" % (_("Slice parallel to"), axis),
+                            pos = sel+1) # append
+                item = sel + 1
+        
+        list.Check(item)
+        list.SetSelection(item)
+        
+        if mode == 'isosurf':
+            data['isosurface'].insert(item, isosurfData)
+            # add isosurface        
+            self._display.AddIsosurface(id, float(level))
+        else:
+            data['slice'].insert(item, sliceData)
+            # add isosurface        
+            nslice = self._display.AddSlice(id)
+            self._display.SetSlicePosition(id, nslice -1, sliceData['position']['x1'], sliceData['position']['x2'],
+                                               sliceData['position']['y1'], sliceData['position']['y2'],
+                                               sliceData['position']['z1'], sliceData['position']['z2'],
+                                               sliceData['position']['axis'])
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        # update buttons
+        self.UpdateIsosurfButtons(list)
+        if mode == 'isosurf':
+            self.UpdateVolumeIsosurfPage(isosurfData)
+        else:
+            self.UpdateVolumeSlicePage(sliceData)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+        
+    def OnVolumeDelete(self, event):
+        """!Remove isosurface/slice from list"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+        list = self.FindWindowById(self.win['volume'][mode + 's'])
+        
+        # remove item from list
+        id = list.GetSelection()
+        list.Delete(id)
+        # select last item
+        if list.GetCount() > 0:
+            list.SetSelection(list.GetCount()-1)
+        
+        name = self.FindWindowById(self.win['volume']['map']).GetValue()
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        data = self.GetLayerData('volume')['volume']
+
+        vid = data['object']['id']
+        
+        # delete isosurface
+        if mode == 'isosurf':
+            del data['isosurface'][id]
+            self._display.DeleteIsosurface(vid, id)
+        else:
+            del data['slice'][id]
+            self._display.DeleteSlice(vid, id)
+        
+        # update buttons
+        if list.GetCount() > 0:
+            if mode == 'isosurf':
+                self.UpdateVolumeIsosurfPage(data['isosurface'][list.GetSelection()])
+            else:
+                self.UpdateVolumeSlicePage(data['slice'][list.GetSelection()])
+        else:
+            if mode == 'isosurf':
+                self.UpdateVolumeIsosurfPage(data['attribute'])
+            else:
+                self.UpdateVolumeSlicePage(None)
+        self.UpdateIsosurfButtons(list)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+        
+    def OnVolumeMoveUp(self, event):
+        """!Move isosurface/slice up in the list"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+        list = self.FindWindowById(self.win['volume'][mode + 's'])
+        sel = list.GetSelection()
+        
+        if sel < 1:
+            return # this should not happen
+        
+        name = self.FindWindowById(self.win['volume']['map']).GetValue()
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        data = self.GetLayerData('volume')['volume']
+        
+        id = data['object']['id']
+        
+        # move item up
+        text = list.GetStringSelection()
+        list.Insert(item = text, pos = sel-1)
+        list.Check(sel-1)
+        list.SetSelection(sel-1)
+        list.Delete(sel+1)
+        if mode == 'isosurf':
+            data['isosurface'].insert(sel-1, data['isosurface'][sel])
+            del data['isosurface'][sel+1]
+            self._display.MoveIsosurface(id, sel, True)
+        else:
+            data['slice'].insert(sel-1, data['slice'][sel])
+            del data['slice'][sel+1]
+            self._display.MoveSlice(id, sel, True)
+        
+        # update buttons
+        self.UpdateIsosurfButtons(list)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+        
+    def OnVolumeMoveDown(self, event):
+        """!Move isosurface/slice down in the list"""
+        if self.FindWindowById(self.win['volume']['draw']['mode']).GetSelection() == 0:
+            mode = 'isosurf'
+        else:
+            mode = 'slice'
+        list = self.FindWindowById(self.win['volume'][mode + 's'])
+        sel = list.GetSelection()
+        
+        if sel >= list.GetCount() - 1:
+            return # this should not happen
+        
+        name = self.FindWindowById(self.win['volume']['map']).GetValue()
+        layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+        data = self.GetLayerData('volume')['volume']
+        
+        id = data['object']['id']
+        
+        # move item up
+        text = list.GetStringSelection()
+        list.Insert(item = text, pos = sel+2)
+        list.Check(sel+2)
+        list.SetSelection(sel+2)
+        list.Delete(sel)
+        if mode == 'isosurf':
+            data['isosurface'].insert(sel+2, data['isosurface'][sel])
+            del data['isosurface'][sel]
+            self._display.MoveIsosurface(id, sel, False)
+        else:
+            data['slice'].insert(sel+2, data['slice'][sel])
+            del data['slice'][sel]
+            self._display.MoveSlice(id, sel, False)
+        
+        # update buttons
+        self.UpdateIsosurfButtons(list)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+        event.Skip()
+    
+    def OnVolumePositionChanged(self, event):
+        """!Volume position changed"""
+        self.mapWindow.render['quick'] = False
+        self.mapWindow.Refresh(False)
+        
+    def OnVolumePosition(self, event):
+        """!Volume position"""
+        winName = self.__GetWindowName(self.win['volume'], event.GetId())
+        if not winName:
+            return
+        axis = self.FindWindowById(self.win['volume']['position']['axis']).GetSelection()
+        
+        value = self.FindWindowById(event.GetId()).GetValue()
+        slider = self.FindWindowById(self.win['volume'][winName]['slider'])
+        self.AdjustSliderRange(slider = slider, value = value)
+        
+        for win in self.win['volume']['position'].itervalues():
+            if win in (self.win['volume']['position']['axis'],
+                       self.win['volume']['position']['reset']):
+                continue
+            else:
+                self.FindWindowById(win).SetValue(value)
+        
+        data = self.GetLayerData('volume')
+        id = data['volume']['object']['id']
+        x, y, z = self._display.GetVolumePosition(id)
+        
+        if axis == 0: # x
+            x = value
+        elif axis == 1: # y
+            y = value
+        else: # z
+            z = value
+        
+        data['volume']['position']['x'] = x
+        data['volume']['position']['y'] = y
+        data['volume']['position']['z'] = z
+        data['volume']['position']['update'] = None
+        # update properties
+        
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        self.mapWindow.render['quick'] = True
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnVolumeAxis(self, event):
+        """!Volume position, axis changed"""
+        data = self.GetLayerData('volume')
+        id = data['volume']['object']['id']
+        
+        axis = self.FindWindowById(self.win['volume']['position']['axis']).GetSelection()
+        slider = self.FindWindowById(self.win['volume']['position']['slider'])
+        text = self.FindWindowById(self.win['volume']['position']['text'])
+        xydim = self._display.GetLongDim()
+        zdim = self._display.GetZRange()
+        zdim = zdim[1] - zdim[0]
+        x, y, z = self._display.GetVolumePosition(id)
+        
+        if axis == 0: # x
+            slider.SetRange(-3 * xydim, 3 * xydim)
+            slider.SetValue(x)
+            text.SetValue(x)
+        elif axis == 1: # y
+            slider.SetRange(-3 * xydim, 3 * xydim)
+            slider.SetValue(y)
+            text.SetValue(y)
+        else: # z
+            slider.SetRange(-3 * zdim, 3 * zdim)
+            slider.SetValue(z)
+            text.SetValue(z)
+            
+    def OnVolumePositionText(self, event):
+        """!Volume position changed by textctrl"""
+        self.OnVolumePosition(event)
+        self.OnVolumePositionChanged(None)
+        
+    def OnResetVolumePosition(self, event):
+        """!Reset position of volume"""
+        for win in self.win['volume']['position'].itervalues():
+            if win == self.win['volume']['position']['axis']:
+                self.FindWindowById(win).SetSelection(0)
+            elif win == self.win['volume']['position']['reset']:
+                continue
+            else:
+                self.FindWindowById(win).SetValue(0)
+                
+        data = self.GetLayerData('volume')
+        data['volume']['position']['x'] = 0
+        data['volume']['position']['y'] = 0
+        data['volume']['position']['z'] = 0
+        data['volume']['position']['update'] = None
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnVolumeSliceAxes(self, event):
+        """!Slice axis changed"""
+        self.UpdateSliceLabels()
+        data = self.GetLayerData('volume')
+        list = self.FindWindowById(self.win['volume']['slices'])
+        sel = list.GetSelection()
+        if sel < 0:
+            return
+        axis = self.FindWindowById(self.win['volume']['slice']['axes']).GetSelection()
+        data['volume']['slice'][sel]['position']['axis'] = axis
+        data['volume']['slice'][sel]['position']['update'] = None
+        
+        axis = ("X", "Y", "Z")[axis]
+        list.SetString(sel, "%s %s" % (_("Slice parallel to"), axis))
+        list.Check(sel)
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event) 
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+    
+    def OnSliceTransparency(self, event):
+        """!Slice transparency changed"""
+        data = self.GetLayerData('volume')
+        
+        list = self.FindWindowById(self.win['volume']['slices'])
+        sel = list.GetSelection()
+        if sel < 0:
+            return
+        
+        val = self.FindWindowById(self.win['volume']['slice']['transp']).GetValue()
+        data['volume']['slice'][sel]['transp']['value'] = self._getPercent(val, toPercent = False)
+        data['volume']['slice'][sel]['transp']['update'] = None
+        
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnSliceReset(self, event):
+        """!Slice position reset"""
+        data = self.GetLayerData('volume')
+        
+        list = self.FindWindowById(self.win['volume']['slices'])
+        sel = list.GetSelection()
+        if sel < 0:
+            return
+        
+        for coord, val in zip(('x1', 'x2', 'y1', 'y2', 'z1', 'z2'),(0, 1, 0, 1, 0, 1, 0)):
+            data['volume']['slice'][sel]['position'][coord] = val
+        data['volume']['slice'][sel]['position']['update'] = None
+        
+        self.UpdateVolumeSlicePage(data['volume']['slice'][sel])
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        
+    def OnSlicePositionChange(self, event):
+        """!Slice position is changing"""
+        data = self.GetLayerData('volume')
+        list = self.FindWindowById(self.win['volume']['slices'])
+        sel = list.GetSelection()
+        if sel < 0:
+            return
+        win = self.win['volume']['slice']
+        winId = event.GetId()
+        value = event.GetInt()/100.
+        
+        for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
+            if win['slider_' + coord] == winId:
+                data['volume']['slice'][sel]['position'][coord] = value
+                data['volume']['slice'][sel]['position']['update'] = None
+                break
+        self.mapWindow.render['quick'] = True
+        # update properties
+        event = wxUpdateProperties(data = data)
+        wx.PostEvent(self.mapWindow, event) 
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+               
+    def OnSlicePositionChanged(self, event):
+        """!Slice position is changed"""
+        self.mapWindow.render['quick'] = False
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+                
+    def OnCPlaneSelection(self, event):
+        """!Cutting plane selected"""
+        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
+        try:
+            planeIndex = int(plane.split()[-1]) - 1
+            self.EnablePage("cplane", enabled = True)
+        except:
+            planeIndex = -1
+            self.EnablePage("cplane", enabled = False)
+        self.mapWindow.SelectCPlane(planeIndex)
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+        self.UpdateCPlanePage(planeIndex)
+        
+    def OnCPlaneChanging(self, event):
+        """!Cutting plane is changing"""
+        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
+        try:
+            planeIndex = int(plane.split()[-1]) - 1
+        except:#TODO disabled page
+            planeIndex = -1
+    
+        if event.GetId() in (self.win['cplane']['rotation']['rot'].values() +
+                            self.win['cplane']['rotation']['tilt'].values()):
+            action = 'rotation'
+        else:
+            action = 'position'
+        data = self.mapWindow.cplanes[planeIndex][action]
+        self.OnScroll(event, self.win['cplane'][action], data)
+        
+        self.mapWindow.render['quick'] = True
+        event = wxUpdateCPlane(update = (action,), current = planeIndex)
+        wx.PostEvent(self.mapWindow, event)
+        
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+
+    def OnCPlaneChangeDone(self, event):
+        """!Cutting plane change done"""
+        self.mapWindow.render['quick'] = False
+        if self.mapDisplay.IsAutoRendered():
+            self.mapWindow.Refresh(False)
+            
+    def OnCPlaneChangeText(self, event):
+        """!Cutting plane changed by textctrl"""
+        for axis in ('x', 'y', 'z'):
+            if event.GetId() == self.win['cplane']['position'][axis]['text']:
+                value = self.FindWindowById(event.GetId()).GetValue()
+                slider = self.FindWindowById(self.win['cplane']['position'][axis]['slider'])
+                self.AdjustSliderRange(slider = slider, value = value)
+        self.OnCPlaneChanging(event = event)
+        self.OnCPlaneChangeDone(None)   
+        
+    def OnCPlaneShading(self, event):
+        """!Cutting plane shading changed"""
+        shading = self.FindWindowById(self.win['cplane']['shading']).GetSelection()
+        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
+        try:
+            planeIndex = int(plane.split()[-1]) - 1
+        except:#TODO disabled page
+            planeIndex = -1
+            
+        self.mapWindow.cplanes[planeIndex]['shading'] = shading
+        
+        event = wxUpdateCPlane(update = ('shading',), current = planeIndex)
+        wx.PostEvent(self.mapWindow, event)
+        
+        self.OnCPlaneChangeDone(None)
+        
+    def OnCPlaneReset(self, event):
+        """!Reset current cutting plane"""
+        plane = self.FindWindowById(self.win['cplane']['planes']).GetStringSelection()
+        try:
+            planeIndex = int(plane.split()[-1]) - 1
+        except:#TODO disabled page
+            planeIndex = -1
+        self.mapWindow.cplanes[planeIndex] = copy.deepcopy(UserSettings.Get(group = 'nviz',
+                                                                            key = 'cplane'))
+        event = wxUpdateCPlane(update = ('position','rotation','shading'), current = planeIndex)
+        wx.PostEvent(self.mapWindow, event)
+        self.OnCPlaneChangeDone(None)
+        self.UpdateCPlanePage(planeIndex)
+    
+    def OnDecorationPlacement(self, event):
+        """!Place an arrow/scalebar by clicking on display"""
+        if event.GetId() == self.win['decoration']['arrow']['place']:
+            type = 'arrow'
+        elif event.GetId() == self.win['decoration']['scalebar']['place']:
+            type = 'scalebar'
+        else: return
+        
+        if event.GetInt():
+            self.mapDisplay.Raise()
+            self.mapWindow.mouse['use'] = type
+            self.mapWindow.SetCursor(self.mapWindow.cursors["cross"])
+        else:
+            self.mapWindow.mouse['use'] = 'default'
+            self.mapWindow.SetCursor(self.mapWindow.cursors["default"])
+    
+    def OnArrowDelete(self, event):
+        """!Delete arrow"""
+        self._display.DeleteArrow()
+        self.mapWindow.decoration['arrow']['show'] = False
+        self.mapWindow.Refresh(False)
+    
+    def OnScalebarDelete(self, event):
+        """!Delete scalebar"""
+        try:
+            id = self.mapWindow.decoration['scalebar'][-1]['id']
+        except IndexError:
+            return
+        self._display.DeleteScalebar(id = id)
+        del self.mapWindow.decoration['scalebar'][-1]
+        
+        self.mapWindow.Refresh(False)   
+         
+    def OnDecorationProp(self, event):
+        """!Set arrow/scalebar properties"""
+        if event.GetId() in self.win['decoration']['arrow'].values():
+            type = 'arrow'
+        elif event.GetId() in self.win['decoration']['scalebar'].values():
+            type = 'scalebar'
+        else: return
+        
+        color = self.FindWindowById(self.win['decoration'][type]['color']).GetValue()
+        size = self.FindWindowById(self.win['decoration'][type]['size']).GetValue()
+        if type == 'arrow':
+            self.mapWindow.decoration[type]['color'] = self._getColorString(color)
+            self.mapWindow.decoration[type]['size'] = size
+        elif type == 'scalebar'and self.mapWindow.decoration['scalebar']:
+            self.mapWindow.decoration[type][-1]['color'] = self._getColorString(color)
+            self.mapWindow.decoration[type][-1]['size'] = size
+        
+        if type == 'arrow' and self.mapWindow.decoration['arrow']['show']:
+            self._display.SetArrow(self.mapWindow.decoration['arrow']['position']['x'],
+                                   self.mapWindow.decoration['arrow']['position']['y'],
+                                   self.mapWindow.decoration['arrow']['size'],
+                                   self.mapWindow.decoration['arrow']['color'])
+            self._display.DrawArrow()
+        elif type == 'scalebar' and self.mapWindow.decoration['scalebar']:
+            self._display.SetScalebar(self.mapWindow.decoration['scalebar'][-1]['id'],
+                                      self.mapWindow.decoration['scalebar'][-1]['position']['x'],
+                                      self.mapWindow.decoration['scalebar'][-1]['position']['y'],
+                                      self.mapWindow.decoration['scalebar'][-1]['size'],
+                                      self.mapWindow.decoration['scalebar'][-1]['color'])
+            self._display.DrawScalebar()
+            self.mapWindow.Refresh(False)
+        
+    def UpdatePage(self, pageId):
+        """!Update dialog (selected page)"""
+        self.pageChanging = True
+        Debug.msg(1, "NvizToolWindow.UpdatePage(): %s", pageId)
+        
+        if pageId == 'view':
+            self.SetPage('view')
+            hmin = self.mapWindow.iview['height']['min']
+            hmax = self.mapWindow.iview['height']['max']
+            hval = self.mapWindow.iview['height']['value']
+            zmin = self.mapWindow.view['z-exag']['min']
+            zmax = self.mapWindow.view['z-exag']['max']
+            zval = self.mapWindow.view['z-exag']['value']
+            
+            for control in ('slider','text'):
+                self.FindWindowById(self.win['view']['height'][control]).SetRange(
+                                                                        hmin,hmax)
+                self.FindWindowById(self.win['view']['z-exag'][control]).SetRange(
+                                                                        zmin, zmax) 
+                self.FindWindowById(self.win['view']['height'][control]).SetValue(hval)                                      
+                
+                self.FindWindowById(self.win['view']['z-exag'][control]).SetValue(zval)                                      
+        
+            self.FindWindowById(self.win['view']['background']['color']).SetColour(\
+                            self.mapWindow.view['background']['color'])
+                            
+            tval = self.mapWindow.view['twist']['value']
+            pval = self.mapWindow.view['persp']['value']
+            for control in ('slider','text'):
+                self.FindWindowById(self.win['view']['twist'][control]).SetValue(tval)                                      
+                
+                self.FindWindowById(self.win['view']['persp'][control]).SetValue(pval)
+            
+            
+        elif pageId in ('surface', 'vector', 'volume'):
+            name = self.FindWindowById(self.win[pageId]['map']).GetValue()
+            data = self.GetLayerData(pageId)
+            if data:
+                if pageId == 'surface':
+                    layer = self.mapWindow.GetLayerByName(name, mapType = 'raster')
+                    self.UpdateSurfacePage(layer, data['surface'])
+                elif pageId == 'vector':
+                    layer = self.mapWindow.GetLayerByName(name, mapType = 'vector')
+                    self.UpdateVectorPage(layer, data['vector'])
+                elif pageId == 'volume':
+                    layer = self.mapWindow.GetLayerByName(name, mapType = '3d-raster')
+                    self.UpdateVolumePage(layer, data['volume'])
+        elif pageId == 'light':
+            zval = self.mapWindow.light['position']['z']
+            bval = self.mapWindow.light['bright']
+            aval = self.mapWindow.light['ambient']
+            for control in ('slider','text'):
+                self.FindWindowById(self.win['light']['z'][control]).SetValue(zval)
+                self.FindWindowById(self.win['light']['bright'][control]).SetValue(bval)
+                self.FindWindowById(self.win['light']['ambient'][control]).SetValue(aval)
+            self.FindWindowById(self.win['light']['color']).SetColour(self.mapWindow.light['color'])
+            self.FindWindowById(self.win['light']['position']).PostDraw()
+        elif pageId == 'fringe':
+            win = self.FindWindowById(self.win['fringe']['map'])
+            win.SetValue(self.FindWindowById(self.win['surface']['map']).GetValue())
+        elif pageId == 'decoration':
+            win = self.FindWindowById(self.win['decoration']['arrow']['size'])
+            win.SetValue(self.mapWindow.decoration['arrow']['size'])
+            win = self.FindWindowById(self.win['decoration']['scalebar']['size'])
+            win.SetValue(self.mapWindow._getDecorationSize())
+        elif pageId == 'constant':
+            if self.mapWindow.constants:
+                surface = self.FindWindowById(self.win['constant']['surface'])
+                for item in self.mapWindow.constants:
+                    surface.Append(_("constant#") + str(item['constant']['object']['name']))
+                surface.SetSelection(0)
+                self.OnConstantSelection(None)
+                self.EnablePage('constant', True)
+        elif pageId == 'cplane':
+            count = self._display.GetCPlanesCount()
+            choices = [_("None"),]
+            for plane in range(count):
+                choices.append("%s %i" % (_("Plane"), plane+1))
+            self.FindWindowById(self.win['cplane']['planes']).SetItems(choices)
+            current = 0
+            for i, cplane in enumerate(self.mapWindow.cplanes):
+                if cplane['on']:
+                    current = i + 1
+            self.FindWindowById(self.win['cplane']['planes']).SetSelection(current)
+            
+            xyRange, zRange = self._display.GetXYRange(), self._display.GetZRange()
+            if xyRange > 0: # GTK warning
+                self.FindWindowById(self.win['cplane']['position']['x']['slider']).SetRange(
+                                                                    -xyRange/2., xyRange/2.)
+                self.FindWindowById(self.win['cplane']['position']['y']['slider']).SetRange(
+                                                                    -xyRange/2., xyRange/2.)
+            if zRange[0] - zRange[1] > 0:
+                self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetRange(zRange[0], zRange[1])
+            self.FindWindowById(self.win['cplane']['position']['z']['slider']).SetValue(zRange[0])
+            self.FindWindowById(self.win['cplane']['position']['z']['text']).SetValue(zRange[0])
+            self.OnCPlaneSelection(None)
+            
+        elif pageId == 'animation':
+            self.UpdateAnimationPage()
+            
+        self.Update()
+        self.pageChanging = False
+        
+    def UpdateAnimationPage(self):
+        """!Update animation page"""
+        # wrap help text according to tool window
+        help = self.FindWindowById(self.win['anim']['help'])
+        width = help.GetGrandParent().GetSizeTuple()[0]
+        help.Wrap(width - 15)
+        anim = self.mapWindow.GetAnimation()
+        if anim.Exists():
+            self.FindWindowById(self.win['anim']['play']).Enable()
+        else:
+            self.UpdateFrameIndex(index = 0)
+            
+        self.UpdateFrameCount()
+        
+        self.FindWindowById(self.win['anim']['play']).Disable()
+        self.FindWindowById(self.win['anim']['record']).Enable()
+        self.FindWindowById(self.win['anim']['pause']).Disable()
+        self.FindWindowById(self.win['anim']['stop']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['slider']).Disable()
+        self.FindWindowById(self.win['anim']['frameIndex']['text']).Disable()
+        
+    def UpdateCPlanePage(self, index):
+        """!Update widgets according to selected clip plane"""
+        if index == -1:   
+            return
+        data = self.mapWindow.cplanes[index]
+        for widget in ('text', 'slider'):
+            for axes in ('x', 'y', 'z'):
+                self.FindWindowById(self.win['cplane']['position'][axes][widget]).SetValue(data['position'][axes])
+            for each in ('tilt', 'rot'):
+                self.FindWindowById(self.win['cplane']['rotation'][each][widget]).SetValue(data['rotation'][each])
+        self.FindWindowById(self.win['cplane']['shading']).SetSelection(data['shading'])
+                
+    def UpdateSurfacePage(self, layer, data, updateName = True):
+        """!Update surface page"""
+        desc = grass.raster_info(layer.name)['title']
+        if updateName:
+            self.FindWindowById(self.win['surface']['map']).SetValue(layer.name)
+        self.FindWindowById(self.win['surface']['desc']).SetLabel(desc)
+        
+        # attributes
+        if layer and layer.type == 'raster':
+            self.vetoGSelectEvt = True
+            self.FindWindowById(self.win['surface']['color']['map']).SetValue(layer.name)
+        else:
+            self.FindWindowById(self.win['surface']['color']['map']).SetValue('')
+
+        self.SetMapObjUseMap(nvizType = 'surface',
+                             attrb = 'color', map = True) # -> map
+                                
+        if 'color' in data['attribute']:
+            value = data['attribute']['color']['value']
+
+            if data['attribute']['color']['map']:
+                self.FindWindowById(self.win['surface']['color']['map']).SetValue(value)
+            else: # constant
+                color = map(int, value.split(':'))
+                self.FindWindowById(self.win['surface']['color']['const']).SetColour(color)
+            self.SetMapObjUseMap(nvizType = 'surface',
+                                 attrb = 'color', map = data['attribute']['color']['map'])
+
+        self.SetMapObjUseMap(nvizType = 'surface',
+                             attrb = 'shine', map = data['attribute']['shine']['map'])
+        value = data['attribute']['shine']['value']
+        if data['attribute']['shine']['map']:
+            self.FindWindowById(self.win['surface']['shine']['map']).SetValue(value)
+        else:
+            self.FindWindowById(self.win['surface']['shine']['const']).SetValue(self._getPercent(value))
+        if 'transp' in data['attribute']:  
+            value = data['attribute']['transp']['value']  
+            if data['attribute']['transp']['map']:
+                self.FindWindowById(self.win['surface']['color']['map']).SetValue(value)
+            else:
+                self.FindWindowById(self.win['surface']['transp']['const']).SetValue(self._getPercent(value))
+            self.SetMapObjUseMap(nvizType = 'surface', attrb = 'transp', map = data['attribute']['transp']['map'])
+        else:
+            self.SetMapObjUseMap(nvizType = 'surface', attrb = 'transp', map = None)
+        #
+        # draw
+        #
+        for control, drawData in data['draw'].iteritems():
+            if control == 'all': # skip 'all' property
+                continue
+            if control == 'resolution':
+                self.FindWindowById(self.win['surface']['draw']['res-coarse']).SetValue(drawData['coarse'])
+                self.FindWindowById(self.win['surface']['draw']['res-fine']).SetValue(drawData['fine'])
+                continue
+            
+            if control == 'mode':
+                if drawData['desc']['mode'] == 'coarse':
+                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(0)
+                elif drawData['desc']['mode'] == 'fine':
+                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(1)
+                else: # both
+                    self.FindWindowById(self.win['surface']['draw']['mode']).SetSelection(2)
+                
+                if drawData['desc']['style'] == 'wire':
+                    self.FindWindowById(self.win['surface']['draw']['style']).SetSelection(0)
+                else: # surface
+                    self.FindWindowById(self.win['surface']['draw']['style']).SetSelection(1)
+                
+                if drawData['desc']['shading'] == 'flat':
+                    self.FindWindowById(self.win['surface']['draw']['shading']).SetSelection(0)
+                else: # gouraud
+                    self.FindWindowById(self.win['surface']['draw']['shading']).SetSelection(1)
+                
+                continue
+            
+            value = drawData['value']
+            win = self.FindWindowById(self.win['surface']['draw'][control])
+            
+            name = win.GetName()
+            
+            if name == "selection":
+                win.SetSelection(value)
+            elif name == "colour":
+                color = map(int, value.split(':'))
+                win.SetColour(color)
+            else:
+                win.SetValue(value)
+        #
+        # position
+        #
+        dim = self._display.GetLongDim()
+        self.FindWindowById(self.win['surface']['position']['slider']).SetRange(-2 * dim, 2 * dim)
+        if 'x' in data['position']:
+            xval = data['position']['x']
+            self.FindWindowById(self.win['surface']['position']['axis']).SetSelection(0)
+            for control in ('slider','text'):
+                    self.FindWindowById(self.win['surface']['position'][control]).SetValue(xval)
+        # enable/disable res widget + set draw mode
+        self.OnSurfaceMode(event = None)
+
+    def VectorInfo(self, layer):
+        """!Get number of points/lines
+        
+        @param layer MapLayer instance
+        
+        @return num of points/features (expect of points)
+        @return None
+        """
+        vInfo = grass.vector_info_topo(layer.GetName())
+        
+        if not vInfo:
+            return None
+        
+        nprimitives = 0
+        for key, value in vInfo.iteritems():
+            if key in ('points',
+                       'lines',
+                       'boundaries',
+                       'centroids',
+                       'faces',
+                       'kernels'):
+                nprimitives += value
+        
+        return (vInfo['points'], vInfo['lines'], nprimitives, vInfo['map3d'])
+        
+    def UpdateVectorPage(self, layer, data, updateName = True):
+        """!Update vector page"""
+        npoints, nlines, nfeatures, mapIs3D = self.VectorInfo(layer)
+        if mapIs3D:
+            desc = _("Vector map is 3D")
+            enable = False
+        else:
+            desc = _("Vector map is 2D")
+            enable = True
+        desc += " - " + _("%(features)d features (%(points)d points)") % \
+            { 'features' : nfeatures, 'points' : npoints }
+        
+        if updateName:
+            self.FindWindowById(self.win['vector']['map']).SetValue(layer.name)
+        self.FindWindowById(self.win['vector']['desc']).SetLabel(desc)
+        
+        self.FindWindowById(self.win['vector']['lines']['flat']).Enable(enable)
+        for v in ('lines', 'points'):
+            self.FindWindowById(self.win['vector'][v]['surface']).Enable(enable)
+            self.FindWindowById(self.win['vector'][v]['height']['slider']).Enable(enable)
+            self.FindWindowById(self.win['vector'][v]['height']['text']).Enable(enable)
+            
+            if data[v]['thematic']['usecolor']:
+                check = self.FindWindowById(self.win['vector'][v]['thematic']['checkcolor'])
+                check.SetValue(data[v]['thematic']['usecolor'])
+            if 'usesize' in data[v]['thematic'] and data[v]['thematic']['usesize']:
+                check = self.FindWindowById(self.win['vector'][v]['thematic']['checksize'])
+                check.SetValue(data[v]['thematic']['usesize'])
+            elif 'usewidth' in data[v]['thematic'] and data[v]['thematic']['usewidth']:
+                check = self.FindWindowById(self.win['vector'][v]['thematic']['checkwidth'])
+                check.SetValue(data[v]['thematic']['usewidth'])
+            self.OnCheckThematic(None)
+        #
+        # lines
+        #
+        showLines = self.FindWindowById(self.win['vector']['lines']['show'])
+        if 'object' in data['lines']:
+            showLines.SetValue(True)
+        else:
+            showLines.SetValue(False)
+            if nlines > 0:
+                showLines.Enable(True)
+            else:
+                showLines.Enable(False)
+        
+        self.UpdateVectorShow('lines',
+                              showLines.IsChecked())
+        
+        width = self.FindWindowById(self.win['vector']['lines']['width'])
+        width.SetValue(data['lines']['width']['value'])
+        
+        color = self.FindWindowById(self.win['vector']['lines']['color'])
+        color.SetValue(map(int, data['lines']['color']['value'].split(':')))
+        
+        for vtype in ('lines', 'points'):
+            if vtype == 'lines':
+                display = self.FindWindowById(self.win['vector']['lines']['flat'])
+                if data[vtype]['mode']['type'] == 'flat':
+                    display.SetSelection(1)
+                else:
+                    display.SetSelection(0)
+            if data[vtype]['mode']['type'] == 'surface':
+                rasters = self.mapWindow.GetLayerNames('raster')
+                constants = self.mapWindow.GetLayerNames('constant')
+                surfaces = rasters + constants
+                surfaceWin = self.FindWindowById(self.win['vector'][vtype]['surface'])
+                surfaceWin.SetItems(surfaces)
+                for idx, surface in enumerate(surfaces):
+                    try:# TODO fix this mess
+                        selected = data[vtype]['mode']['surface']['show'][idx]
+                    except (TypeError, IndexError, KeyError):
+                        selected = False
+                    surfaceWin.Check(idx, selected)
+
+        for type in ('slider', 'text'):
+            win = self.FindWindowById(self.win['vector']['lines']['height'][type])
+            win.SetValue(data['lines']['height']['value'])
+        
+        #
+        # points
+        #
+        showPoints = self.FindWindowById(self.win['vector']['points']['show'])
+        
+        if 'object' in data['points']:
+            showPoints.SetValue(True)
+        else:
+            showPoints.SetValue(False)
+            if npoints > 0:
+                showPoints.Enable(True)
+            else:
+                showPoints.Enable(False)
+        
+        self.UpdateVectorShow('points',
+                              showPoints.IsChecked())
+        # size, width, marker, color
+        for prop in ('size', 'marker', 'color'):
+            win = self.FindWindowById(self.win['vector']['points'][prop])
+            name = win.GetName()
+            if name == 'selection':
+                win.SetSelection(data['points'][prop]['value'])
+            elif name == 'color':
+                color = map(int, data['points'][prop]['value'].split(':'))
+                win.SetValue(color)
+            else:
+                win.SetValue(data['points'][prop]['value'])
+##        self.OnCheckThematic(None)
+        # height
+        for type in ('slider', 'text'):
+            win = self.FindWindowById(self.win['vector']['points']['height'][type])
+            win.SetValue(data['points']['height']['value'])
+        
+    def UpdateVolumePage(self, layer, data, updateName = True):
+        """!Update volume page"""
+        if updateName:
+            self.FindWindowById(self.win['volume']['map']).SetValue(layer.name)
+        
+        # draw
+        for control, idata in data['draw'].iteritems():
+            if control == 'all': # skip 'all' property
+                continue
+                
+            win = self.FindWindowById(self.win['volume']['draw'][control])
+            if control == 'mode':
+                value = data['draw']['mode']['value']
+            if control == 'shading':
+                if data['draw']['shading'][data['draw']['mode']['desc']]['desc'] == 'flat':
+                    value = 0
+                else:
+                    value = 1
+            if control == 'resolution':
+                value = idata[data['draw']['mode']['desc']]['value']
+            
+            if win.GetName() == "selection":
+                win.SetSelection(value)
+            else:
+                win.SetValue(value)
+                
+        self.OnVolumeMode(None)
+        id = data['object']['id']
+        if data['draw']['mode']['desc'] == 'isosurface':
+            self._display.SetIsosurfaceMode(id, data['draw']['shading']['isosurface']['value'])
+            self._display.SetIsosurfaceRes(id, data['draw']['resolution']['isosurface']['value'])
+        else:
+            self._display.SetSliceMode(id, data['draw']['shading']['slice']['value'])
+            self._display.SetSliceRes(id, data['draw']['resolution']['slice']['value'])
+        box = self.FindWindowById(self.win['volume']['isosurfs'])
+        
+        if data['draw']['mode']['desc'] == 'isosurface':
+            isosurfaces = []
+            for iso in data['isosurface']:
+                level = iso['topo']['value']
+                isosurfaces.append("%s %s" % (_("Level"), level))
+            box.Set(isosurfaces)
+            box.SetChecked(range(len(isosurfaces)))
+            if data['isosurface']:
+                box.SetSelection(0)
+                self.UpdateVolumeIsosurfPage(data['isosurface'][0])
+            else:
+                self.UpdateVolumeIsosurfPage(data['attribute'])
+        else:
+            slices = []
+            for slice in data['slice']:
+                axis = ("X", "Y", "Z")[slice['position']['axis']]
+                slices.append("%s %s" % (_("Slice parallel to"), axis))
+            box.Set(slices)
+            box.SetChecked(range(len(slices)))
+            if data['slice']:
+                box.SetSelection(0)
+                self.UpdateVolumeSlicePage(data['slice'][0])
+            else:
+                self.UpdateVolumeSlicePage(None)
+        #
+        # position
+        #
+        if 'x' in data['position']:
+            xval = data['position']['x']
+            self.FindWindowById(self.win['volume']['position']['axis']).SetSelection(0)
+            for control in ('slider','text'):
+                    self.FindWindowById(self.win['volume']['position'][control]).SetValue(xval)    
+        # set topo range
+        mapRange = self._get3dRange(name = layer.name)
+        desc = self.FindWindowById(self.win['volume']['desc'])
+        desc.SetLabel("%s %.2f - %.2f" % (_("range:"), mapRange[0], mapRange[1]))
+        
+    def UpdateVolumeIsosurfPage(self, data):
+        """!Update dialog -- isosurface attributes"""
+        #
+        # isosurface attributes
+        #
+        for attrb in ('topo', 'color', 'mask',
+                     'transp', 'shine'):
+            # skip empty attributes
+            if attrb not in data:
+                self.SetMapObjUseMap(nvizType = 'volume', attrb = attrb, map = None)
+                continue     
+            
+            value = data[attrb]['value']
+            if attrb == 'color':
+                if data[attrb]['map']:
+                    self.FindWindowById(self.win['volume'][attrb]['map']).SetValue(value)
+                else: # constant
+                    color = map(int, value.split(':'))
+                    self.FindWindowById(self.win['volume'][attrb]['const']).SetColour(color)
+            else:
+                if data[attrb]['map']:
+                    self.vetoGSelectEvt = True
+                    win = self.FindWindowById(self.win['volume'][attrb]['map'])
+                    win.SetValue(value)
+                else:
+                    if value:
+                        win = self.FindWindowById(self.win['volume'][attrb]['const'])
+                        if attrb == 'topo':
+                            win.SetValue(float(value))
+                        else:
+                            win.SetValue(self._getPercent(value))
+                    
+            self.SetMapObjUseMap(nvizType = 'volume',
+                                 attrb = attrb, map = data[attrb]['map'])
+        # set inout
+        if 'inout' in data:
+            self.FindWindowById(self.win['volume']['inout']).SetValue(data['inout'])
+            
+    def UpdateVolumeSlicePage(self, data):
+        """!Update dialog -- slice attributes"""
+        if data:
+            for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
+                win = self.FindWindowById(self.win['volume']['slice']['slider_' + coord])
+                win.Enable()
+                win.SetValue(data['position'][coord] * 100)
+            win = self.FindWindowById(self.win['volume']['slice']['axes'])
+            win.SetSelection(data['position']['axis'])
+            win.Enable()
+            
+            win = self.FindWindowById(self.win['volume']['slice']['transp'])
+            win.SetValue(self._getPercent(data['transp']['value']))
+            win.Enable()
+            self.FindWindowById(self.win['volume']['slice']['reset']).Enable()
+        else:
+            for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
+                self.FindWindowById(self.win['volume']['slice']['slider_' + coord]).Disable()
+            self.FindWindowById(self.win['volume']['slice']['axes']).Disable()
+            self.FindWindowById(self.win['volume']['slice']['transp']).Disable()
+            self.FindWindowById(self.win['volume']['slice']['reset']).Disable()
+        
+        self.UpdateSliceLabels()
+        
+    def UpdateSliceLabels(self):
+        """!Update text labels of slice controls according to axis"""
+        sel = self.FindWindowById(self.win['volume']['slice']['axes']).GetSelection()
+        if sel == 0:
+            self.FindWindowByName('label_edge_0').SetLabel(_("North edge:"))
+            self.FindWindowByName('label_edge_1').SetLabel(_("South edge:"))
+            self.FindWindowByName('label_edge_2').SetLabel(_("West edge:"))
+            self.FindWindowByName('label_edge_3').SetLabel(_("East edge:"))
+            
+            self.FindWindowByName('label_coord_0').SetLabel(_("Northing (Y):"))
+            self.FindWindowByName('label_coord_1').SetLabel(_("Height (Z):"))
+            self.FindWindowByName('label_coord_2').SetLabel(_("Easting (X):"))
+        elif sel == 1:
+            self.FindWindowByName('label_edge_0').SetLabel(_("West edge:"))
+            self.FindWindowByName('label_edge_1').SetLabel(_("East edge:"))
+            self.FindWindowByName('label_edge_2').SetLabel(_("North edge:"))
+            self.FindWindowByName('label_edge_3').SetLabel(_("South edge:"))
+            
+            self.FindWindowByName('label_coord_0').SetLabel(_("Easting (X):"))
+            self.FindWindowByName('label_coord_1').SetLabel(_("Height (Z):"))
+            self.FindWindowByName('label_coord_2').SetLabel(_("Northing (Y):"))
+        else:
+            self.FindWindowByName('label_edge_0').SetLabel(_("West edge:"))
+            self.FindWindowByName('label_edge_1').SetLabel(_("East edge:"))
+            self.FindWindowByName('label_edge_2').SetLabel(_("Bottom edge:"))
+            self.FindWindowByName('label_edge_3').SetLabel(_("Top edge:"))  
+            
+            self.FindWindowByName('label_coord_0').SetLabel(_("Easting (X):"))
+            self.FindWindowByName('label_coord_1').SetLabel(_("Northing (Y):"))
+            self.FindWindowByName('label_coord_2').SetLabel(_("Height (Z):")) 
+        
+    def SetPage(self, name):
+        """!Get named page"""
+        if name == 'view':
+            self.SetSelection(0)
+        elif name in ('surface', 'vector', 'volume'):
+            self.SetSelection(1)
+        else:
+            self.SetSelection(2)
+
+        win = self.FindWindowById(self.page[name]['notebook'])
+        try:
+            win.Expand(win.GetFoldPanel(self.page[name]['id']))
+            self.UpdateScrolling((win.GetFoldPanel(self.page[name]['id']).GetGrandParent(),))
+        except AttributeError:
+            win.SetSelection(self.page[name]['id'])
+
+class PositionWindow(wx.Window):
+    """!Abstract position control window, see subclasses
+    ViewPostionWindow and LightPositionWindow"""
+    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
+                 **kwargs):
+        self.mapWindow = mapwindow
+        self.quick = True
+        
+        wx.Window.__init__(self, parent, id, **kwargs)
+        
+        self.SetBackgroundColour("WHITE")
+        
+        self.pdc = wx.PseudoDC()
+        
+        self.pdc.SetBrush(wx.Brush(colour = 'dark green', style = wx.SOLID))
+        self.pdc.SetPen(wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID))
+
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        # self.Bind(wx.EVT_MOTION,       self.OnMouse)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
+        
+    def Draw(self, pos, scale = False):
+        w, h = self.GetClientSize()
+        x, y = pos
+        if scale:
+            x = x * w
+            y = y * h
+        self.pdc.Clear()
+        self.pdc.BeginDrawing()
+        self.pdc.DrawLine(w / 2, h / 2, x, y)
+        self.pdc.DrawCircle(x, y, 5)
+        self.pdc.EndDrawing()
+        
+    def OnPaint(self, event):
+        dc = wx.BufferedPaintDC(self)
+        dc.SetBackground(wx.Brush("White"))
+        dc.Clear()
+        
+        self.PrepareDC(dc)
+        self.pdc.DrawToDC(dc)
+        
+    def UpdatePos(self, xcoord, ycoord):
+        """!Update position coordinates (origin: UL)"""
+        if xcoord < 0.0:
+            xcoord = 0.0
+        elif xcoord > 1.0:
+            xcoord = 1.0
+        if ycoord < 0.0:
+            ycoord = 0.0
+        elif ycoord > 1.0:
+            ycoord = 1.0
+        
+        x, y = self.TransformCoordinates(xcoord, ycoord)
+        self.data['position']['x'] = x        
+        self.data['position']['y'] = y
+        
+        return xcoord, ycoord
+    
+    def OnMouse(self, event):
+        if event.LeftIsDown():
+            x, y = event.GetPosition()
+            self.Draw(pos = (x, y))
+            w, h = self.GetClientSize()
+            x = float(x) / w
+            y = float(y) / h
+            self.UpdatePos(x, y)
+            self.Refresh(False)
+        
+        event.Skip()
+        
+    def PostDraw(self):
+        x, y = self.UpdatePos(self.data['position']['x'],
+                              self.data['position']['y'])
+        
+        self.Draw(pos = (x,y), scale = True)
+
+class ViewPositionWindow(PositionWindow):
+    """!View position control widget"""
+    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
+                 **kwargs):
+        PositionWindow.__init__(self, parent, mapwindow, id, **kwargs)
+
+        self.data = self.mapWindow.view
+        self.PostDraw()
+        
+    def UpdatePos(self, xcoord, ycoord):
+        x, y = PositionWindow.UpdatePos(self, xcoord, ycoord)
+        
+        event = wxUpdateView(zExag = True)
+        wx.PostEvent(self.mapWindow, event)
+
+        return x, y
+    
+    def TransformCoordinates(self, x, y, toLight = True):
+        return x, y
+        
+    def OnMouse(self, event):
+        self.mapWindow.iview['dir']['use'] = False # use focus instead of viewdir
+        PositionWindow.OnMouse(self, event)
+        if event.LeftIsDown():
+            self.mapWindow.render['quick'] = self.quick
+            self.mapWindow.Refresh(eraseBackground = False)
+        elif event.LeftUp():
+            self.mapWindow.render['quick'] = False
+            self.mapWindow.Refresh(eraseBackground = False)
+        
+        event.Skip()
+    
+class LightPositionWindow(PositionWindow):
+    """!Light position control widget"""
+    def __init__(self, parent, mapwindow, id = wx.ID_ANY,
+                 **kwargs):
+        PositionWindow.__init__(self, parent, mapwindow, id, **kwargs)
+        
+        self.data = self.mapWindow.light
+        self.quick = False
+        self.PostDraw()
+
+    def UpdatePos(self, xcoord, ycoord):
+        x, y = PositionWindow.UpdatePos(self, xcoord, ycoord)
+        
+        event = wxUpdateLight(refresh = False)
+        wx.PostEvent(self.mapWindow, event)
+        
+        return x, y
+    
+    def TransformCoordinates(self, x, y, toLight = True):
+        if toLight:
+            x = 2 * x - 1
+            y = -2 * y + 1
+        else:
+            x = (x + 1)/2
+            y = (1 - y)/2
+        return x, y
+    
+    def PostDraw(self):
+        event = wxUpdateLight(refresh = True)
+        wx.PostEvent(self.mapWindow, event)
+        x, y = self.data['position']['x'], self.data['position']['y']
+        x, y = self.TransformCoordinates(x, y, toLight = False)
+        
+        self.Draw(pos = (x,y), scale = True)
+        
+    def OnMouse(self, event):
+        PositionWindow.OnMouse(self, event)
+        if event.LeftUp():
+            self.mapWindow.render['quick'] = False
+            self.mapWindow.Refresh(eraseBackground = False)

Added: grass/trunk/gui/wxpython/nviz/workspace.py
===================================================================
--- grass/trunk/gui/wxpython/nviz/workspace.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/workspace.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,342 @@
+"""!
+ at package nviz.settings
+
+ at brief wxNviz settings
+
+Classes:
+ - NvizSettings
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Kratochvilova <kratochanna gmail.com> (wxNviz / Google SoC 2011)
+"""
+
+import copy
+
+from core.settings import UserSettings
+
+try:
+    import nviz.wxcore as wxnviz
+except ImportError:
+    wxnviz = None
+
+class NvizSettings(object):
+    def __init__(self):
+        """Default 3D settings"""
+        UserSettings.Reset('nviz')
+        UserSettings.ReadSettingsFile()
+        
+    def SetConstantDefaultProp(self):
+        """Set default constant data properties"""
+        data = dict()
+        for key, value in UserSettings.Get(group='nviz', key='constant').iteritems():
+            data[key] = value
+        color = str(data['color'][0]) + ':' + str(data['color'][1]) + ':' + str(data['color'][2])
+        data['color'] = color
+
+        return data
+    
+    def SetSurfaceDefaultProp(self, data = None):
+        """Set default surface data properties"""
+        if not data:
+            data = dict()
+        for sec in ('attribute', 'draw', 'mask', 'position'):
+            data[sec] = {}
+        
+        #
+        # attributes
+        #
+        for attrb in ('shine', ):
+            data['attribute'][attrb] = {}
+            for key, value in UserSettings.Get(group='nviz', key='surface',
+                                               subkey=attrb).iteritems():
+                data['attribute'][attrb][key] = value
+            data['attribute'][attrb]['update'] = None
+        
+        #
+        # draw
+        #
+        data['draw']['all'] = False # apply only for current surface
+        for control, value in UserSettings.Get(group='nviz', key='surface', subkey='draw').iteritems():
+            if control[:3] == 'res':
+                if 'resolution' not in data['draw']:
+                    data['draw']['resolution'] = {}
+                if 'update' not in data['draw']['resolution']:
+                    data['draw']['resolution']['update'] = None
+                data['draw']['resolution'][control[4:]] = value
+                continue
+            
+            if control == 'wire-color':
+                value = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
+            elif control in ('mode', 'style', 'shading'):
+                if 'mode' not in data['draw']:
+                    data['draw']['mode'] = {}
+                continue
+
+            data['draw'][control] = { 'value' : value }
+            data['draw'][control]['update'] = None
+        
+        value, desc = self.GetDrawMode(UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'mode']),
+                                       UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'style']),
+                                       UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'shading']))
+    
+        data['draw']['mode'] = { 'value' : value,
+                                 'desc' : desc, 
+                                 'update': None }
+        # position
+        for coord in ('x', 'y', 'z'):
+            data['position'][coord] = UserSettings.Get(group='nviz', key='surface', subkey=['position', coord])
+        data['position']['update'] = None
+            
+        return data
+    
+    def SetVolumeDefaultProp(self):
+        """Set default volume data properties"""
+        data = dict()
+        for sec in ('attribute', 'draw', 'position'):
+            data[sec] = dict()
+            for sec in ('isosurface', 'slice'):
+                    data[sec] = list()
+        
+        #
+        # draw
+        #
+        for control, value in UserSettings.Get(group='nviz', key='volume', subkey='draw').iteritems():
+            if control == 'shading':
+                sel = UserSettings.Get(group='nviz', key='volume', subkey=['draw', 'shading'])
+                value, desc = self.GetDrawMode(shade=sel, string=False)
+                
+                data['draw']['shading'] = {}
+                data['draw']['shading']['isosurface'] = { 'value' : value,
+                                                          'desc' : desc['shading'] }
+                data['draw']['shading']['slice'] = { 'value' : value,
+                                                     'desc' : desc['shading'] }
+            elif control == 'mode':
+                sel = UserSettings.Get(group='nviz', key='volume', subkey=['draw', 'mode'])
+                if sel == 0:
+                    desc = 'isosurface'
+                else:
+                    desc = 'slice'
+                data['draw']['mode'] = { 'value' : sel,
+                                         'desc' : desc, }
+            else:
+                data['draw'][control] = {}
+                data['draw'][control]['isosurface'] = { 'value' : value }
+                data['draw'][control]['slice'] = { 'value' : value }
+
+            if 'update' not in data['draw'][control]:
+                data['draw'][control]['update'] = None
+        
+        #
+        # isosurface attributes
+        #
+        for attrb in ('shine', ):
+            data['attribute'][attrb] = {}
+            for key, value in UserSettings.Get(group='nviz', key='volume',
+                                               subkey=attrb).iteritems():
+                data['attribute'][attrb][key] = value
+        
+        return data
+    
+    def SetIsosurfaceDefaultProp(self):
+        """!Set default isosurface properties"""
+        data = dict()
+        for attr in ('shine', 'topo', 'transp', 'color'):
+            data[attr] = {}
+            for key, value in UserSettings.Get(group = 'nviz', key = 'volume',
+                                               subkey = attr).iteritems():
+                data[attr][key] = value
+            data[attr]['update'] = None
+        return data
+    
+    def SetSliceDefaultProp(self):
+        """!Set default slice properties"""
+        data = dict()
+        data['position'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'volume',
+                                               subkey = 'slice_position'))
+        data['position']['update'] = None
+        
+        data['transp'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'volume',
+                                               subkey = 'transp'))
+        return data
+    
+    def SetVectorDefaultProp(self, data = None):
+        """Set default vector data properties"""
+        if not data:
+            data = dict()
+        for sec in ('lines', 'points'):
+            data[sec] = {}
+        
+        self.SetVectorLinesDefaultProp(data['lines'])
+        self.SetVectorPointsDefaultProp(data['points'])
+
+        return data
+    
+    def SetVectorLinesDefaultProp(self, data):
+        """Set default vector properties -- lines"""
+        # width
+        data['width'] = {'value' : UserSettings.Get(group='nviz', key='vector',
+                                                    subkey=['lines', 'width']) }
+        
+        # color
+        value = UserSettings.Get(group='nviz', key='vector',
+                                 subkey=['lines', 'color'])
+        color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
+        data['color'] = { 'value' : color }
+
+        # mode
+        if UserSettings.Get(group='nviz', key='vector',
+                            subkey=['lines', 'flat']):
+            type = 'flat'
+            
+        else:
+            type = 'surface'
+            
+        data['mode'] = {}
+        data['mode']['type'] = type
+        data['mode']['update'] = None
+    
+        # height
+        data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['lines', 'height']) }
+        # thematic
+        data['thematic'] = {'rgbcolumn' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['lines', 'rgbcolumn']),
+                            'sizecolumn' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['lines', 'sizecolumn']),
+                            'layer': 1,
+                            'usecolor' : False,
+                            'usewidth' : False}
+        if 'object' in data:
+            for attrb in ('color', 'width', 'mode', 'height', 'thematic'):
+                data[attrb]['update'] = None
+        
+    def SetVectorPointsDefaultProp(self, data):
+        """Set default vector properties -- points"""
+        # size
+        data['size'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
+                                                    subkey=['points', 'size']) }
+
+        # width
+        data['width'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
+                                                     subkey=['points', 'width']) }
+
+        # marker
+        data['marker'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['points', 'marker']) }
+
+        # color
+        value = UserSettings.Get(group='nviz', key='vector',
+                                 subkey=['points', 'color'])
+        color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
+        data['color'] = { 'value' : color }
+
+        # mode
+        data['mode'] = { 'type' : 'surface'}
+##                         'surface' : '', }
+        
+        # height
+        data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['points', 'height']) }
+        
+        data['thematic'] = {'rgbcolumn' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['points', 'rgbcolumn']),
+                            'sizecolumn' : UserSettings.Get(group='nviz', key='vector',
+                                                      subkey=['points', 'sizecolumn']),
+                            'layer': 1,
+                            'usecolor' : False,
+                            'usesize' : False}
+        if 'object' in data:
+            for attrb in ('size', 'width', 'marker',
+                          'color', 'height', 'thematic'):
+                data[attrb]['update'] = None
+        
+    def GetDrawMode(self, mode=None, style=None, shade=None, string=False):
+        """Get surface draw mode (value) from description/selection
+
+        @param mode,style,shade modes
+        @param string if True input parameters are strings otherwise
+        selections
+        """
+        if not wxnviz:
+            return None
+        
+        value = 0
+        desc = {}
+
+        if string:
+            if mode is not None:
+                if mode == 'coarse':
+                    value |= wxnviz.DM_WIRE
+                elif mode == 'fine':
+                    value |= wxnviz.DM_POLY
+                else: # both
+                    value |= wxnviz.DM_WIRE_POLY
+
+            if style is not None:
+                if style == 'wire':
+                    value |= wxnviz.DM_GRID_WIRE
+                else: # surface
+                    value |= wxnviz.DM_GRID_SURF
+                    
+            if shade is not None:
+                if shade == 'flat':
+                    value |= wxnviz.DM_FLAT
+                else: # surface
+                    value |= wxnviz.DM_GOURAUD
+
+            return value
+
+        # -> string is False
+        if mode is not None:
+            if mode == 0: # coarse
+                value |= wxnviz.DM_WIRE
+                desc['mode'] = 'coarse'
+            elif mode == 1: # fine
+                value |= wxnviz.DM_POLY
+                desc['mode'] = 'fine'
+            else: # both
+                value |= wxnviz.DM_WIRE_POLY
+                desc['mode'] = 'both'
+
+        if style is not None:
+            if style == 0: # wire
+                value |= wxnviz.DM_GRID_WIRE
+                desc['style'] = 'wire'
+            else: # surface
+                value |= wxnviz.DM_GRID_SURF
+                desc['style'] = 'surface'
+
+        if shade is not None:
+            if shade == 0:
+                value |= wxnviz.DM_FLAT
+                desc['shading'] = 'flat'
+            else: # surface
+                value |= wxnviz.DM_GOURAUD
+                desc['shading'] = 'gouraud'
+        
+        return (value, desc)
+    
+    def SetDecorDefaultProp(self, type):
+        """!Set default arrow properties
+        """
+        data = {}
+        
+        # arrow
+        if type == 'arrow':
+            data['arrow'] = UserSettings.Get(group = 'nviz', key = 'arrow')
+            data['arrow']['color'] = "%d:%d:%d" % (
+                UserSettings.Get(group = 'nviz', key = 'arrow', subkey = 'color')[:3])
+            data['arrow'].update(UserSettings.Get(group = 'nviz', key = 'arrow', internal = True))
+            data['arrow']['show'] = False
+        
+        # arrow
+        if type == 'scalebar':
+            data['scalebar'] = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'scalebar'))
+            data['scalebar']['color'] = "%d:%d:%d" % (
+                UserSettings.Get(group = 'nviz', key = 'scalebar', subkey = 'color')[:3])
+            data['scalebar'].update(copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'scalebar', internal = True)))
+            data['scalebar']['id'] = 0
+        return data


Property changes on: grass/trunk/gui/wxpython/nviz/workspace.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/nviz/wxnviz.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/wxnviz.py)
===================================================================
--- grass/trunk/gui/wxpython/nviz/wxnviz.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/nviz/wxnviz.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,2102 @@
+"""!
+ at package nviz.wxnviz
+
+ at brief wxGUI 3D view mode (ctypes-based classes)
+
+This module implements 3D visualization mode for map display (ctypes
+required).
+
+List of classes:
+ - Nviz
+ - Texture
+ - ImageTexture
+ - TextTexture
+
+(C) 2008-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
+ at author Pythonized by Glynn Clements
+ at author Anna Kratochvilova <KratochAnna seznam.cz> (Google SoC 2011)
+"""
+
+import sys
+import locale
+import struct
+from math  import sqrt
+try:
+    from numpy import matrix
+except ImportError:
+    msg = _("This module requires the NumPy module, which could not be "
+            "imported. It probably is not installed (it's not part of the "
+            "standard Python distribution). See the Numeric Python site "
+            "(http://numpy.scipy.org) for information on downloading source or "
+            "binaries.")
+    print >> sys.stderr, "wxnviz.py: " + msg
+
+import wx
+
+from ctypes import *
+try:
+    from grass.lib.gis      import *
+    from grass.lib.raster3d import *
+    from grass.lib.vector   import *
+    from grass.lib.ogsf     import *
+    from grass.lib.nviz     import *
+    from grass.lib.raster   import *
+except ImportError, e:
+    sys.stderr.write(_("3D view mode: %s\n") % e)
+    
+from core.debug import Debug
+import grass.script as grass
+
+log      = None
+progress = None
+
+def print_error(msg, type):
+    """!Redirect stderr"""
+    global log
+    if log:
+        log.write(msg)
+    else:
+        print msg
+    
+    return 0
+
+def print_progress(value):
+    """!Redirect progress info"""
+    global progress
+    if progress:
+        progress.SetValue(value)
+    else:
+        print value
+    
+    return 0
+
+errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
+errfunc = errtype(print_error)
+pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
+perfunc = pertype(print_progress)
+
+class Nviz(object):
+    def __init__(self, glog, gprogress):
+        """!Initialize Nviz class instance
+        
+        @param log logging area
+        @param gprogress progressbar
+        """
+        global errfunc, perfunc, log, progress
+        log = glog
+        progress = gprogress
+        
+        G_gisinit("wxnviz")
+        # gislib is already initialized (where?)
+        G_set_error_routine(errfunc) 
+        G_set_percent_routine(perfunc)
+        
+        self.Init()
+        
+        self.data_obj = nv_data()
+        self.data = pointer(self.data_obj)
+        self.color_obj = Colors()
+        self.color = pointer(self.color_obj)
+        
+        self.width = self.height = -1
+        self.showLight = False
+        
+        Debug.msg(1, "Nviz::Nviz()")
+        
+    def __del__(self):
+        """!Destroy Nviz class instance"""
+        G_unset_error_routine()
+        G_unset_percent_routine()
+        del self.data
+        del self.data_obj
+        self.log = None
+
+    def Init(self):
+        """!Initialize window"""
+        locale.setlocale(locale.LC_NUMERIC, 'C')
+        G_unset_window()
+        Rast_unset_window()
+        Rast__init_window()
+        GS_libinit()
+        GVL_libinit()
+    
+    def ResizeWindow(self, width, height):
+        """!GL canvas resized
+        
+        @param width window width
+        @param height window height
+        
+        @return 1 on success
+        @return 0 on failure (window resized by default to 20x20 px)
+        """
+        self.width  = width
+        self.height = height
+        Debug.msg(3, "Nviz::ResizeWindow(): width=%d height=%d",
+                  width, height)
+        return Nviz_resize_window(width, height)
+    
+    def GetLongDim(self):
+        """!Get longest dimension, used for initial size of north arrow"""
+        return Nviz_get_longdim(self.data)
+    
+    def SetViewDefault(self):
+        """!Set default view (based on loaded data)
+        
+        @return z-exag value, default, min and max height
+        """
+        # determine z-exag
+        z_exag = Nviz_get_exag()
+        Nviz_change_exag(self.data, z_exag)
+        
+        # determine height
+        hdef = c_double()
+        hmin = c_double()
+        hmax = c_double()
+        Nviz_get_exag_height(byref(hdef), byref(hmin), byref(hmax))
+        
+        Debug.msg(1, "Nviz::SetViewDefault(): hdef=%f, hmin=%f, hmax=%f",
+                  hdef.value, hmin.value, hmax.value)
+        
+        return (z_exag, hdef.value, hmin.value, hmax.value)
+    
+    def SetView(self, x, y, height, persp, twist):
+        """!Change view settings
+        @param x,y position
+        @param height
+        @param persp perpective
+        @param twist
+        """
+        Nviz_set_viewpoint_height(height)
+        Nviz_set_viewpoint_position(x, y)
+        Nviz_set_viewpoint_twist(twist)
+        Nviz_set_viewpoint_persp(persp)
+        
+        Debug.msg(3, "Nviz::SetView(): x=%f, y=%f, height=%f, persp=%f, twist=%f",
+                  x, y, height, persp, twist)
+                
+    def GetViewpointPosition(self):
+        x = c_double()
+        y = c_double()
+        h = c_double()
+        Nviz_get_viewpoint_height(byref(h))
+        Nviz_get_viewpoint_position(byref(x), byref(y))
+        
+        return (x.value, y.value, h.value)
+        
+    def LookHere(self, x, y):
+        """!Look here feature 
+        @param x,y screen coordinates
+        """
+        
+        Nviz_look_here(x, y)
+        Debug.msg(3, "Nviz::LookHere(): x=%f, y=%f", x, y)
+    
+    def LookAtCenter(self):
+        """!Center view at center of displayed surface"""
+        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
+        Debug.msg(3, "Nviz::LookAtCenter()")
+    
+    def GetFocus(self):
+        """!Get focus"""
+        Debug.msg(3, "Nviz::GetFocus()")
+        if Nviz_has_focus(self.data):
+            x = c_float()
+            y = c_float()
+            z = c_float()
+            Nviz_get_focus(self.data, byref(x), byref(y), byref(z))
+            return x.value, y.value, z.value
+        else:
+            return -1, -1, -1
+        
+    def SetFocus(self, x, y, z):
+        """!Set focus"""
+        Debug.msg(3, "Nviz::SetFocus()")
+        Nviz_set_focus(self.data, x, y, z)
+        
+    def GetViewdir(self):
+        """!Get viewdir"""
+        Debug.msg(3, "Nviz::GetViewdir()")
+        dir = (c_float * 3)()
+        GS_get_viewdir(byref(dir))
+        
+        return dir[0], dir[1], dir[2]
+        
+    def SetViewdir(self, x, y, z):
+        """!Set viewdir"""
+        Debug.msg(3, "Nviz::SetViewdir(): x=%f, y=%f, z=%f" % (x, y, z))
+        dir = (c_float * 3)()
+        for i, coord in enumerate((x, y, z)):
+            dir[i] = coord
+        GS_set_viewdir(byref(dir))
+                
+    def SetZExag(self, z_exag):
+        """!Set z-exag value
+        
+        @param z_exag value
+        
+        @return 1
+        """
+        Debug.msg(3, "Nviz::SetZExag(): z_exag=%f", z_exag)
+        return Nviz_change_exag(self.data, z_exag)
+    
+    def Draw(self, quick, quick_mode):
+        """!Draw canvas
+        
+        Draw quick mode:
+         - DRAW_QUICK_SURFACE
+         - DRAW_QUICK_VLINES
+         - DRAW_QUICK_VPOINTS
+         - DRAW_QUICK_VOLUME
+        
+        @param quick if true draw in wiremode
+        @param quick_mode quick mode
+        """
+        Debug.msg(3, "Nviz::Draw(): quick=%d", quick)
+        
+        Nviz_draw_cplane(self.data, -1, -1) # ?
+        
+        if quick:
+            Nviz_draw_quick(self.data, quick_mode)
+        else:
+            Nviz_draw_all(self.data)
+        
+    def EraseMap(self):
+        """!Erase map display (with background color)
+        """
+        Debug.msg(1, "Nviz::EraseMap()")
+        GS_clear(Nviz_get_bgcolor(self.data))
+        
+    def InitView(self):
+        """!Initialize view"""
+        # initialize nviz data
+        Nviz_init_data(self.data)
+        
+        # define default attributes for map objects
+        Nviz_set_surface_attr_default()
+        # set background color
+        Nviz_set_bgcolor(self.data, Nviz_color_from_str("white"))
+        
+        GS_clear(Nviz_get_bgcolor(self.data))        
+        # initialize view, lights
+        Nviz_init_view(self.data)
+        
+        Debug.msg(1, "Nviz::InitView()")
+        
+    def SetBgColor(self, color_str):
+        """!Set background color
+        
+        @param color_str color string
+        """
+        Nviz_set_bgcolor(self.data, Nviz_color_from_str(color_str))
+        
+    def SetLight(self, x, y, z, color, bright, ambient, w = 0, lid = 1):
+        """!Change lighting settings
+        @param x,y,z position
+        @param color light color (as string)
+        @param bright light brightness
+        @param ambient light ambient
+        @param w local coordinate (default to 0)
+        """
+        Nviz_set_light_position(self.data, lid, x, y, z, w)
+        Nviz_set_light_bright(self.data, lid, bright)
+        Nviz_set_light_color(self.data, lid, int(color[0]), int(color[1]), int(color[2]))
+        Nviz_set_light_ambient(self.data, lid, ambient)
+                             
+    def LoadSurface(self, name, color_name, color_value):
+        """!Load raster map (surface)
+        
+        @param name raster map name
+        @param color_name raster map for color (None for color_value)
+        @param color_value color string (named color or RGB triptet)
+        
+        @return object id
+        @return -1 on failure
+        """
+        mapset = G_find_raster2(name, "")
+        if mapset is None:
+            G_warning(_("Raster map <%s> not found"), name)
+            return -1
+        
+        # topography
+        id = Nviz_new_map_obj(MAP_OBJ_SURF,
+                              G_fully_qualified_name(name, mapset), 0.0,
+                              self.data)
+        
+        if color_name:      # check for color map
+            mapset = G_find_raster2(color_name, "")
+            if mapset is None:
+                G_warning(_("Raster map <%s> not found"), color_name)
+                GS_delete_surface(id)
+                return -1
+            
+            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
+                          G_fully_qualified_name(color_name, mapset), -1.0,
+                          self.data)
+        
+        elif color_value:   # check for color value
+            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, CONST_ATT,
+                          None, Nviz_color_from_str(color_value),
+                          self.data)
+        
+        else:               # use by default elevation map for coloring
+            Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, MAP_ATT,
+                          G_fully_qualified_name(name, mapset), -1.0,
+                          self.data)
+        
+        # if (i > 1)
+        #     set_default_wirecolors(self.data, i)
+        
+        # focus on loaded self.data
+        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
+        
+        Debug.msg(1, "Nviz::LoadRaster(): name=%s -> id=%d", name, id)
+        
+        return id
+    
+    def AddConstant(self, value, color):
+        """!Add new constant surface"""
+        id = Nviz_new_map_obj(MAP_OBJ_SURF, None, value, self.data)
+        
+        Nviz_set_attr(id, MAP_OBJ_SURF, ATT_COLOR, CONST_ATT,
+                        None, Nviz_color_from_str(color),
+                        self.data)
+        Nviz_set_focus_map(MAP_OBJ_UNDEFINED, -1)
+        
+        Debug.msg(1, "Nviz::AddConstant(): id=%d", id)
+        return id
+        
+    def UnloadSurface(self, id):
+        """!Unload surface
+        
+        @param id surface id
+        
+        @return 1 on success
+        @return 0 on failure
+        """
+        if not GS_surf_exists(id):
+            return 0
+        
+        Debug.msg(1, "Nviz::UnloadSurface(): id=%d", id)
+        
+        if GS_delete_surface(id) < 0:
+            return 0
+        
+        return 1
+    
+    def LoadVector(self, name, points):
+        """!Load vector map overlay
+        
+        @param name vector map name
+        @param points if true load 2d points rather then 2d lines
+        
+        @return object id, id of base surface (or -1 if it is not loaded)
+        @return -1 on failure
+        """
+        baseId = -1
+        if GS_num_surfs() == 0:     # load base surface if no loaded
+            baseId = Nviz_new_map_obj(MAP_OBJ_SURF, None, 0.0, self.data)
+            
+            nsurf = c_int()
+            surf_list = GS_get_surf_list(byref(nsurf))
+            GS_set_att_const(surf_list[0], ATT_TRANSP, 255)
+            
+        mapset = G_find_vector2 (name, "")
+        if mapset is None:
+            G_warning(_("Vector map <%s> not found"),
+                      name)
+        
+        if points:
+            id = Nviz_new_map_obj(MAP_OBJ_SITE,
+                                  G_fully_qualified_name(name, mapset), 0.0,
+                                  self.data)
+        else:
+            id = Nviz_new_map_obj(MAP_OBJ_VECT,
+                                  G_fully_qualified_name(name, mapset), 0.0,
+                                  self.data)
+        
+        Debug.msg(1, "Nviz::LoadVector(): name=%s -> id=%d", name, id)
+        
+        return id, baseId
+    
+    def UnloadVector(self, id, points):
+        """!Unload vector set
+        
+        @param id vector set id
+        @param points vector points or lines set
+        
+        @return 1 on success
+        @return 0 on failure
+        """
+        Debug.msg(1, "Nviz::UnloadVector(): id=%d", id)
+        
+        if points:
+            if not GP_site_exists(id):
+                return 0
+            if GP_delete_site(id) < 0:
+                return 0
+        else:
+            if not GV_vect_exists(id):
+                return 0
+            if GV_delete_vector(id) < 0:
+                return 0
+        
+        return 1
+
+    def VectorSurfaceSelected(self, vid, sid):
+        """!Check if surface is selected (currently unused)
+        
+        @param vid vector id
+        @param sid surface id
+        
+        @return True if selected
+        @return False if not selected
+        """
+        selected = GV_surf_is_selected(vid, sid)
+        Debug.msg(1, "Nviz::VectorSurfaceSelected(): vid=%s, sid=%d -> selected=%d", vid, sid, selected)
+        return selected
+    
+    def LoadVolume(self, name, color_name, color_value):
+        """!Load 3d raster map (volume)
+        
+        @param name 3d raster map name
+        @param color_name 3d raster map for color (None for color_value)
+        @param color_value color string (named color or RGB triptet)
+        
+        @return object id
+        @return -1 on failure
+        """
+        mapset = G_find_raster3d(name, "")
+        if mapset is None:
+            G_warning(_("3d raster map <%s> not found"),
+                      name)
+            return -1
+        
+        # topography
+        id = Nviz_new_map_obj(MAP_OBJ_VOL,
+                              G_fully_qualified_name(name, mapset), 0.0,
+                              self.data)
+        
+        if color_name:      # check for color map
+            mapset = G_find_raster3d(color_name, "")
+            if mapset is None:
+                G_warning(_("3d raster map <%s> not found"),
+                          color_name)
+                GVL_delete_vol(id)
+                return -1
+            
+            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, MAP_ATT,
+                          G_fully_qualified_name(color_name, mapset), -1.0,
+                          self.data)
+        elif color_value:   # check for color value
+            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, CONST_ATT,
+                          None, Nviz_color_from_str(color_value),
+                          self.data)
+        else:               # use by default elevation map for coloring
+            Nviz_set_attr(id, MAP_OBJ_VOL, ATT_COLOR, MAP_ATT,
+                          G_fully_qualified_name(name, mapset), -1.0,
+                          self.data)
+        
+        Debug.msg(1, "Nviz::LoadVolume(): name=%s -> id=%d", name, id)
+        
+        return id
+
+    def UnloadVolume(self, id):
+        """!Unload volume
+        
+        @param id volume id
+        
+        @return 1 on success
+        @return 0 on failure
+        """
+        if not GVL_vol_exists(id):
+            return 0
+        
+        Debug.msg(1, "Nviz::UnloadVolume(): id=%d", id)
+        
+        if GVL_delete_vol(id) < 0:
+          return 0
+        
+        return 1
+    
+    def SetSurfaceTopo(self, id, map, value):
+        """!Set surface topography
+        
+        @param id surface id
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_TOPO, map, value)
+    
+    def SetSurfaceColor(self, id, map, value):
+        """!Set surface color
+        
+        @param id surface id
+        @param map if true use map otherwise constant
+        @param value map name or value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_COLOR, map, value)
+    
+    def SetSurfaceMask(self, id, invert, value):
+        """!Set surface mask
+        
+        @todo invert
+        
+        @param id surface id
+        @param invert if true invert mask 
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_MASK, True, value)
+    
+    def SetSurfaceTransp(self, id, map, value):
+        """!Set surface mask
+        
+        @todo invert
+        
+        @param id surface id
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_TRANSP, map, value)
+    
+    def SetSurfaceShine(self, id, map, value):
+        """!Set surface shininess
+        
+        @param id surface id
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_SHINE, map, value)
+    
+    def SetSurfaceEmit(self, id, map, value):
+        """!Set surface emission (currently unused)
+        
+        @param id surface id
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.SetSurfaceAttr(id, ATT_EMIT, map, value)
+    
+    def SetSurfaceAttr(self, id, attr, map, value):
+        """!Set surface attribute
+        
+        @param id surface id
+        @param attr attribute desc
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        if not GS_surf_exists(id):
+            return -1
+        
+        if map:
+            ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, MAP_ATT,
+                                value, -1.0, self.data)
+        else:
+            if attr == ATT_COLOR:
+                val = Nviz_color_from_str(value)
+            else:
+                val = float(value)
+            
+            ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, CONST_ATT,
+                                None, val, self.data)
+        
+        Debug.msg(3, "Nviz::SetSurfaceAttr(): id=%d, attr=%d, map=%d, value=%s",
+                  id, attr, map, value)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def UnsetSurfaceMask(self, id):
+        """!Unset surface mask
+        
+        @param id surface id
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        @return -1 on failure
+        """
+        return self.UnsetSurfaceAttr(id, ATT_MASK)
+    
+    def UnsetSurfaceTransp(self, id):
+        """!Unset surface transparency
+        
+        @param id surface id
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.UnsetSurfaceAttr(id, ATT_TRANSP)
+    
+    def UnsetSurfaceEmit(self, id):
+        """!Unset surface emission (currently unused)
+        
+        @param id surface id
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        return self.UnsetSurfaceAttr(id, ATT_EMIT)
+    
+    def UnsetSurfaceAttr(self, id, attr):
+        """!Unset surface attribute
+        
+        @param id surface id
+        @param attr attribute descriptor
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        if not GS_surf_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::UnsetSurfaceAttr(): id=%d, attr=%d",
+                  id, attr)
+        
+        ret = Nviz_unset_attr(id, MAP_OBJ_SURF, attr)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+
+    def SetSurfaceRes(self, id, fine, coarse):
+        """!Set surface resolution
+        
+        @param id surface id
+        @param fine x/y fine resolution
+        @param coarse x/y coarse resolution
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        Debug.msg(3, "Nviz::SetSurfaceRes(): id=%d, fine=%d, coarse=%d",
+                  id, fine, coarse)
+        
+        if id > 0:
+            if not GS_surf_exists(id):
+                return -1
+            
+            if GS_set_drawres(id, fine, fine, coarse, coarse) < 0:
+                return -2
+        else:
+            GS_setall_drawres(fine, fine, coarse, coarse)
+        
+        return 1
+
+    def SetSurfaceStyle(self, id, style):
+        """!Set draw style
+        
+        Draw styles:
+         - DM_GOURAUD
+         - DM_FLAT
+         - DM_FRINGE
+         - DM_WIRE
+         - DM_COL_WIRE
+         - DM_POLY
+         - DM_WIRE_POLY
+         - DM_GRID_WIRE
+         - DM_GRID_SURF
+         
+        @param id surface id (<= 0 for all)
+        @param style draw style
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        """
+        Debug.msg(3, "Nviz::SetSurfaceStyle(): id=%d, style=%d",
+                  id, style)
+        
+        if id > 0:
+            if not GS_surf_exists(id):
+                return -1
+            
+            if GS_set_drawmode(id, style) < 0:
+                return -2
+            
+            return 1
+        
+        if GS_setall_drawmode(style) < 0:
+            return -2
+        
+        return 1
+    
+    def SetWireColor(self, id, color_str):
+        """!Set color of wire
+        
+        @todo all
+         
+        @param surface id (< 0 for all)
+        @param color color string (R:G:B)
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting attributes failed
+        @return 1 on success
+        @return 0 on failure
+        """
+        Debug.msg(3, "Nviz::SetWireColor(): id=%d, color=%s",
+                  id, color_str)
+        
+        color = Nviz_color_from_str(color_str)
+        
+        if id > 0:
+            if not GS_surf_exists(id):
+                return -1
+            
+            GS_set_wire_color(id, color)
+        else:
+            nsurfs = c_int()
+            surf_list = GS_get_surf_list(byref(nsurfs))
+            for i in xrange(nsurfs.value):
+                id = surf_list[i]
+                GS_set_wire_color(id, color)
+            
+            G_free(surf_list)
+            surf_list = None
+        
+        return 1
+    
+    def GetSurfacePosition(self, id):
+        """!Get surface position
+        
+        @param id surface id
+        
+        @return x,y,z
+        @return zero-length vector on error
+        """
+        if not GS_surf_exists(id):
+            return []
+        
+        x, y, z = c_float(), c_float(), c_float()
+        GS_get_trans(id, byref(x), byref(y), byref(z))
+        
+        Debug.msg(3, "Nviz::GetSurfacePosition(): id=%d, x=%f, y=%f, z=%f",
+                  id, x.value, y.value, z.value)
+        
+        return [x.value, y.value, z.value]
+
+    def SetSurfacePosition(self, id, x, y, z):
+        """!Set surface position
+        
+        @param id surface id
+        @param x,y,z translation values
+        
+        @return 1 on success
+        @return -1 surface not found
+        @return -2 setting position failed
+        """
+        if not GS_surf_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetSurfacePosition(): id=%d, x=%f, y=%f, z=%f",
+                  id, x, y, z)
+        
+        GS_set_trans(id, x, y, z)
+        
+        return 1
+
+    def SetVectorLineMode(self, id, color_str, width, flat):
+        """!Set mode of vector line overlay
+        
+        @param id vector id
+        @param color_str color string
+        @param width line width
+        @param flat display flat or on surface
+        
+        @return -1 vector set not found
+        @return -2 on failure
+        @return 1 on success
+        """
+        if not GV_vect_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetVectorMode(): id=%d, color=%s, width=%d, flat=%d",
+                  id, color_str, width, flat)
+        
+        color = Nviz_color_from_str(color_str)
+        
+        # use memory by default
+        if GV_set_style(id, 1, color, width, flat) < 0:
+            return -2
+        
+        return 1
+
+    def SetVectorLineHeight(self, id, height):
+        """!Set vector height above surface (lines)
+        
+        @param id vector set id
+        @param height
+        
+        @return -1 vector set not found
+        @return 1 on success
+        """
+        if not GV_vect_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetVectorLineHeight(): id=%d, height=%f",
+                  id, height)
+        
+        GV_set_trans(id, 0.0, 0.0, height)
+        
+        return 1
+
+    def SetVectorLineSurface(self, id, surf_id):
+        """!Set reference surface of vector set (lines)
+        
+        @param id vector set id
+        @param surf_id surface id
+        
+        @return 1 on success
+        @return -1 vector set not found
+        @return -2 surface not found
+        @return -3 on failure
+        """
+        if not GV_vect_exists(id):
+            return -1
+        
+        if not GS_surf_exists(surf_id):
+            return -2
+        
+        if GV_select_surf(id, surf_id) < 0:
+            return -3
+        
+        return 1
+
+    def UnsetVectorLineSurface(self, id, surf_id):
+        """!Unset reference surface of vector set (lines)
+        
+        @param id vector set id
+        @param surf_id surface id
+        
+        @return 1 on success
+        @return -1 vector set not found
+        @return -2 surface not found
+        @return -3 on failure
+        """
+        if not GV_vect_exists(id):
+            return -1
+        
+        if not GS_surf_exists(surf_id):
+            return -2
+        
+        if GV_unselect_surf(id, surf_id) < 0:
+            return -3
+        
+        return 1
+        
+    def SetVectorPointMode(self, id, color_str, width, size, marker):
+        """!Set mode of vector point overlay
+        
+        @param id vector id
+        @param color_str color string
+        @param width line width
+        @param flat
+        
+        @return -1 vector set not found
+        """
+        if not GP_site_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetVectorPointMode(): id=%d, color=%s, "
+                  "width=%d, size=%f, marker=%d",
+                  id, color_str, width, size, marker)
+        
+        color = Nviz_color_from_str(color_str)
+        
+        if GP_set_style(id, color, width, size, marker) < 0:
+            return -2
+        
+        return 1
+
+    def SetVectorPointHeight(self, id, height):
+        """!Set vector height above surface (points)
+        
+        @param id vector set id
+        @param height
+        
+        @return -1 vector set not found
+        @return 1 on success
+        """
+        if not GP_site_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetVectorPointHeight(): id=%d, height=%f",
+                  id, height)
+        
+        GP_set_trans(id, 0.0, 0.0, height)
+        
+        return 1
+
+    def SetVectorPointSurface(self, id, surf_id):
+        """!Set reference surface of vector set (points)
+        
+        @param id vector set id
+        @param surf_id surface id
+        
+        @return 1 on success
+        @return -1 vector set not found
+        @return -2 surface not found
+        @return -3 on failure
+        """
+        if not GP_site_exists(id):
+            return -1
+        
+        if not GS_surf_exists(surf_id):
+            return -2
+        
+        if GP_select_surf(id, surf_id) < 0:
+            return -3
+        
+        return 1
+
+    def ReadVectorColors(self, name, mapset):
+        """!Read vector colors
+        
+        @param name vector map name
+        @mapset mapset name ("" for search path)
+        
+        @return -1 on error 
+        @return 0 if color table missing 
+        @return 1 on success (color table found) 
+        """
+        return Vect_read_colors(name, mapset, self.color)
+        
+    def CheckColorTable(self, id, type):
+        """!Check if color table exists.
+        
+        @param id vector set id
+        @param type vector set type (lines/points)
+        
+        @return 1 color table exists
+        @return 0 no color table found
+        @return -1 on error
+        @return -2 vector set not found
+        """
+        file = c_char_p()
+        
+        if type == 'points':
+            ret = GP_get_sitename(id, byref(file))
+        elif type == 'lines':
+            ret = GV_get_vectname(id, byref(file))
+            
+        if ret < 0:
+            return -2
+        
+        return self.ReadVectorColors(file, "")
+        
+    def SetPointsStyleThematic(self, id, layer, color = None, colorTable = False, 
+                               width = None, size = None, symbol = None):
+        """!Set thematic style for vector points
+        
+        @param id vector set id
+        @param layer layer number for thematic mapping
+        @param colorTable use color table 
+        @param color color column name 
+        @param width width column name 
+        @param size size column name 
+        @param symbol symbol column name 
+        """
+        file = c_char_p()
+        ret = GP_get_sitename(id, byref(file))
+        if ret < 0:
+            return -1
+        
+        ret = self.ReadVectorColors(file, "")
+        if ret < 0:
+            return -1
+        
+        if colorTable:
+            GP_set_style_thematic(id, layer, color, width, size, symbol, self.color)
+        else:
+            GP_set_style_thematic(id, layer, color, width, size, symbol, None)
+
+    def SetLinesStyleThematic(self, id, layer, color = None, colorTable = False, width = None):
+        """!Set thematic style for vector lines
+        
+        @param id vector set id
+        @param layer layer number for thematic mapping
+        @param color color column name 
+        @param colorTable use color table 
+        @param width width column name 
+        """
+        file = c_char_p()
+        ret = GV_get_vectname(id, byref(file))
+        if ret < 0:
+            return -1
+        
+        ret = self.ReadVectorColors(file, "")
+        if ret < 0:
+            return -1
+        
+        if colorTable:
+            GV_set_style_thematic(id, layer, color, width, self.color)
+        else:
+            GV_set_style_thematic(id, layer, color, width, None)
+        
+    def UnsetLinesStyleThematic(self, id):
+        """!Unset thematic style for vector points"""
+        GV_unset_style_thematic(id)      
+         
+    def UnsetPointsStyleThematic(self, id):
+        """!Unset thematic style for vector lines"""
+        GP_unset_style_thematic(id)
+        
+    def UnsetVectorPointSurface(self, id, surf_id):
+        """!Unset reference surface of vector set (points)
+        
+        @param id vector set id
+        @param surf_id surface id
+        
+        @return 1 on success
+        @return -1 vector set not found
+        @return -2 surface not found
+        @return -3 on failure
+        """
+        if not GP_site_exists(id):
+            return -1
+        
+        if not GS_surf_exists(surf_id):
+            return -2
+        
+        if GP_unselect_surf(id, surf_id) < 0:
+            return -3
+        
+        return 1
+        
+    def AddIsosurface(self, id, level, isosurf_id = None):
+        """!Add new isosurface
+        
+        @param id volume id
+        @param level isosurface level (topography)
+        
+        @return -1 on failure
+        @return 1 on success
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id is not None:
+            num = GVL_isosurf_num_isosurfs(id)
+            if num < 0 or isosurf_id != num:
+                return -1
+                
+        if GVL_isosurf_add(id) < 0:
+            return -1
+        
+        # set topography level
+        nisosurfs = GVL_isosurf_num_isosurfs(id)
+        
+        return GVL_isosurf_set_att_const(id, nisosurfs - 1, ATT_TOPO, level)
+    
+    def AddSlice(self, id, slice_id = None):
+        """!Add new slice
+        
+        @param id volume id
+        
+        @return -1 on failure
+        @return number of slices
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if slice_id is not None:
+            num = GVL_slice_num_slices(id)
+            if num < 0 or slice_id != num:
+                return -1
+                
+        if GVL_slice_add(id) < 0:
+            return -1
+        
+        return GVL_slice_num_slices(id)
+    
+    def DeleteIsosurface(self, id, isosurf_id):
+        """!Delete isosurface
+        
+        @param id volume id
+        @param isosurf_id isosurface id
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id > GVL_isosurf_num_isosurfs(id):
+            return -2
+        
+        ret = GVL_isosurf_del(id, isosurf_id)
+        
+        if ret < 0:
+            return -3
+
+        return 1
+    
+    def DeleteSlice(self, id, slice_id):
+        """!Delete slice
+        
+        @param id volume id
+        @param slice_id slice id
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 slice not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if slice_id > GVL_slice_num_slices(id):
+            return -2
+        
+        ret = GVL_slice_del(id, slice_id)
+        
+        if ret < 0:
+            return -3
+
+        return 1
+    
+    def MoveIsosurface(self, id, isosurf_id, up):
+        """!Move isosurface up/down in the list
+        
+        @param id volume id
+        @param isosurf_id isosurface id
+        @param up if true move up otherwise down
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id > GVL_isosurf_num_isosurfs(id):
+            return -2
+        
+        if up:
+            ret = GVL_isosurf_move_up(id, isosurf_id)
+        else:
+            ret = GVL_isosurf_move_down(id, isosurf_id)
+        
+        if ret < 0:
+            return -3
+
+        return 1
+
+    def MoveSlice(self, id, slice_id, up):
+        """!Move slice up/down in the list
+        
+        @param id volume id
+        @param slice_id slice id
+        @param up if true move up otherwise down
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 slice not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if slice_id > GVL_slice_num_slices(id):
+            return -2
+        
+        if up:
+            ret = GVL_slice_move_up(id, slice_id)
+        else:
+            ret = GVL_slice_move_down(id, slice_id)
+        
+        if ret < 0:
+            return -3
+
+        return 1
+    
+    def SetIsosurfaceTopo(self, id, isosurf_id, map, value):
+        """!Set isosurface level
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_TOPO, map, value)
+    
+    def SetIsosurfaceColor(self, id, isosurf_id, map, value):
+        """!Set isosurface color
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_COLOR, map, value)
+    
+    def SetIsosurfaceMask(self, id, isosurf_id, invert, value):
+        """!Set isosurface mask
+        
+        @todo invert
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param invert true for invert mask
+        @param value map name to be used for mask
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_MASK, True, value)
+    
+    def SetIsosurfaceTransp(self, id, isosurf_id, map, value):
+        """!Set isosurface transparency
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_TRANSP, map, value)
+    
+    def SetIsosurfaceShine(self, id, isosurf_id, map, value):
+        """!Set isosurface shininess
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_SHINE, map, value)
+    
+    def SetIsosurfaceEmit(self, id, isosurf_id, map, value):
+        """!Set isosurface emission (currently unused)
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        return self.SetIsosurfaceAttr(id, isosurf_id, ATT_EMIT, map, value)
+    
+    def SetIsosurfaceAttr(self, id, isosurf_id, attr, map, value):
+        """!Set isosurface attribute
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param attr attribute desc
+        @param map if true use map otherwise constant
+        @param value map name of value
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 setting attributes failed
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
+            return -2
+        
+        if map:
+            ret = GVL_isosurf_set_att_map(id, isosurf_id, attr, value)
+        else:
+            if attr == ATT_COLOR:
+                val = Nviz_color_from_str(value)
+            else:
+                val = float(value)
+            
+            ret = GVL_isosurf_set_att_const(id, isosurf_id, attr, val)
+        
+        Debug.msg(3, "Nviz::SetIsosurfaceAttr(): id=%d, isosurf=%d, "
+                  "attr=%d, map=%s, value=%s",
+                  id, isosurf_id, attr, map, value)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def UnsetIsosurfaceMask(self, id, isosurf_id):
+        """!Unset isosurface mask
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 setting attributes failed
+        """
+        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_MASK)
+    
+    def UnsetIsosurfaceTransp(self, id, isosurf_id):
+        """!Unset isosurface transparency
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 setting attributes failed
+        """
+        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_TRANSP)
+    
+    def UnsetIsosurfaceEmit(self, id, isosurf_id):
+        """!Unset isosurface emission (currently unused)
+        
+        @param id volume id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -3 setting attributes failed
+        """
+        return self.UnsetIsosurfaceAttr(id, isosurf_id, ATT_EMIT)
+    
+    def UnsetIsosurfaceAttr(self, id, isosurf_id, attr):
+        """!Unset surface attribute
+        
+        @param id surface id
+        @param isosurf_id isosurface id (0 - MAX_ISOSURFS)
+        @param attr attribute descriptor
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 isosurface not found
+        @return -2 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
+            return -2
+        
+        Debug.msg(3, "Nviz::UnsetSurfaceAttr(): id=%d, isosurf_id=%d, attr=%d",
+                  id, isosurf_id, attr)
+        
+        ret = GVL_isosurf_unset_att(id, isosurf_id, attr)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+
+    def SetIsosurfaceMode(self, id, mode):
+        """!Set draw mode for isosurfaces
+        
+        @param mode
+        
+        @return 1 on success
+        @return -1 volume set not found
+        @return -2 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        ret = GVL_isosurf_set_drawmode(id, mode)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetSliceMode(self, id, mode):
+        """!Set draw mode for slices
+        
+        @param mode
+        
+        @return 1 on success
+        @return -1 volume set not found
+        @return -2 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        ret = GVL_slice_set_drawmode(id, mode)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetIsosurfaceRes(self, id, res):
+        """!Set draw resolution for isosurfaces
+        
+        @param res resolution value
+        
+        @return 1 on success
+        @return -1 volume set not found
+        @return -2 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        ret = GVL_isosurf_set_drawres(id, res, res, res)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetSliceRes(self, id, res):
+        """!Set draw resolution for slices
+        
+        @param res resolution value
+        
+        @return 1 on success
+        @return -1 volume set not found
+        @return -2 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        ret = GVL_slice_set_drawres(id, res, res, res)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetSlicePosition(self, id, slice_id, x1, x2, y1, y2, z1, z2, dir):
+        """!Set slice position
+        
+        @param id volume id
+        @param slice_id slice id
+        @param x1,x2,y1,y2,z1,z2 slice coordinates
+        @param dir axis
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 slice not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if slice_id > GVL_slice_num_slices(id):
+            return -2
+        
+        ret = GVL_slice_set_pos(id, slice_id, x1, x2, y1, y2, z1, z2, dir)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetSliceTransp(self, id, slice_id, value):
+        """!Set slice transparency
+        
+        @param id volume id
+        @param slice_id slice id
+        @param x1,x2,y1,y2,z1,z2 slice coordinates
+        @param value transparency value (0 - 255)
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 slice not found
+        @return -3 on failure
+        """
+        
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if slice_id > GVL_slice_num_slices(id):
+            return -2
+        
+        ret = GVL_slice_set_transp(id, slice_id, value)
+        
+        if ret < 0:
+            return -2
+        
+        return 1
+    
+    def SetIsosurfaceInOut(self, id, isosurf_id, inout):
+        """!Set inout mode
+        
+        @param inout mode true/false
+        
+        @return 1 on success
+        @return -1 volume set not found
+        @return -2 isosurface not found
+        @return -3 on failure
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        if isosurf_id > GVL_isosurf_num_isosurfs(id) - 1:
+            return -2
+        
+        ret = GVL_isosurf_set_flags(id, isosurf_id, inout)
+        
+        if ret < 0:
+            return -3
+        
+        return 1
+    
+    def GetVolumePosition(self, id):
+        """!Get volume position
+        
+        @param id volume id
+        
+        @return x,y,z
+        @return zero-length vector on error
+        """
+        if not GVL_vol_exists(id):
+            return []
+        
+        x, y, z = c_float(), c_float(), c_float()
+        GVL_get_trans(id, byref(x), byref(y), byref(z))
+        
+        Debug.msg(3, "Nviz::GetVolumePosition(): id=%d, x=%f, y=%f, z=%f",
+                  id, x.value, y.value, z.value)
+        
+        return [x.value, y.value, z.value]
+    
+    def SetVolumePosition(self, id, x, y, z):
+        """!Set volume position
+        
+        @param id volume id
+        @param x,y,z translation values
+        
+        @return 1 on success
+        @return -1 volume not found
+        @return -2 setting position failed
+        """
+        if not GVL_vol_exists(id):
+            return -1
+        
+        Debug.msg(3, "Nviz::SetVolumePosition(): id=%d, x=%f, y=%f, z=%f",
+                  id, x, y, z)
+        
+        GVL_set_trans(id, x, y, z)
+        
+        return 1
+    
+    def GetCPlaneCurrent(self):
+        return Nviz_get_current_cplane(self.data)
+    
+    def GetCPlanesCount(self):
+        """!Returns number of cutting planes"""
+        return Nviz_num_cplanes(self.data) 
+    
+    def GetCPlaneRotation(self):
+        """!Returns rotation parameters of current cutting plane"""
+        x, y, z = c_float(), c_float(), c_float()
+        
+        current = Nviz_get_current_cplane(self.data)
+        Nviz_get_cplane_rotation(self.data, current, byref(x), byref(y), byref(z))
+        
+        return x.value, y.value, z.value
+    
+    def GetCPlaneTranslation(self):
+        """!Returns translation parameters of current cutting plane"""
+        x, y, z = c_float(), c_float(), c_float()
+        
+        current = Nviz_get_current_cplane(self.data)
+        Nviz_get_cplane_translation(self.data, current, byref(x), byref(y), byref(z))
+        
+        return x.value, y.value, z.value
+    
+    def SetCPlaneRotation(self, x, y, z):
+        """!Set current clip plane rotation
+        
+        @param x,y,z rotation parameters
+        """
+        current = Nviz_get_current_cplane(self.data)
+        Nviz_set_cplane_rotation(self.data, current, x, y, z)
+        Nviz_draw_cplane(self.data, -1, -1)
+    
+    def SetCPlaneTranslation(self, x, y, z):
+        """!Set current clip plane translation
+        
+        @param x,y,z translation parameters
+        """
+        current = Nviz_get_current_cplane(self.data)
+        Nviz_set_cplane_translation(self.data, current, x, y, z)
+        Nviz_draw_cplane(self.data, -1, -1) 
+        Debug.msg(3, "Nviz::SetCPlaneTranslation(): id=%d, x=%f, y=%f, z=%f",
+                  current, x, y, z)
+                
+    def SetCPlaneInteractively(self, x, y):
+        current = Nviz_get_current_cplane(self.data)
+        ret = Nviz_set_cplane_here(self.data, current, x, y)
+        if ret:
+            Nviz_draw_cplane(self.data, -1, -1)
+            x, y, z = self.GetCPlaneTranslation()
+            return x, y, z
+        else:
+            return None, None, None
+        
+        
+    def SelectCPlane(self, index):
+        """!Select cutting plane
+        
+        @param index index of cutting plane
+        """
+        Nviz_on_cplane(self.data, index)
+    
+    def UnselectCPlane(self, index):
+        """!Unselect cutting plane
+        
+        @param index index of cutting plane
+        """
+        Nviz_off_cplane(self.data, index)
+        
+    def SetFenceColor(self, index):
+        """!Select current cutting plane
+        
+        @param index type of fence - from 0 (off) to 4
+        """    
+        Nviz_set_fence_color(self.data, index)
+            
+    def GetXYRange(self):
+        """!Get xy range"""
+        return Nviz_get_xyrange(self.data)
+    
+    def GetZRange(self):
+        """!Get z range"""
+        min, max = c_float(), c_float()
+        Nviz_get_zrange(self.data, byref(min), byref(max))
+        return min.value, max.value
+    
+    def SaveToFile(self, filename, width = 20, height = 20, itype = 'ppm'):
+        """!Save current GL screen to ppm/tif file
+
+        @param filename file name
+        @param width image width
+        @param height image height
+        @param itype image type ('ppm' or 'tif')
+        """
+        widthOrig  = self.width
+        heightOrig = self.height
+        
+        self.ResizeWindow(width, height)
+        GS_clear(Nviz_get_bgcolor(self.data))
+        self.Draw(False, -1)
+        if itype == 'ppm':
+            GS_write_ppm(filename)
+        else:
+            GS_write_tif(filename)
+        
+        self.ResizeWindow(widthOrig, heightOrig)
+
+    def DrawLightingModel(self):
+        """!Draw lighting model"""
+        if self.showLight:
+            Nviz_draw_model(self.data)
+
+    def DrawFringe(self):
+        """!Draw fringe"""
+        Nviz_draw_fringe(self.data)
+        
+    def SetFringe(self, sid, color, elev, nw = False, ne = False, sw = False, se = False):
+        """!Set fringe
+
+        @param sid surface id
+        @param color color
+        @param elev elevation (height)
+        @param nw,ne,sw,se fringe edges (turn on/off)
+        """
+        scolor = str(color[0]) + ':' + str(color[1]) + ':' + str(color[2])
+        Nviz_set_fringe(self.data,
+                        sid, Nviz_color_from_str(scolor),
+                        elev, int(nw), int(ne), int(sw), int(se))
+    
+    def DrawArrow(self):
+        """!Draw north arrow
+        """
+        return Nviz_draw_arrow(self.data)
+        
+    def SetArrow(self, sx, sy, size, color):
+        """!Set north arrow from canvas coordinates
+        
+        @param sx,sy canvas coordinates
+        @param size arrow length
+        @param color arrow color
+        """
+        return Nviz_set_arrow(self.data, sx, sy, size, Nviz_color_from_str(color))       
+        
+    def DeleteArrow(self):
+        """!Delete north arrow
+        """
+        Nviz_delete_arrow(self.data)
+    
+    def SetScalebar(self, id, sx, sy, size, color):
+        """!Set scale bar from canvas coordinates
+        
+        @param sx,sy canvas coordinates
+        @param id scale bar id
+        @param size scale bar length
+        @param color scale bar color
+        """
+        return Nviz_set_scalebar(self.data, id, sx, sy, size, Nviz_color_from_str(color))
+    
+    def DrawScalebar(self):
+        """!Draw scale bar
+        """
+        return Nviz_draw_scalebar(self.data)
+    
+    def DeleteScalebar(self, id):
+        """!Delete scalebar
+        """
+        Nviz_delete_scalebar(self.data, id)
+        
+    def GetPointOnSurface(self, sx, sy):
+        """!Get point on surface
+
+        @param sx,sy canvas coordinates (LL)
+        """
+        sid = c_int()
+        x   = c_float()
+        y   = c_float()
+        z   = c_float()
+        Debug.msg(5, "Nviz::GetPointOnSurface(): sx=%d sy=%d" % (sx, sy))
+        num = GS_get_selected_point_on_surface(sx, sy, byref(sid), byref(x), byref(y), byref(z))
+        if num == 0:
+            return (None, None, None, None)
+        
+        return (sid.value, x.value, y.value, z.value)
+
+    def QueryMap(self, sx, sy):
+        """!Query surface map
+
+        @param sx,sy canvas coordinates (LL)
+        """
+        sid, x, y, z = self.GetPointOnSurface(sx, sy)
+        if not sid:
+            return None
+        
+        catstr = create_string_buffer(256)
+        valstr = create_string_buffer(256)
+        GS_get_cat_at_xy(sid, ATT_TOPO, catstr, x, y)
+        GS_get_val_at_xy(sid, ATT_COLOR, valstr, x, y)
+        
+        return { 'id' : sid,
+                 'x'  : x,
+                 'y'  : y,
+                 'z'  : z,
+                 'elevation' : catstr.value.replace('(', '').replace(')', ''),
+                 'color'     : valstr.value }
+    
+    def GetDistanceAlongSurface(self, sid, p1, p2, useExag = True):
+        """!Get distance measured along surface"""
+        d = c_float()
+        
+        GS_get_distance_alongsurf(sid, p1[0], p1[1], p2[0], p2[1],
+                                  byref(d), int(useExag))
+        
+        return d.value
+
+    def GetRotationParameters(self, dx, dy):
+        """!Get rotation parameters (angle, x, y, z axes)
+        
+        @param dx,dy difference from previous mouse drag event
+        """
+        modelview = (c_double * 16)()
+        Nviz_get_modelview(byref(modelview))
+        
+        angle = sqrt(dx*dx+dy*dy)/float(self.width+1)*180.0
+        m = []
+        row = []
+        for i, item in enumerate(modelview):
+            row.append(item)
+            if (i+1) % 4 == 0:
+                m.append(row)
+                row = []
+        inv = matrix(m).I
+        ax, ay, az = dy, dx, 0.
+        x = inv[0,0]*ax + inv[1,0]*ay + inv[2,0]*az
+        y = inv[0,1]*ax + inv[1,1]*ay + inv[2,1]*az
+        z = inv[0,2]*ax + inv[1,2]*ay + inv[2,2]*az
+        
+        return angle, x, y, z 
+       
+    def Rotate(self, angle, x, y, z):
+        """!Set rotation parameters
+        Rotate scene (difference from current state).
+
+        @param angle angle
+        @param x,y,z axis coordinate
+        """
+        Nviz_set_rotation(angle, x, y, z)
+        
+    def UnsetRotation(self):
+        """!Stop rotating the scene"""
+        Nviz_unset_rotation()
+        
+    def ResetRotation(self):
+        """!Reset scene rotation"""
+        Nviz_init_rotation()
+        
+    def GetRotationMatrix(self):
+        """!Get rotation matrix"""
+        matrix = (c_double * 16)()
+        GS_get_rotation_matrix(byref(matrix))
+        returnMatrix = []
+        for item in matrix:
+            returnMatrix.append(item)
+        return returnMatrix
+        
+    def SetRotationMatrix(self, matrix):
+        """!Set rotation matrix"""
+        mtrx = (c_double * 16)()
+        for i in range(len(matrix)):
+            mtrx[i] = matrix[i]
+        GS_set_rotation_matrix(byref(mtrx))
+    
+    def Start2D(self):
+        Nviz_set_2D(self.width, self.height)
+        
+    def FlyThrough(self, flyInfo, mode, exagInfo):
+        """!Fly through the scene
+        
+        @param flyInfo fly parameters
+        @param mode 0 or 1 for different fly behaviour
+        @param exagInfo parameters changing fly speed
+        """
+        fly = (c_float * 3)()
+        for i, item in enumerate(flyInfo):
+            fly[i] = item
+        exag = (c_int * 2)()
+        exag[0] = int(exagInfo['move'])
+        exag[1] = int(exagInfo['turn'])
+        Nviz_flythrough(self.data, fly, exag, mode)
+        
+class Texture(object):
+    """!Class representing OpenGL texture"""
+    def __init__(self, filepath, overlayId, coords):
+        """!Load image to texture
+
+        @param filepath path to image file
+        @param overlayId id of overlay (1 for legend, 101 and more for text)
+        @param coords image coordinates
+        """
+        self.path = filepath
+        self.image = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
+        self.width = self.image.GetWidth()
+        self.height = self.image.GetHeight()
+        self.id = overlayId
+        self.coords = list(coords)
+        self.bounds = wx.Rect()
+        self.active = True
+        
+        # alpha needs to be initialized
+        if not self.image.HasAlpha():
+            self.image.InitAlpha()
+    
+        # resize image to match 2^n
+        self.Resize()
+        
+        # check max texture size
+        maxSize = c_int()
+        Nviz_get_max_texture(byref(maxSize))
+        self.maxSize = maxSize.value
+        if self.maxSize < self.width or self.maxSize < self.height:
+            # TODO: split up image 
+            self.textureId = None
+        else:
+            self.textureId = self.Load()
+            
+    def __del__(self):
+        """!Delete texture"""
+        if self.textureId:
+            Nviz_del_texture(self.textureId)
+        grass.try_remove(self.path)
+            
+    def Resize(self):    
+        """!Resize image to match 2^n"""
+        n = m = 1
+        while self.width > pow(2,n):
+            n += 1
+        while self.height > pow(2,m):
+            m += 1
+        self.image.Resize(size = (pow(2,n), pow(2,m)), pos = (0, 0))
+        self.width = self.image.GetWidth()
+        self.height = self.image.GetHeight()
+        
+    def Load(self):
+        """!Load image to texture"""  
+        if self.image.HasAlpha():
+            bytesPerPixel = 4
+        else:
+            bytesPerPixel = 3
+        bytes = bytesPerPixel * self.width * self.height
+        rev_val = self.height - 1
+        im = (c_ubyte * bytes)()
+        bytes3 = 3 * self.width * self.height
+        bytes1 = self.width * self.height
+        imageData = struct.unpack(str(bytes3) + 'B', self.image.GetData())
+        if self.image.HasAlpha():
+            alphaData = struct.unpack(str(bytes1) + 'B', self.image.GetAlphaData())
+        
+        # this takes too much time
+        wx.BeginBusyCursor()
+        for i in range(self.height):
+            for j in range(self.width):
+                im[(j + i * self.width) * bytesPerPixel + 0] = imageData[( j + (rev_val - i) * self.width) * 3 + 0]
+                im[(j + i * self.width) * bytesPerPixel + 1] = imageData[( j + (rev_val - i) * self.width) * 3 + 1]
+                im[(j + i * self.width) * bytesPerPixel + 2] = imageData[( j + (rev_val - i) * self.width) * 3 + 2]
+                if self.image.HasAlpha():
+                    im[(j + i * self.width) * bytesPerPixel + 3] = alphaData[( j + (rev_val - i) * self.width)]
+        wx.EndBusyCursor()
+        
+        id = Nviz_load_image(im, self.width, self.height, self.image.HasAlpha())
+        
+        return id
+        
+    def Draw(self):
+        """!Draw texture as an image"""
+        Nviz_draw_image(self.coords[0], self.coords[1], self.width, self.height, self.textureId)
+    
+        
+    def SetBounds(self, rect):
+        """!Set Bounding Rectangle"""
+        self.bounds = rect
+        
+    def HitTest(self, x, y, radius):
+        copy = wx.Rect(*self.bounds)
+        copy.Inflate(radius, radius)
+        return copy.ContainsXY(x, y)
+    
+    def MoveTexture(self, dx, dy):
+        """!Move texture on the screen"""
+        self.coords[0] += dx
+        self.coords[1] += dy
+        self.bounds.OffsetXY(dx, dy)
+    
+    def SetCoords(self, coords):
+        """!Set coordinates"""
+        dx = coords[0] - self.coords[0]
+        dy = coords[1] - self.coords[1]
+        self.MoveTexture(dx, dy)
+        
+    def GetId(self):
+        """!Returns image id."""
+        return self.id
+    
+    def SetActive(self, active = True):
+        self.active = active
+        
+    def IsActive(self):
+        return self.active
+        
+class ImageTexture(Texture):
+    """!Class representing OpenGL texture as an overlay image"""
+    def __init__(self, filepath, overlayId, coords, cmd):
+        """!Load image to texture
+
+        @param filepath path to image file
+        @param overlayId id of overlay (1 for legend)
+        @param coords image coordinates
+        @param cmd d.legend command      
+        """
+        Texture.__init__(self, filepath = filepath, overlayId = overlayId, coords = coords)
+        
+        self.cmd = cmd
+        
+    def GetCmd(self):
+        """!Returns overlay command."""
+        return self.cmd
+        
+    def Corresponds(self, item):
+        return sorted(self.GetCmd()) == sorted(item.GetCmd())
+        
+class TextTexture(Texture):
+    """!Class representing OpenGL texture as a text label"""
+    def __init__(self, filepath, overlayId, coords, textDict):
+        """!Load image to texture
+
+        @param filepath path to image file
+        @param overlayId id of overlay (101 and more for text)
+        @param coords text coordinates
+        @param textDict text properties      
+        """
+        Texture.__init__(self, filepath = filepath, overlayId = overlayId, coords = coords)
+        
+        self.textDict = textDict
+        
+    def GetTextDict(self):
+        """!Returns text properties."""
+        return self.textDict
+        
+        
+    def Corresponds(self, item):
+        t = self.GetTextDict()
+        for prop in t.keys():
+            if prop in ('coords','bbox'): continue
+            if t[prop] != item[prop]:
+                return False
+                
+        return True
+    

Copied: grass/trunk/gui/wxpython/psmap/dialogs.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py)
===================================================================
--- grass/trunk/gui/wxpython/psmap/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/psmap/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,6403 @@
+"""!
+ at package psmap.dialogs
+
+ at brief Map feature objects and dialogs for wxPsMap
+
+Classes:
+ - UnitConversion
+ - TCValidator
+ - PenStyleComboBox
+ - CheckListCtrl
+ - Instruction
+ - InstructionObject
+ - InitMap
+ - MapFrame
+ - PageSetup
+ - Mapinfo
+ - Text
+ - Image
+ - NorthArrow
+ - Scalebar
+ - RasterLegend
+ - VectorLegend
+ - Raster
+ - Vector
+ - VProperties
+ - PsmapDialog
+ - PageSetupDialog
+ - MapDialog
+ - MapFramePanel
+ - RasterPanel
+ - VectorPanel
+ - RasterDialog
+ - MainVectorDialog
+ - VPropertiesDialog
+ - LegendDialog
+ - MapinfoDialog
+ - ScalebarDialog
+ - TextDialog
+ - ImageDialog
+ - NorthArrowDialog
+
+(C) 2011 by Anna Kratochvilova, and 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 Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
+ at author Martin Landa <landa.martin gmail.com> (mentor)
+"""
+
+import os
+import sys
+import string
+from math import ceil, floor, sin, cos, pi
+from copy import deepcopy
+from time import strftime, localtime
+try:
+    import Image as PILImage
+    havePILImage = True
+except ImportError:
+    havePILImage = False
+
+import wx
+import wx.lib.scrolledpanel    as scrolled
+import wx.lib.filebrowsebutton as filebrowse
+from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin
+from wx.lib.expando         import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
+try:
+    import wx.lib.agw.floatspin as fs
+except ImportError:
+    fs = None
+
+import grass.script as grass
+
+from core             import globalvar
+from dbm.vinfo        import VectorDBInfo
+from core.utils       import CmdToTuple, GetCmdString
+from gui_core.gselect import Select
+from core.gcmd        import RunCommand, GError, GMessage, GWarning
+
+# grass.set_raise_on_error(True)
+
+PSMAP_COLORS = ['aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'grey', 'green', 'indigo',
+                'magenta','orange', 'purple', 'red', 'violet', 'white', 'yellow']
+
+class UnitConversion:
+    """! Class for converting units"""
+    def __init__(self, parent = None):
+        self.parent = parent
+        if self.parent:
+            ppi = wx.PaintDC(self.parent).GetPPI()
+        else: 
+            ppi = (72, 72)
+        self._unitsPage = { 'inch'          : {'val': 1.0, 'tr' : _("inch")},
+                            'point'         : {'val': 72.0, 'tr' : _("point")},
+                            'centimeter'    : {'val': 2.54, 'tr' : _("centimeter")},
+                            'millimeter'    : {'val': 25.4, 'tr' : _("millimeter")}}
+        self._unitsMap = {  'meters'        : {'val': 0.0254, 'tr' : _("meters")},
+                            'kilometers'    : {'val': 2.54e-5, 'tr' : _("kilometers")},
+                            'feet'          : {'val': 1./12, 'tr' : _("feet")},
+                            'miles'         : {'val': 1./63360, 'tr' : _("miles")},
+                            'nautical miles': {'val': 1/72913.386, 'tr' : _("nautical miles")}}
+
+        self._units = { 'pixel'     : {'val': ppi[0], 'tr' : _("pixel")},
+                        'meter'     : {'val': 0.0254, 'tr' : _("meter")},
+                        'nautmiles' : {'val': 1/72913.386, 'tr' :_("nautical miles")},
+                        'degrees'   : {'val': 0.0254 , 'tr' : _("degree")} #like 1 meter, incorrect
+                        }
+        self._units.update(self._unitsPage)
+        self._units.update(self._unitsMap)
+
+    def getPageUnitsNames(self):
+        return sorted(self._unitsPage[unit]['tr'] for unit in self._unitsPage.keys())
+    
+    def getMapUnitsNames(self):
+        return sorted(self._unitsMap[unit]['tr'] for unit in self._unitsMap.keys())
+    
+    def getAllUnits(self):
+        return sorted(self._units.keys())
+    
+    def findUnit(self, name):
+        """!Returns unit by its tr. string"""
+        for unit in self._units.keys():
+            if self._units[unit]['tr'] == name:
+                return unit
+        return None
+    
+    def findName(self, unit):
+        """!Returns tr. string of a unit"""
+        try:
+            return self._units[unit]['tr']
+        except KeyError:
+            return None
+    
+    def convert(self, value, fromUnit = None, toUnit = None):
+        return float(value)/self._units[fromUnit]['val']*self._units[toUnit]['val']
+    
+    
+class TCValidator(wx.PyValidator):
+    """!validates input in textctrls, combobox, taken from wxpython demo"""
+    def __init__(self, flag = None):
+        wx.PyValidator.__init__(self)
+        self.flag = flag
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+
+    def Clone(self):
+        return TCValidator(self.flag)
+
+    def Validate(self, win):
+        
+        tc = self.GetWindow()
+        val = tc.GetValue()
+
+        if self.flag == 'DIGIT_ONLY':
+            for x in val:
+                if x not in string.digits:
+                    return False
+        return True
+
+    def OnChar(self, event):
+        key = event.GetKeyCode()
+        if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
+            event.Skip()
+            return
+        if self.flag == 'DIGIT_ONLY' and chr(key) in string.digits + '.':
+            event.Skip()
+            return
+##        if self.flag == 'SCALE' and chr(key) in string.digits + ':':
+##            event.Skip()
+##            return
+        if self.flag == 'ZERO_AND_ONE_ONLY' and chr(key) in '01':
+            event.Skip()
+            return
+        if not wx.Validator_IsSilent():
+            wx.Bell()
+        # Returning without calling even.Skip eats the event before it
+        # gets to the text control
+        return  
+
+
+class PenStyleComboBox(wx.combo.OwnerDrawnComboBox):
+    """!Combo for selecting line style, taken from wxpython demo"""
+
+    # Overridden from OwnerDrawnComboBox, called to draw each
+    # item in the list
+    def OnDrawItem(self, dc, rect, item, flags):
+        if item == wx.NOT_FOUND:
+            # painting the control, but there is no valid item selected yet
+            return
+
+        r = wx.Rect(*rect)  # make a copy
+        r.Deflate(3, 5)
+
+        penStyle = wx.SOLID
+        if item == 1:
+            penStyle = wx.LONG_DASH
+        elif item == 2:
+            penStyle = wx.DOT
+        elif item == 3:
+            penStyle = wx.DOT_DASH
+
+        pen = wx.Pen(dc.GetTextForeground(), 3, penStyle)
+        dc.SetPen(pen)
+
+        # for painting the items in the popup
+        dc.DrawText(self.GetString(item ),
+                    r.x + 3,
+                    (r.y + 0) + ((r.height/2) - dc.GetCharHeight() )/2
+                    )
+        dc.DrawLine(r.x+5, r.y+((r.height/4)*3)+1, r.x+r.width - 5, r.y+((r.height/4)*3)+1 )
+
+        
+    def OnDrawBackground(self, dc, rect, item, flags):
+        """!Overridden from OwnerDrawnComboBox, called for drawing the
+        background area of each item."""
+        # If the item is selected, or its item # iseven, or we are painting the
+        # combo control itself, then use the default rendering.
+        if (item & 1 == 0 or flags & (wx.combo.ODCB_PAINTING_CONTROL |
+                                      wx.combo.ODCB_PAINTING_SELECTED)):
+            wx.combo.OwnerDrawnComboBox.OnDrawBackground(self, dc, rect, item, flags)
+            return
+
+        # Otherwise, draw every other background with different colour.
+        bgCol = wx.Colour(240,240,250)
+        dc.SetBrush(wx.Brush(bgCol))
+        dc.SetPen(wx.Pen(bgCol))
+        dc.DrawRectangleRect(rect);
+
+    def OnMeasureItem(self, item):
+        """!Overridden from OwnerDrawnComboBox, should return the height
+        needed to display an item in the popup, or -1 for default"""
+        return 30
+
+    def OnMeasureItemWidth(self, item):
+        """!Overridden from OwnerDrawnComboBox.  Callback for item width, or
+        -1 for default/undetermined"""
+        return -1; # default - will be measured from text width  
+    
+    
+class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
+    """!List control for managing order and labels of vector maps in legend"""
+    def __init__(self, parent):
+        wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY, 
+                             style = wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.BORDER_SUNKEN|wx.LC_VRULES|wx.LC_HRULES)
+        CheckListCtrlMixin.__init__(self) 
+        ListCtrlAutoWidthMixin.__init__(self)
+        
+class Instruction:
+    """!Class which represents instruction file"""
+    def __init__(self, parent, objectsToDraw):
+        
+        self.parent = parent
+        self.objectsToDraw = objectsToDraw
+        #here are kept objects like mapinfo, rasterlegend, etc.
+        self.instruction = list()
+        
+    def __str__(self):
+        """!Returns text for instruction file"""
+        comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
+        env = grass.gisenv()
+        comment += "# location: %s\n" % env['LOCATION_NAME']
+        comment += "# mapset: %s\n" % env['MAPSET']
+        comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
+        border = ''
+        if not self.FindInstructionByType('map'):
+            border = 'border n\n'
+        text = [str(each) for each in self.instruction]
+        return comment + border + '\n'.join(text) + '\nend'
+    
+    def __getitem__(self, id):
+        for each in self.instruction:
+            if each.id == id:
+                return each
+        return None
+
+    def __contains__(self, id):
+        """!Test if instruction is included"""
+        for each in self.instruction:
+            if each.id == id:
+                return True
+        return False
+    
+    def __delitem__(self, id):
+        """!Delete instruction"""
+        for each in self.instruction:
+            if each.id == id:
+                if each.type == 'map':
+                    #must remove raster, vector layers too
+                    vektor = self.FindInstructionByType('vector', list = True)
+                    vProperties = self.FindInstructionByType('vProperties', list = True)
+                    raster = self.FindInstructionByType('raster', list = True)
+                    for item in vektor + vProperties + raster:
+                        if item in self.instruction:
+                            self.instruction.remove(item)
+                            
+                self.instruction.remove(each)
+                if id in self.objectsToDraw:
+                    self.objectsToDraw.remove(id)
+                return
+            
+    def AddInstruction(self, instruction):
+        """!Add instruction"""
+        # add to instructions
+        if instruction.type == 'map':
+            self.instruction.insert(0, instruction)
+        else:
+            self.instruction.append(instruction)
+        # add to drawable objects
+        if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
+            if instruction.type == 'map':
+                self.objectsToDraw.insert(0, instruction.id) 
+            else:
+                self.objectsToDraw.append(instruction.id) 
+                
+            
+    def FindInstructionByType(self, type, list = False):
+        """!Find instruction(s) with the given type"""
+        inst = []
+        for each in self.instruction:
+            if each.type == type:
+                inst.append(each)
+        if len(inst) == 1 and not list:
+            return inst[0]
+        return inst
+    
+    def Read(self, filename):
+        """!Reads instruction file and creates instruction objects"""
+        self.filename = filename
+        # open file
+        try:
+            file = open(filename, 'r')
+        except IOError:
+            GError(message = _("Unable to open file\n%s") % filename)
+            return
+        # first read file to get information about region and scaletype
+        isRegionComment = False
+        orientation = 'Portrait'
+        for line in file:
+            if '# g.region' in line:
+                self.SetRegion(regionInstruction = line)
+                isRegionComment = True
+                break
+            if '# page orientation' in line:
+                orientation = line.split(':')[-1].strip()
+                
+        if not isRegionComment:
+            self.SetRegion(regionInstruction = None)
+        # then run ps.map -b to get information for maploc
+        # compute scale and center 
+        map = self.FindInstructionByType('map')
+        region = grass.region()
+        map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
+        mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
+        map['rect'] = mapRect
+        proj = projInfo()
+        toM = 1.0
+        if proj['units']:
+            toM = float(proj['meters'])
+        units = UnitConversion(self.parent)
+        w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
+        map['scale'] = w / abs((region['w'] - region['e']))
+        
+        SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
+        
+        # read file again, now with information about map bounds
+        isBuffer = False
+        buffer = []
+        instruction = None
+        vectorMapNumber = 1
+        file.seek(0)
+        for line in file:
+            if not line.strip(): 
+                continue
+            line = line.strip()
+            if isBuffer:
+                buffer.append(line)
+                if 'end' in line:
+                    isBuffer = False
+                    kwargs = {}
+                    if instruction == 'scalebar':
+                        kwargs['scale'] = map['scale']
+                    elif instruction in ('text', 'eps'):
+                        kwargs['mapInstruction'] = map
+                    elif instruction in ('vpoints', 'vlines', 'vareas'):
+                        kwargs['id'] = wx.NewId()
+                        kwargs['vectorMapNumber'] = vectorMapNumber
+                        vectorMapNumber += 1
+                    elif instruction == 'paper':
+                        kwargs['Orientation'] = orientation
+                        
+                    ok = self.SendToRead(instruction, buffer, **kwargs)
+                    if not ok: return False
+                    buffer = []
+                continue 
+            
+            elif line.startswith('paper'):
+                instruction = 'paper'
+                isBuffer = True
+                buffer.append(line)
+            
+            elif line.startswith('border'):
+                if line.split()[1].lower() in ('n', 'no', 'none'):
+                    ok = self.SendToRead('border', [line])
+                    if not ok: return False
+                elif line.split()[1].lower() in ('y', 'yes'):
+                    instruction = 'border'
+                    isBuffer = True
+                    buffer.append(line)
+            
+            elif line.startswith('scale '):
+                if isBuffer:
+                    continue
+                ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
+                if not ok: return False
+            
+            elif line.startswith('maploc'):
+                ok = self.SendToRead(instruction = 'maploc', text = line)
+                if not ok: return False
+                
+            elif line.startswith('raster'):
+                ok = self.SendToRead(instruction = 'raster', text = line)
+                if not ok: return False
+            
+            elif line.startswith('mapinfo'):
+                instruction = 'mapinfo'
+                isBuffer = True
+                buffer.append(line)
+
+
+            elif line.startswith('scalebar'):
+                instruction = 'scalebar'
+                isBuffer = True
+                buffer.append(line) 
+            
+            elif line.startswith('text'):
+                instruction = 'text'
+                isBuffer = True
+                buffer.append(line)
+                
+            elif line.startswith('eps'):
+                instruction = 'eps'
+                isBuffer = True
+                buffer.append(line) 
+            
+            elif line.startswith('colortable'):
+                if len(line.split()) == 2 and line.split()[1].lower() in ('n', 'no', 'none'):
+                    break
+                instruction = 'colortable'
+                isBuffer = True
+                buffer.append(line) 
+        
+            elif line.startswith('vlegend'):
+                instruction = 'vlegend'
+                isBuffer = True
+                buffer.append(line) 
+                
+            elif line.startswith('vpoints'):
+                instruction = 'vpoints'
+                isBuffer = True
+                buffer.append(line) 
+                
+            elif line.startswith('vlines'):
+                instruction = 'vlines'
+                isBuffer = True
+                buffer.append(line)
+                
+            elif line.startswith('vareas'):
+                instruction = 'vareas'
+                isBuffer = True
+                buffer.append(line)
+
+
+        
+        rasterLegend = self.FindInstructionByType('rasterLegend')
+        raster = self.FindInstructionByType('raster')
+        page = self.FindInstructionByType('page')
+        vector = self.FindInstructionByType('vector')
+        vectorLegend = self.FindInstructionByType('vectorLegend')
+        vectorMaps = self.FindInstructionByType('vProperties', list = True)
+
+        # check (in case of scaletype 0) if map is drawn also
+        map['drawMap'] = False
+        if map['scaleType'] == 0:
+            mapForRegion = map['map']
+            if map['mapType'] == 'raster' and raster:
+                if mapForRegion == raster['raster']:
+                    map['drawMap'] = True
+            elif map['mapType'] == 'vector' and vector:
+                for vmap in vector['list']:
+                    if mapForRegion == vmap[0]:
+                        map['drawMap'] = True
+
+        # rasterLegend
+        if rasterLegend:
+            if rasterLegend['rasterDefault'] and raster:
+                rasterLegend['raster'] = raster['raster']
+                if not rasterLegend['discrete']:
+                    rasterType = getRasterType(map = rasterLegend['raster'])
+                    if rasterType == 'CELL':
+                        rasterLegend['discrete'] = 'y'
+                    else:
+                        rasterLegend['discrete'] = 'n'
+            
+            #estimate size
+            height = rasterLegend.EstimateHeight(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
+                                                 fontsize = rasterLegend['fontsize'],
+                                                 cols = rasterLegend['cols'], 
+                                                 height = rasterLegend['height'])
+            width = rasterLegend.EstimateWidth(raster = rasterLegend['raster'], discrete = rasterLegend['discrete'], 
+                                               fontsize = rasterLegend['fontsize'],
+                                               cols = rasterLegend['cols'] , 
+                                               width = rasterLegend['width'],
+                                               paperInstr = page)
+            rasterLegend['rect'] = wx.Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
+                                             w = width, h = height)
+            
+        # vectors, vlegend        
+        
+        if vector:
+            for vmap in vectorMaps:
+                for i, each in enumerate(vector['list']):
+                    if each[2] == vmap.id:
+                        
+                        vector['list'][i][4] = vmap['label']
+                        vector['list'][i][3] = vmap['lpos']
+            if vectorLegend:
+                size = vectorLegend.EstimateSize(vectorInstr = vector, fontsize = vectorLegend['fontsize'],
+                                                 width = vectorLegend['width'], cols = vectorLegend['cols'])                            
+                vectorLegend['rect'] = wx.Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
+                                                 w = size[0], h = size[1])
+        
+        
+        page = self.FindInstructionByType('page')
+        if not page:
+            page = PageSetup(wx.NewId())
+            self.AddInstruction(page)
+        else:
+            page['Orientation'] = orientation
+
+
+        #
+        return True
+    
+    def SendToRead(self, instruction, text, **kwargs):
+        psmapInstrDict = dict(paper = ['page'],
+                              maploc = ['map'],
+                              scale = ['map'],
+                              border = ['map'],
+                              raster = ['raster'],
+                              mapinfo = ['mapinfo'],
+                              scalebar = ['scalebar'],
+                              text = ['text'],
+                              eps = ['image', 'northArrow'],
+                              vpoints = ['vector', 'vProperties'],
+                              vlines = ['vector', 'vProperties'],
+                              vareas = ['vector', 'vProperties'],
+                              colortable = ['rasterLegend'],
+                              vlegend = ['vectorLegend']
+                              )
+        
+        myInstrDict = dict(page = PageSetup,
+                           map = MapFrame,
+                           raster = Raster,
+                           mapinfo = Mapinfo,
+                           scalebar = Scalebar,
+                           text = Text,
+                           image = Image,
+                           northArrow = NorthArrow,
+                           rasterLegend = RasterLegend,
+                           vectorLegend = VectorLegend,
+                           vector = Vector,
+                           vProperties = VProperties
+                           )
+        
+        myInstruction = psmapInstrDict[instruction]
+        
+        for i in myInstruction:
+            instr = self.FindInstructionByType(i)
+            if i in ('text', 'vProperties', 'image', 'northArrow') or not instr:
+                
+                id = wx.NewId() #!vProperties expect subtype
+                if i == 'vProperties':
+                    id = kwargs['id']
+                    newInstr = myInstrDict[i](id, subType = instruction[1:])
+                elif i in ('image', 'northArrow'):
+                    commentFound = False
+                    for line in text:
+                        if line.find("# north arrow") >= 0:
+                            commentFound = True
+                    if i == 'image' and commentFound or \
+                       i == 'northArrow' and not commentFound:
+                        continue
+                    newInstr = myInstrDict[i](id, settings = self)
+                else:
+                    newInstr = myInstrDict[i](id)
+                ok = newInstr.Read(instruction, text, **kwargs)
+                if ok:
+                    self.AddInstruction(newInstr)
+                else:
+                    return False
+
+            else:
+                ok = instr.Read(instruction, text, **kwargs)
+
+                if not ok:
+                    return False
+        return True
+    
+    def SetRegion(self, regionInstruction):
+        """!Sets region from file comment or sets current region in case of no comment"""
+        map = MapFrame(wx.NewId())
+        self.AddInstruction(map)
+        if regionInstruction:
+            cmd = CmdToTuple(regionInstruction.strip('# ').split())
+            
+            # define scaleType
+            if len(cmd[1]) <= 3:
+                if 'rast' in cmd[1]:
+                    map['scaleType'] = 0
+                    map['mapType'] = 'raster'   
+                    map['map'] = cmd[1]['rast']  
+                elif 'vect' in cmd[1]:
+                    map['scaleType'] = 0
+                    map['mapType'] = 'vector' 
+                    map['map'] = cmd[1]['vect']  
+                elif 'region' in cmd[1]:
+                    map['scaleType'] = 1  
+                    map['region'] = cmd[1]['region']
+                    
+            else:
+                map['scaleType'] = 2  
+        else:
+            map['scaleType'] = 2
+            grass.del_temp_region()
+            region = grass.region()
+            grass.use_temp_region()    
+            cmd = ['g.region', region]
+        cmdString = GetCmdString(cmd).replace('g.region', '')
+        GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
+        try:
+            RunCommand(cmd[0], **cmd[1])
+            
+        except grass.ScriptError, e:
+            GError(_("Region cannot be set\n%s") % e)
+            return False
+        
+
+class InstructionObject:
+    """!Abtract class representing single instruction"""
+    def __init__(self, id): 
+        self.id = id
+        
+        # default values
+        self.defaultInstruction = dict()
+        # current values
+        self.instruction = self.defaultInstruction   
+        # converting units
+        self.unitConv = UnitConversion() 
+    
+    def __str__(self):
+        """!Returns particular part of text instruction"""
+        return ''
+    
+    def __getitem__(self, key):
+        for each in self.instruction.keys():
+            if each == key:
+                return self.instruction[key]
+        return None
+    
+    def __setitem__(self, key, value):
+        self.instruction[key] = value
+    
+    def GetInstruction(self):
+        """!Get current values"""
+        return self.instruction
+    
+    def SetInstruction(self, instruction):
+        """!Set default values"""
+        self.instruction = instruction
+        
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save them"""
+        pass
+    
+class InitMap(InstructionObject):
+    """!Class representing virtual map"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'initMap'
+        
+        # default values
+        self.defaultInstruction = dict(rect = None, scale =  None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    
+class MapFrame(InstructionObject):
+    """!Class representing map (instructions maploc, scale, border)"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'map'
+        # default values
+        self.defaultInstruction = dict(map = None, mapType = None, drawMap = True, region = None,
+                                       rect = wx.Rect2D(), scaleType = 0, scale = None, center = None,
+                                       resolution = 300, border = 'y', width = 1, color = '0:0:0') 
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = ''
+        comment = ''
+        
+        #region settings
+        region = grass.region()
+        if self.instruction['scaleType'] == 0: #match map
+            map = self.instruction['map']
+            if self.instruction['mapType'] == 'raster':
+                comment = "# g.region rast=%s nsres=%s ewres=%s\n" % (map, region['nsres'], region['ewres'])
+            else:
+                comment = "# g.region vect=%s\n" % (map)
+        elif self.instruction['scaleType'] == 1:# saved region
+            region = self.instruction['region']
+            comment = "# g.region region=%s\n" % region
+        elif self.instruction['scaleType'] in (2, 3): #current region, fixed scale
+            comment = string.Template("# g.region n=$n s=$s e=$e w=$w rows=$rows cols=$cols \n").substitute(**region)
+        
+        instr += comment
+        instr += '\n'
+        # maploc
+        maplocInstruction = "maploc %.3f %.3f" % (self.instruction['rect'].x, self.instruction['rect'].y)
+        if self.instruction['scaleType'] != 3:
+            maplocInstruction += "  %.3f %.3f"% (self.instruction['rect'].width, self.instruction['rect'].height)
+        instr += maplocInstruction
+        instr += '\n'
+        
+        # scale
+        if self.instruction['scaleType'] == 3: #fixed scale
+            scaleInstruction = "scale 1:%.0f" % (1/self.instruction['scale'])
+            instr += scaleInstruction
+            instr += '\n'
+        # border
+        borderInstruction = ''
+        if self.instruction['border'] == 'n':
+            borderInstruction = "border n"
+        else:
+            borderInstruction = "border y\n"
+            borderInstruction += string.Template("    width $width\n    color $color\n").substitute(self.instruction)
+            borderInstruction += "    end"
+        instr += borderInstruction
+        instr += '\n'
+
+        return instr  
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        if 'isRegionComment' in kwargs:
+            isRegionComment = kwargs['isRegionComment']
+        instr = {}
+        
+        if instruction == 'border':
+            for line in text:
+                if line.startswith('end'):
+                    break
+                try:
+                    if line.split()[1].lower() in ('n', 'no', 'none'):
+                        instr['border'] = 'n'
+                        break
+                    elif line.split()[1].lower() in ('y', 'yes'):
+                        instr['border'] = 'y'
+                    elif line.startswith('width'):
+                        instr['width'] = line.split()[1]
+                    elif line.startswith('color'):
+                        instr['color'] = line.split()[1]
+                except IndexError:
+                    GError(_("Failed to read instruction %s") % instruction)
+                    return False
+                
+        elif instruction == 'scale':
+            try:
+                scaleText = text.strip('scale ').split(':')[1]
+                # when scale instruction given and region comment also, then scaletype is fixed scale
+                if not isRegionComment:
+                    instr['scaleType'] = 2 
+                else:
+                    instr['scaleType'] = 3
+
+                scale = 1/float(scaleText)
+                if abs(scale - self.instruction['scale']) > (0.01 * scale):
+                    GWarning(_("Scale has changed, old value: %(old)s\nnew value: %(new)s") % \
+                                 { 'old' : scale, 'new' : self.instruction['scale'] })
+            except (ValueError, IndexError):
+                GError(_("Failed to read instruction %s.\nUse 1:25000 notation.") % instruction)
+                return False
+        
+        elif instruction == 'maploc':
+            maploc = text.strip('maploc ').split()
+            if len(maploc) >= 2:
+                if  abs(self.instruction['rect'].Get()[0] - float(maploc[0])) > 0.5 or \
+                        abs(self.instruction['rect'].Get()[1] - float(maploc[1])) > 0.5:
+                    GWarning(_("Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
+                                 { 'old1' : maploc[0], 'old2' : maploc[1],
+                                   'new1' : self.instruction['rect'].Get()[0], 'new2' : self.instruction['rect'].Get()[1] })
+                    
+                #instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3])
+            if len(maploc) == 4:
+                if  abs(self.instruction['rect'].Get()[2] - float(maploc[2])) > 0.5 or \
+                        abs(self.instruction['rect'].Get()[3] - float(maploc[3])) > 0.5:
+                    GWarning(_("Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s") % \
+                                 { 'old1' : maploc[2], 'old2' : maploc[3],
+                                   'new1' : self.instruction['rect'].Get()[2], 'new2' : self.instruction['rect'].Get()[3] })
+                #instr['rect'] = wx.Rect2D(*map(float, maploc))
+        self.instruction.update(instr)   
+        return True 
+    
+class PageSetup(InstructionObject):
+    """!Class representing page instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'page'
+        # default values
+        self.defaultInstruction = dict(Units = 'inch', Format = 'a4', Orientation = 'Portrait',
+                                       Width = 8.268, Height = 11.693, Left = 0.5, Right = 0.5, Top = 1, Bottom = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        if self.instruction['Format'] == 'custom':
+            instr = string.Template("paper\n    width $Width\n    height $Height\n").substitute(self.instruction)
+        else:
+            instr = string.Template("paper $Format\n").substitute(self.instruction)
+        instr += string.Template("    left $Left\n    right $Right\n    bottom $Bottom\n    top $Top\n    end").substitute(self.instruction)
+
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        self.cats = ['Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+        self.subInstr = dict(zip(['width', 'height', 'left', 'right', 'top', 'bottom'], self.cats))
+        
+        if instruction == 'paper': # just for sure
+            for line in text:
+                if line.startswith('paper'): 
+                    if len(line.split()) > 1:
+                        pformat = line.split()[1]
+                        availableFormats = self._toDict(grass.read_command('ps.map', flags = 'p',
+                                                                           quiet = True))
+                        # e.g. paper a3 
+                        try:
+                            instr['Format'] = pformat
+                            for key, value in availableFormats[pformat].iteritems():
+                                instr[key] = float(value)
+                            break
+                        except KeyError:
+                            GError(_("Failed to read instruction %(file)s.\nUnknown format %(for)s") % \
+                                       { 'file' : instruction, 'for' : format })
+                            return False
+                    else:
+                        # paper
+                        # width ...
+                        instr['Format'] = 'custom'
+                # read subinstructions
+                elif instr['Format'] == 'custom' and not line.startswith('end'):
+                    text = line.split()
+                    try:
+                        instr[self.subInstr[text[0]]] = float(text[1])
+                    except  (IndexError, KeyError):
+                        GError(_("Failed to read instruction %s.") % instruction)
+                        return False
+                    
+            if 'Orientation' in kwargs and kwargs['Orientation'] == 'Landscape':
+                instr['Width'], instr['Height'] = instr['Height'], instr['Width']
+                
+            self.instruction.update(instr)
+        return True  
+    
+    def _toDict(self, paperStr):    
+        sizeDict = dict()
+#     cats = self.subInstr[ 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+        for line in paperStr.strip().split('\n'):
+            d = dict(zip(self.cats, line.split()[1:]))
+            sizeDict[line.split()[0]] = d
+            
+        return sizeDict    
+    
+class Mapinfo(InstructionObject):
+    """!Class representing mapinfo instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'mapinfo'
+        # default values
+        self.defaultInstruction = dict(unit = 'inch', where = (0, 0),
+                                       font = 'Helvetica', fontsize = 10, color = '0:0:0', background = 'none', 
+                                       border = 'none', rect = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "mapinfo\n"
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").substitute(self.instruction)            
+        instr += string.Template("    background $background\n    border $border\n").substitute(self.instruction)  
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text):
+        """!Read instruction and save information"""
+        instr = {}
+        try:
+            for line in text:
+                sub = line.split(None,1)
+                if sub[0] == 'font':
+                    instr['font'] = sub[1]
+                elif sub[0] == 'fontsize':
+                    instr['fontsize'] = int(sub[1])
+                elif sub[0] == 'color':
+                    instr['color'] = sub[1]
+                elif sub[0] == 'background':
+                    instr['background'] = sub[1]
+                elif sub[0] == 'border':
+                    instr['border'] = sub[1]
+                elif sub[0] == 'where':
+                    instr['where'] = float(sub[1].split()[0]), float(sub[1].split()[1])
+        except (ValueError, IndexError):
+            GError(_("Failed to read instruction %s") % instruction)
+            return False
+        self.instruction.update(instr)
+        self.instruction['rect'] = self.EstimateRect(mapinfoDict = self.instruction)
+        return True
+    
+    def EstimateRect(self, mapinfoDict):
+        """!Estimate size to draw mapinfo"""
+        w = mapinfoDict['fontsize'] * 20 # any better estimation? 
+        h = mapinfoDict['fontsize'] * 7
+        width = self.unitConv.convert(value = w, fromUnit = 'point', toUnit = 'inch')
+        height = self.unitConv.convert(value = h, fromUnit = 'point', toUnit = 'inch')
+        return wx.Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]), w = width, h = height)
+    
+class Text(InstructionObject):
+    """!Class representing text instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'text'
+        # default values
+        self.defaultInstruction = dict(text = "", font = "Helvetica", fontsize = 10, color = 'black', background = 'none',
+                                       hcolor = 'none', hwidth = 1, border = 'none', width = '1', XY = True,
+                                       where = (0,0), unit = 'inch', rotate = None, 
+                                       ref = "center center", xoffset = 0, yoffset = 0, east = None, north = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        text = self.instruction['text'].replace('\n','\\n')
+        instr = "text %s %s" % (self.instruction['east'], self.instruction['north'])
+        try:
+            instr += " %s\n" % text.encode('latin_1')
+        except UnicodeEncodeError, err:
+            try:
+                pos = str(err).split('position')[1].split(':')[0].strip()
+            except IndexError:
+                pos = ''
+            if pos:
+                message = _("Characters on position %s are not supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.") % pos
+            else:
+                message = _("Not all characters are supported "
+                            "by ISO-8859-1 (Latin 1) encoding "
+                            "which is required by module ps.map.")
+            GMessage(message = message)
+            return ''
+        instr += (string.Template("    font $font\n    fontsize $fontsize\n    color $color\n").
+                                                                   substitute(self.instruction).
+                                                                   encode('latin_1'))
+        instr += string.Template("    hcolor $hcolor\n").substitute(self.instruction).encode('latin_1')
+        if self.instruction['hcolor'] != 'none':
+            instr += string.Template("    hwidth $hwidth\n").substitute(self.instruction).encode('latin_1')
+        instr += string.Template("    border $border\n").substitute(self.instruction).encode('latin_1')
+        if self.instruction['border'] != 'none':
+            instr += string.Template("    width $width\n").substitute(self.instruction).encode('latin_1')
+        instr += string.Template("    background $background\n").substitute(self.instruction).encode('latin_1')
+        if self.instruction["ref"] != '0':
+            instr += string.Template("    ref $ref\n").substitute(self.instruction).encode('latin_1')
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction).encode('latin_1')
+        if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
+            instr += (string.Template("    xoffset $xoffset\n    yoffset $yoffset\n").
+                                                            substitute(self.instruction).encode('latin_1'))
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        map = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'text':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                        
+                    instr['text'] = line.split(None, 3)[3]
+                
+                elif sub == 'font':
+                    instr['font'] = line.split(None, 1)[1]
+                elif sub == 'fontsize':
+                    instr['fontsize'] = float(line.split(None, 1)[1])
+                elif sub == 'color':
+                    instr['color'] = line.split(None, 1)[1]
+                elif sub == 'width':
+                    instr['width'] = line.split(None, 1)[1]
+                elif sub == 'hcolor':
+                    instr['hcolor'] = line.split(None, 1)[1]
+                elif sub == 'hwidth':
+                    instr['hwidth'] = line.split(None, 1)[1]
+                elif sub == 'background':
+                    instr['background'] = line.split(None, 1)[1]
+                elif sub == 'border':
+                    instr['border'] = line.split(None, 1)[1]
+                elif sub == 'ref':
+                    instr['ref'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'xoffset':
+                    instr['xoffset'] = int(line.split(None, 1)[1])
+                elif sub == 'yoffset':
+                    instr['yoffset'] = int(line.split(None, 1)[1])
+                elif sub == 'opaque':
+                    if line.split(None, 1)[1].lower() in ('n', 'none'):
+                        instr['background'] = 'none'
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        instr['where'] = PaperMapCoordinates(map = map, x = instr['east'], y = instr['north'], paperToMap = False)       
+        self.instruction.update(instr)
+
+        return True 
+    
+    def PercentToReal(self, e, n):
+        """!Converts text coordinates from percent of region to map coordinates"""
+        e, n = float(e.strip('%')), float(n.strip('%'))
+        region = grass.region()
+        N = region['s'] + (region['n'] - region['s']) / 100 * n
+        E = region['w'] + (region['e'] - region['w']) / 100 * e
+        return E, N
+        
+class Image(InstructionObject):
+    """!Class representing eps instruction - image"""
+    def __init__(self, id, settings):
+        InstructionObject.__init__(self, id = id)
+        self.settings = settings
+        self.type = 'image'
+        # default values
+        self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
+                                       east = None, north = None,
+                                       rotate = None, scale = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'eps':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                
+                elif sub == 'epsfile':
+                    instr['epsfile'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'scale':
+                    instr['scale'] = float(line.split(None, 1)[1])
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        if not os.path.exists(instr['epsfile']):
+            GError(_("Failed to read instruction %s: file %s not found.") % instruction, instr['epsfile'])
+            return False
+        
+        instr['epsfile'] = os.path.abspath(instr['epsfile'])
+        instr['size'] = self.GetImageOrigSize(instr['epsfile'])
+        if 'rotate' in instr:
+            instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
+        self.instruction.update(instr)
+        self.ChangeRefPoint(toCenter = False)
+        instr['where'] = PaperMapCoordinates(map = mapInstr, x = self.instruction['east'],
+                                             y = self.instruction['north'], paperToMap = False)       
+        w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
+        instr['rect'] = wx.Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
+                                  w = w * self.instruction['scale'], h = h * self.instruction['scale'])
+        self.instruction.update(instr)
+
+        return True 
+    
+    def PercentToReal(self, e, n):
+        """!Converts eps coordinates from percent of region to map coordinates"""
+        e, n = float(e.strip('%')), float(n.strip('%'))
+        region = grass.region()
+        N = region['s'] + (region['n'] - region['s']) / 100 * n
+        E = region['w'] + (region['e'] - region['w']) / 100 * e
+        return E, N
+        
+    def ChangeRefPoint(self, toCenter):
+        """!Change reference point (left top x center)"""
+        mapInstr = self.settings.FindInstructionByType('map')
+        if not mapInstr:
+            mapInstr = self.settings.FindInstructionByType('initMap')
+        mapId = mapInstr.id
+        if toCenter:
+            center = self.instruction['rect'].GetCentre()
+            ENCenter = PaperMapCoordinates(map = self.settings[mapId],
+                                           x = center[0], y = center[1], paperToMap = True)
+                                           
+            self.instruction['east'], self.instruction['north'] = ENCenter
+        else:
+            x, y = PaperMapCoordinates(map = self.settings[mapId], x = self.instruction['east'],
+                                       y = self.instruction['north'], paperToMap = False)
+            w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
+            h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
+            x -= w * self.instruction['scale'] / 2
+            y -= h * self.instruction['scale'] / 2
+            e, n = PaperMapCoordinates(map = self.settings[mapId], x = x, y = y, paperToMap = True)
+            self.instruction['east'], self.instruction['north'] = e, n
+
+    def GetImageOrigSize(self, imagePath):
+        """!Get image size.
+        
+        If eps, size is read from image header.
+        """
+        fileName = os.path.split(imagePath)[1]
+        # if eps, read info from header
+        if os.path.splitext(fileName)[1].lower() == '.eps':
+            bbInfo = "%%BoundingBox"
+            file = open(imagePath,"r")
+            w = h = 0
+            while file:
+                line = file.readline()
+                if line.find(bbInfo) == 0:
+                    w, h = line.split()[3:5]
+                    break
+            file.close()
+            return float(w), float(h)
+        else: # we can use wx.Image
+            img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
+            return img.GetWidth(), img.GetHeight()
+            
+class NorthArrow(Image):
+    """!Class representing eps instruction -- North Arrow"""
+    def __init__(self, id, settings):
+        Image.__init__(self, id = id, settings = settings)
+        self.type = 'northArrow'
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += "# north arrow\n"
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+        
+class Scalebar(InstructionObject):
+    """!Class representing scalebar instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'scalebar'
+        # default values
+        self.defaultInstruction = dict(unit = 'inch', where = (1,1),
+                                       unitsLength = 'auto', unitsHeight = 'inch',
+                                       length = None, height = 0.1, rect = None,
+                                       fontsize = 10, background = 'y',
+                                       scalebar = 'f', segment = 4, numbers = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("scalebar $scalebar\n").substitute(self.instruction)
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    length $length\n    units $unitsLength\n").substitute(self.instruction)
+        instr += string.Template("    height $height\n").substitute(self.instruction)
+        instr += string.Template("    segment $segment\n    numbers $numbers\n").substitute(self.instruction)
+        instr += string.Template("    fontsize $fontsize\n    background $background\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        scale = kwargs['scale']
+        instr = {}
+        for line in text:
+            try:
+                if line.startswith('scalebar'):
+                    if 'scalebar s' in line:
+                        instr['scalebar'] = 's'
+                    else:
+                        instr['scalebar'] = 'f'
+                elif line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('length'):
+                    instr['length'] = float(line.split()[1])
+                elif line.startswith('units'):
+                    if line.split()[1] in ['auto', 'meters', 'kilometers', 'feet', 'miles', 'nautmiles']:
+                        instr['unitsLength'] = line.split()[1]
+                elif line.startswith('height'):
+                    instr['height'] = float(line.split()[1])
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('numbers'):
+                    instr['numbers'] = int(line.split()[1])
+                elif line.startswith('segment'):
+                    instr['segment'] = int(line.split()[1])
+                elif line.startswith('background'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['background'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['background'] = 'n'
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        self.instruction.update(instr)
+        w, h = self.EstimateSize(scalebarDict = self.instruction, scale = scale)
+        x = self.instruction['where'][0] - w / 2 
+        y = self.instruction['where'][1] - h / 2
+        self.instruction['rect'] = wx.Rect2D(x, y, w, h)
+        return True 
+    
+    def EstimateSize(self, scalebarDict, scale):
+        """!Estimate size to draw scalebar"""
+        units = projInfo()['units']
+        if not units or units not in self.unitConv.getAllUnits():
+            units = 'meters'
+        if scalebarDict['unitsLength'] != 'auto':
+            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = scalebarDict['unitsLength'], toUnit = 'inch')
+        else:
+            length = self.unitConv.convert(value = scalebarDict['length'], fromUnit = units, toUnit = 'inch')
+            
+        length *= scale
+        length *= 1.1 #for numbers on the edge
+        height = scalebarDict['height'] + 2 * self.unitConv.convert(value = scalebarDict['fontsize'], fromUnit = 'point', toUnit = 'inch')     
+        return (length, height)
+    
+class RasterLegend(InstructionObject):
+    """!Class representing colortable instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'rasterLegend'
+        # default values
+        self.defaultInstruction = dict(rLegend = False, unit = 'inch', rasterDefault = True, raster = None,
+                                       discrete = None, type = None,
+                                       where = (0, 0),
+                                       width = None, height = None, cols = 1, font = "Helvetica", fontsize = 10,
+                                       #color = '0:0:0', tickbar = False, range = False, min = 0, max = 0,
+                                       color = 'black', tickbar = 'n', range = False, min = 0, max = 0,
+                                       nodata = 'n')
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "colortable y\n"
+        instr += string.Template("    raster $raster\n").substitute(self.instruction)
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        if self.instruction['width']:
+            instr += string.Template("    width $width\n").substitute(self.instruction)
+        instr += string.Template("    discrete $discrete\n").substitute(self.instruction)
+        if self.instruction['discrete'] == 'n':
+            if self.instruction['height']:
+                instr += string.Template("    height $height\n").substitute(self.instruction)
+            instr += string.Template("    tickbar $tickbar\n").substitute(self.instruction)
+            if self.instruction['range']:
+                instr += string.Template("    range $min $max\n").substitute(self.instruction)
+        else:
+            instr += string.Template("    cols $cols\n").substitute(self.instruction)
+            instr += string.Template("    nodata $nodata\n").substitute(self.instruction)
+        instr += string.Template("    font $font\n    fontsize $fontsize\n    color $color\n")\
+            .substitute(self.instruction)
+        instr += "    end"
+        return instr    
+    
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['rLegend'] = True
+        for line in text:
+            try:
+                if line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('font '):
+                    instr['font'] = line.split()[1]
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('color '):
+                    instr['color'] = line.split()[1]
+                elif line.startswith('raster'):
+                    instr['raster'] = line.split()[1]
+                elif line.startswith('width'):
+                    instr['width'] = float(line.split()[1])
+                elif line.startswith('height'):
+                    instr['height'] = float(line.split()[1])
+                elif line.startswith('cols'):
+                    instr['cols'] = int(line.split()[1])                    
+                elif line.startswith('range'):
+                    instr['range'] = True
+                    instr['min'] = float(line.split()[1])
+                    instr['max'] = float(line.split()[2])
+                elif line.startswith('nodata'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['nodata'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['nodata'] = 'n'
+                elif line.startswith('tickbar'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['tickbar'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['tickbar'] = 'n'
+                elif line.startswith('discrete'):
+                    if line.split()[1].strip().lower() in ('y','yes'):
+                        instr['discrete'] = 'y'
+                    elif line.split()[1].strip().lower() in ('n','no', 'none'):
+                        instr['discrete'] = 'n'            
+
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        if 'raster' in instr:
+            instr['rasterDefault'] = False
+            if 'discrete' not in instr:
+                rasterType = getRasterType(map = instr['raster'])
+                instr['type'] = rasterType
+                if rasterType == 'CELL':
+                    instr['discrete'] = 'y'
+                else:
+                    instr['discrete'] = 'n'
+            
+        else:
+            instr['rasterDefault'] = True
+        self.instruction.update(instr)
+        # add 'rect' in the end
+            
+        return True 
+    
+    def EstimateHeight(self, raster, discrete, fontsize, cols = None,  height = None):
+        """!Estimate height to draw raster legend"""
+        if discrete == 'n':
+            if height:
+                height = height
+            else:
+                height = self.unitConv.convert(value = fontsize * 10,
+                                                    fromUnit = 'point', toUnit = 'inch')
+                                                    
+        if discrete == 'y':
+            if cols:
+                cols = cols 
+            else:
+                cols = 1 
+
+            rinfo = grass.raster_info(raster)
+            if rinfo['datatype'] in ('DCELL', 'FCELL'):
+                minim, maxim = rinfo['min'], rinfo['max']
+                rows = ceil(maxim / cols )
+            else:
+                cat = grass.read_command('r.category', map = raster,
+                                    fs = ':').strip().split('\n')
+                rows = ceil(float(len(cat)) / cols )
+                            
+                
+            height = self.unitConv.convert(value =  1.5 * rows * fontsize, fromUnit = 'point', toUnit = 'inch')
+            
+        return height
+        
+    def EstimateWidth(self, raster, discrete, fontsize, cols = None, width = None, paperInstr = None):
+        """!Estimate size to draw raster legend"""
+        
+        if discrete == 'n':
+            rinfo = grass.raster_info(raster)
+            minim, maxim = rinfo['min'], rinfo['max']
+            if width:
+                width = width
+            else:
+                width = self.unitConv.convert(value = fontsize * 2,
+                                                    fromUnit = 'point', toUnit = 'inch')
+            text = len(max(str(minim), str(maxim), key = len))
+            textPart = self.unitConv.convert(value = text * fontsize / 2,
+                                                    fromUnit = 'point', toUnit = 'inch')
+            width += textPart
+                                                    
+        elif discrete == 'y':
+            if cols:
+                cols = cols 
+            else:
+                cols = 1    
+
+            if width:
+                width = width
+            else:
+                paperWidth = paperInstr['Width'] - paperInstr['Right'] - paperInstr['Left']
+                width = (paperWidth / cols) * (cols - 1) + 1
+                
+        return width    
+             
+class VectorLegend(InstructionObject):
+    """!Class representing colortable instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vectorLegend'
+        # default values
+        self.defaultInstruction = dict(vLegend = False, unit = 'inch', where = (0, 0),
+                                                defaultSize = True, width = 0.4, cols = 1, span = None,
+                                                font = "Helvetica", fontsize = 10,
+                                                border = 'none')
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = "vlegend\n"
+        instr += "    where %.3f %.3f\n" % (self.instruction['where'][0], self.instruction['where'][1])
+        instr += string.Template("    font $font\n    fontsize $fontsize\n").substitute(self.instruction)
+        instr += string.Template("    width $width\n    cols $cols\n").substitute(self.instruction)
+        if self.instruction['span']:
+            instr += string.Template("    span $span\n").substitute(self.instruction)
+        instr += string.Template("    border $border\n").substitute(self.instruction)  
+        instr += "    end"  
+        return instr
+
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['vLegend'] = True
+        for line in text:
+            try:
+                if line.startswith('where'):
+                    instr['where'] = map(float, line.split()[1:3])
+                elif line.startswith('font '):
+                    instr['font'] = line.split()[1]
+                elif line.startswith('fontsize'):
+                    instr['fontsize'] = float(line.split()[1])
+                elif line.startswith('width'):
+                    instr['width'] = float(line.split()[1])
+                elif line.startswith('cols'):
+                    instr['cols'] = int(line.split()[1]) 
+                elif line.startswith('span'):
+                    instr['span'] = float(line.split()[1])
+                elif line.startswith('border'):
+                    instr['border'] = line.split()[1]
+                    
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+            
+        self.instruction.update(instr)
+            
+        return True 
+    
+    def EstimateSize(self, vectorInstr, fontsize, width = None, cols = None):
+        """!Estimate size to draw vector legend"""
+        if width:
+            width = width 
+        else:
+            width = fontsize/24.0
+
+        if cols:
+            cols = cols 
+        else:
+            cols = 1
+
+        vectors = vectorInstr['list']
+        labels = [vector[4] for vector in vectors if vector[3] != 0]
+        extent = (len(max(labels, key = len)) * fontsize / 2, fontsize)
+        wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'point', toUnit = 'inch')
+        hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'point', toUnit = 'inch')
+        w = (width + wExtent) * cols
+        h = len(labels) * hExtent / cols
+        h *= 1.1
+        return (w, h)
+            
+   
+class Raster(InstructionObject):
+    """!Class representing raster instruction"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'raster'
+        # default values
+        self.defaultInstruction = dict(isRaster = False, raster = None)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        instr = string.Template("raster $raster").substitute(self.instruction)
+        return instr
+    
+    def Read(self, instruction, text):
+        """!Read instruction and save information"""
+        instr = {}
+        instr['isRaster'] = True
+        try:
+            map = text.split()[1]
+        except IndexError:
+            GError(_("Failed to read instruction %s") % instruction)
+            return False
+        try:
+            info = grass.find_file(map, element = 'cell')
+        except grass.ScriptError, e:
+            GError(message = e.value)
+            return False
+        instr['raster'] = info['fullname']
+
+        
+        self.instruction.update(instr)
+        return True
+    
+class Vector(InstructionObject):
+    """!Class keeps vector layers"""
+    def __init__(self, id):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vector'
+        # default values
+        self.defaultInstruction = dict(list = None)# [vmap, type, id, lpos, label] 
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+    def __str__(self):
+        return ''
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        
+        for line in text:
+            if line.startswith('vpoints') or line.startswith('vlines') or line.startswith('vareas'):
+                # subtype
+                if line.startswith('vpoints'):
+                    subType = 'points'
+                elif line.startswith('vlines'):
+                    subType = 'lines'
+                elif line.startswith('vareas'):
+                    subType = 'areas'
+                # name of vector map
+                vmap = line.split()[1]
+                try:
+                    info = grass.find_file(vmap, element = 'vector')
+                except grass.ScriptError, e:
+                    GError(message = e.value)
+                    return False
+                vmap = info['fullname']
+                # id
+                id = kwargs['id']
+                # lpos
+                lpos = kwargs['vectorMapNumber']
+                #label
+                label = '('.join(vmap.split('@')) + ')'
+                break
+        instr = [vmap, subType, id, lpos, label] 
+        if not self.instruction['list']:
+            self.instruction['list'] = []
+        self.instruction['list'].append(instr)
+        
+        return True    
+    
+class VProperties(InstructionObject):
+    """!Class represents instructions vareas, vlines, vpoints"""
+    def __init__(self, id, subType):
+        InstructionObject.__init__(self, id = id)
+        self.type = 'vProperties'
+        self.subType = subType
+        # default values
+        if self.subType == 'points':
+            dd = dict(subType  = 'points', name = None, type = 'point or centroid', connection = False, layer = '1',
+                        masked = 'n', color = '0:0:0', width = 1,
+                        fcolor = '255:0:0', rgbcolumn = None, symbol = os.path.join('basic', 'x'), eps = None,
+                        size = 5, sizecolumn = None, scale = None,
+                        rotation = False, rotate = 0, rotatecolumn = None, label = None, lpos = None)
+        elif self.subType == 'lines':
+            dd = dict(subType = 'lines', name = None, type = 'line or boundary', connection = False, layer = '1',
+                        masked = 'n', color = '0:0:0', hwidth = 1,
+                        hcolor = 'none', rgbcolumn = None,
+                        width = 1, cwidth = None,
+                        style = 'solid', linecap = 'butt', label = None, lpos = None)
+        else: # areas
+            dd = dict(subType = 'areas', name = None, connection = False, layer = '1',    
+                        masked = 'n', color = '0:0:0', width = 1,
+                        fcolor = 'none', rgbcolumn = None,
+                        pat = None, pwidth = 1, scale = 1, label = None, lpos = None)
+        self.defaultInstruction = dd
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        dic = self.instruction
+        vInstruction = string.Template("v$subType $name\n").substitute(dic)
+        #data selection
+        if self.subType in ('points', 'lines'):
+           vInstruction += string.Template("    type $type\n").substitute(dic) 
+        if dic['connection']:
+            vInstruction += string.Template("    layer $layer\n").substitute(dic)
+            if dic.has_key('cats'):
+                vInstruction += string.Template("    cats $cats\n").substitute(dic)
+            elif dic.has_key('where'):
+                    vInstruction += string.Template("    where $where\n").substitute(dic)
+        vInstruction += string.Template("    masked $masked\n").substitute(dic)
+        #colors
+        vInstruction += string.Template("    color $color\n").substitute(dic)
+        if self.subType in ('points', 'areas'):
+            if dic['color'] != 'none':
+                vInstruction += string.Template("    width $width\n").substitute(dic)
+            if dic['rgbcolumn']:
+                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
+            vInstruction += string.Template("    fcolor $fcolor\n").substitute(dic)
+        else:
+            if dic['rgbcolumn']:
+                vInstruction += string.Template("    rgbcolumn $rgbcolumn\n").substitute(dic)
+            elif dic['hcolor'] != 'none':
+                vInstruction += string.Template("    hwidth $hwidth\n").substitute(dic)
+                vInstruction += string.Template("    hcolor $hcolor\n").substitute(dic)
+        
+        # size and style
+        if self.subType == 'points':
+            if dic['symbol']:
+                vInstruction += string.Template("    symbol $symbol\n").substitute(dic)
+            else: #eps
+                vInstruction += string.Template("    eps $eps\n").substitute(dic)
+            if dic['size']:
+                vInstruction += string.Template("    size $size\n").substitute(dic)            
+            else: # sizecolumn
+                vInstruction += string.Template("    sizecolumn $sizecolumn\n").substitute(dic)
+                vInstruction += string.Template("    scale $scale\n").substitute(dic)
+            if dic['rotation']:
+                if dic['rotate'] is not None:
+                    vInstruction += string.Template("    rotate $rotate\n").substitute(dic)
+                else:
+                    vInstruction += string.Template("    rotatecolumn $rotatecolumn\n").substitute(dic)
+                    
+        if self.subType == 'areas':
+            if dic['pat'] is not None:
+                vInstruction += string.Template("    pat $pat\n").substitute(dic)
+                vInstruction += string.Template("    pwidth $pwidth\n").substitute(dic)
+                vInstruction += string.Template("    scale $scale\n").substitute(dic)
+                
+        if self.subType == 'lines':
+            if dic['width'] is not None:
+                vInstruction += string.Template("    width $width\n").substitute(dic)
+            else:
+                vInstruction += string.Template("    cwidth $cwidth\n").substitute(dic)
+            vInstruction += string.Template("    style $style\n").substitute(dic)
+            vInstruction += string.Template("    linecap $linecap\n").substitute(dic)
+        #position and label in vlegend
+        vInstruction += string.Template("    label $label\n    lpos $lpos\n").substitute(dic)
+        
+        vInstruction += "    end"
+        return vInstruction
+    
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        instr = {}
+        try:
+            info = grass.find_file(name = text[0].split()[1], element = 'vector')
+        except grass.ScriptError, e:
+            GError(message = e.value)
+            return False
+        instr['name'] = info['fullname']
+        #connection
+        instr['connection'] = True
+        self.mapDBInfo = VectorDBInfo(instr['name'])
+        self.layers = self.mapDBInfo.layers.keys()
+        if not self.layers:
+            instr['connection'] = False
+            
+        # points
+        if text[0].startswith('vpoints'):
+            for line in text[1:]:
+                if line.startswith('type'):
+                    tp = []
+                    if line.find('point') != -1:
+                        tp.append('point')
+                    if line.find('centroid') != -1:
+                        tp.append('centroid')
+                    instr['type'] = ' or '.join(tp)
+                elif line.startswith('fcolor'):
+                    instr['fcolor'] = line.split()[1]
+                elif line.startswith('rgbcolumn'):
+                    instr['rgbcolumn'] = line.split()[1]
+                elif line.startswith('symbol'):
+                    instr['symbol'] = line.split()[1]
+                elif line.startswith('eps'):
+                    instr['eps'] = line.split()[1]
+                elif line.startswith('size '):
+                    instr['size'] = line.split()[1]
+                elif line.startswith('sizecolumn'):
+                    instr['size'] = None
+                    instr['sizecolumn'] = line.split()[1]
+                elif line.startswith('scale '):
+                    instr['scale'] = float(line.split()[1])
+                elif line.startswith('rotate '):
+                    instr['rotation'] = True
+                    instr['rotate'] = line.split()[1]
+                elif line.startswith('rotatecolumn'):
+                    instr['rotatecolumn'] = line.split()[1]
+                    instr['rotation'] = True
+                    instr['rotate'] = None
+                    
+        # lines            
+        elif text[0].startswith('vlines'):
+            for line in text[1:]:
+                if line.startswith('type'):
+                    tp = []
+                    if line.find('line') != -1:
+                        tp.append('line')
+                    if line.find('boundary') != -1:
+                        tp.append('boundary')
+                    instr['type'] = ' or '.join(tp)
+                elif line.startswith('hwidth'):
+                    instr['hwidth'] = float(line.split()[1])
+                elif line.startswith('hcolor'):
+                    instr['hcolor'] = line.split()[1]
+                elif line.startswith('rgbcolumn'):
+                    instr['rgbcolumn'] = line.split()[1]                    
+                elif line.startswith('cwidth'):
+                    instr['cwidth'] = float(line.split()[1])
+                    instr['width'] = None
+                elif line.startswith('style'):
+                    instr['style'] = line.split()[1]       
+                elif line.startswith('linecap'):
+                    instr['linecap'] = line.split()[1]
+         
+        elif text[0].startswith('vareas'):
+            for line in text[1:]:
+                if line.startswith('fcolor'):
+                    instr['fcolor'] = line.split()[1]    
+                elif line.startswith('pat'):
+                    instr['pat'] = line.split()[1]
+                elif line.startswith('pwidth'):
+                    instr['pwidth'] = float(line.split()[1])
+                elif line.startswith('scale'):
+                    instr['scale'] = float(line.split()[1])
+            
+            
+        # same properties for all    
+        for line in text[1:]:
+            if line.startswith('lpos'):
+                instr['lpos'] = int(line.split()[1])
+            elif line.startswith('label'):
+                instr['label'] = line.split(None, 1)[1]
+            elif line.startswith('layer'):
+                instr['layer'] = line.split()[1]
+            elif line.startswith('masked'):
+                if line.split()[1].lower() in ('y', 'yes'):
+                    instr['masked'] = 'y'
+                else:
+                    instr['masked'] = 'n'
+            elif line.startswith('color'):
+                instr['color'] = line.split()[1]
+            elif line.startswith('rgbcolumn'):
+                instr['rgbcolumn'] = line.split()[1] 
+            elif line.startswith('width'):
+                instr['width'] = float(line.split()[1])
+                
+        if 'label' not in instr:
+            instr['label'] = '('.join(instr['name'].split('@')) + ')'
+        if 'lpos' not in instr:
+            instr['lpos'] = kwargs['vectorMapNumber']
+        self.instruction.update(instr)
+        
+        return True
+        
+class PsmapDialog(wx.Dialog):
+    def __init__(self, parent, id,  title, settings, apply = True):
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, 
+                            title = title, size = wx.DefaultSize,
+                            style = wx.CAPTION|wx.MINIMIZE_BOX|wx.CLOSE_BOX)
+        self.apply = apply
+        self.id = id
+        self.parent = parent
+        self.instruction = settings
+        self.objectType = None
+        self.unitConv = UnitConversion(self)
+        self.spinCtrlSize = (65, -1)
+        
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        
+    
+        
+    def AddUnits(self, parent, dialogDict):
+        parent.units = dict()
+        parent.units['unitsLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Units:"))
+        choices = self.unitConv.getPageUnitsNames()
+        parent.units['unitsCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = choices)  
+        parent.units['unitsCtrl'].SetStringSelection(self.unitConv.findName(dialogDict['unit']))
+          
+    def AddPosition(self, parent, dialogDict):
+        if not hasattr(parent, "position"):
+            parent.position = dict()
+        parent.position['comment'] = wx.StaticText(parent, id = wx.ID_ANY,\
+                    label = _("Position of the top left corner\nfrom the top left edge of the paper"))
+        parent.position['xLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("X:"))
+        parent.position['yLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Y:"))
+        parent.position['xCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][0]), validator = TCValidator(flag = 'DIGIT_ONLY'))
+        parent.position['yCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][1]), validator = TCValidator(flag = 'DIGIT_ONLY'))
+        if dialogDict.has_key('unit'):
+            x = self.unitConv.convert(value = dialogDict['where'][0], fromUnit = 'inch', toUnit = dialogDict['unit'])
+            y = self.unitConv.convert(value = dialogDict['where'][1], fromUnit = 'inch', toUnit = dialogDict['unit'])
+            parent.position['xCtrl'].SetValue("%5.3f" % x)
+            parent.position['yCtrl'].SetValue("%5.3f" % y)
+        
+    def AddExtendedPosition(self, panel, gridBagSizer, dialogDict):
+        """!Add widgets for setting position relative to paper and to map"""
+        panel.position = dict()
+        positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
+        panel.position['toPaper'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
+        panel.position['toMap'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
+        panel.position['toPaper'].SetValue(dialogDict['XY'])
+        panel.position['toMap'].SetValue(not dialogDict['XY'])
+        
+        gridBagSizer.Add(positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toPaper'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toMap'], pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        
+        # first box - paper coordinates
+        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
+        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerP.AddGrowableCol(1)
+        self.gridBagSizerP.AddGrowableRow(3)
+        
+        self.AddPosition(parent = panel, dialogDict = dialogDict)
+        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
+        self.AddUnits(parent = panel, dialogDict = dialogDict)
+        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
+        
+        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+        
+        # second box - map coordinates
+        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
+        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerM.AddGrowableCol(0)
+        self.gridBagSizerM.AddGrowableCol(1)
+        
+        eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
+        northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
+        panel.position['eCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        panel.position['nCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
+        panel.position['eCtrl'].SetValue(str(east))
+        panel.position['nCtrl'].SetValue(str(north))
+        
+        self.gridBagSizerM.Add(eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['eCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['nCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+        
+    def AddFont(self, parent, dialogDict, color = True):
+        parent.font = dict()
+##        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:"))
+##        parent.font['fontCtrl'] = wx.FontPickerCtrl(parent, id = wx.ID_ANY)
+##        
+##        parent.font['fontCtrl'].SetSelectedFont(
+##                        wx.FontFromNativeInfoString(dialogDict['font'] + " " + str(dialogDict['fontsize'])))
+##        parent.font['fontCtrl'].SetMaxPointSize(50)
+##        
+##        if color:
+##            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
+##            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY, style=wx.FNTP_FONTDESC_AS_LABEL)
+##            parent.font['colorCtrl'].SetColour(dialogDict['color'])
+           
+##        parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color'])) 
+           
+        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font:"))
+        parent.font['fontSizeLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font size:"))
+        fontChoices = [ 'Times-Roman', 'Times-Italic', 'Times-Bold', 'Times-BoldItalic', 'Helvetica',\
+                        'Helvetica-Oblique', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Courier',\
+                        'Courier-Oblique', 'Courier-Bold', 'Courier-BoldOblique'] 
+        parent.font['fontCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = fontChoices)
+        if dialogDict['font'] in fontChoices:
+            parent.font['fontCtrl'].SetStringSelection(dialogDict['font'])
+        else:
+            parent.font['fontCtrl'].SetStringSelection('Helvetica')
+        parent.font['fontSizeCtrl'] = wx.SpinCtrl(parent, id = wx.ID_ANY, min = 4, max = 50, initial = 10)
+        parent.font['fontSizeCtrl'].SetValue(dialogDict['fontsize'])
+         
+        if color:
+            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
+            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
+            parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color']))
+##            parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Color:"))
+##            colorChoices = [  'aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'green', 'indigo', 'magenta',\
+##                                'orange', 'purple', 'red', 'violet', 'white', 'yellow']
+##            parent.colorCtrl = wx.Choice(parent, id = wx.ID_ANY, choices = colorChoices)
+##            parent.colorCtrl.SetStringSelection(parent.rLegendDict['color'])
+##            parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
+##            parent.font['colorCtrl'].SetColour(dialogDict['color'])   
+    def OnApply(self, event):
+        ok = self.update()
+        if ok:
+            self.parent.DialogDataChanged(id = self.id)
+            return True 
+        else:
+            return False
+        
+    def OnOK(self, event):
+        """!Apply changes, close dialog"""
+        ok = self.OnApply(event)
+        if ok:
+            self.Close()
+    
+    def OnCancel(self, event):
+        """!Close dialog"""
+        self.Close()
+
+    def OnClose(self, event):
+        """!Destroy dialog and delete it from open dialogs"""
+        if self.objectType:
+            for each in  self.objectType:
+                if each in self.parent.openDialogs:
+                    del self.parent.openDialogs[each]
+        event.Skip()
+        self.Destroy()
+        
+    def _layout(self, panel):
+        #buttons
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnOK = wx.Button(self, wx.ID_OK)
+        btnOK.SetDefault()
+        if self.apply:
+            btnApply = wx.Button(self, wx.ID_APPLY)
+        
+
+        # bindigs
+        btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
+        btnOK.SetToolTipString(_("Close dialog and apply changes"))
+        #btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        if self.apply:
+            btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+            btnApply.SetToolTipString(_("Apply changes"))
+        
+        # sizers
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        if self.apply:
+            btnSizer.AddButton(btnApply)
+        btnSizer.AddButton(btnOK)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = panel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Layout()
+        mainSizer.Fit(self) 
+            
+class PageSetupDialog(PsmapDialog):
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Page setup",  settings = settings)
+        
+        self.cat = ['Units', 'Format', 'Orientation', 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+        labels = [_('Units'), _('Format'), _('Orientation'), _('Width'), _('Height'),
+                  _('Left'), _('Right'), _('Top'), _('Bottom')]
+        self.catsLabels = dict(zip(self.cat, labels))
+        paperString = RunCommand('ps.map', flags = 'p', read = True, quiet = True)
+        self.paperTable = self._toList(paperString) 
+        self.unitsList = self.unitConv.getPageUnitsNames()
+        self.pageSetupDict = settings[id].GetInstruction()
+
+        self._layout()
+        
+        if self.pageSetupDict:
+            self.getCtrl('Units').SetStringSelection(self.unitConv.findName(self.pageSetupDict['Units']))
+            if self.pageSetupDict['Format'] == 'custom':
+                self.getCtrl('Format').SetSelection(self.getCtrl('Format').GetCount() - 1)
+            else:
+                self.getCtrl('Format').SetStringSelection(self.pageSetupDict['Format'])
+            if self.pageSetupDict['Orientation'] == 'Portrait':
+                self.getCtrl('Orientation').SetSelection(0)
+            else:
+                self.getCtrl('Orientation').SetSelection(1)
+                
+            for item in self.cat[3:]:
+                val = self.unitConv.convert(value = self.pageSetupDict[item],
+                                            fromUnit = 'inch', toUnit = self.pageSetupDict['Units'])
+                self.getCtrl(item).SetValue("%4.3f" % val)
+
+       
+        if self.getCtrl('Format').GetSelection() != self.getCtrl('Format').GetCount() - 1: # custom
+            self.getCtrl('Width').Disable()
+            self.getCtrl('Height').Disable()
+        else:
+            self.getCtrl('Orientation').Disable()
+        # events
+        self.getCtrl('Units').Bind(wx.EVT_CHOICE, self.OnChoice)
+        self.getCtrl('Format').Bind(wx.EVT_CHOICE, self.OnChoice)
+        self.getCtrl('Orientation').Bind(wx.EVT_CHOICE, self.OnChoice)
+        self.btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
+
+    
+    def update(self):
+        self.pageSetupDict['Units'] = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
+        self.pageSetupDict['Format'] = self.paperTable[self.getCtrl('Format').GetSelection()]['Format']
+        if self.getCtrl('Orientation').GetSelection() == 0:
+            self.pageSetupDict['Orientation'] = 'Portrait'
+        else:
+            self.pageSetupDict['Orientation'] = 'Landscape'
+        for item in self.cat[3:]:
+            self.pageSetupDict[item] = self.unitConv.convert(value = float(self.getCtrl(item).GetValue()),
+                                        fromUnit = self.pageSetupDict['Units'], toUnit = 'inch')
+            
+
+            
+    def OnOK(self, event):
+        try:
+            self.update()
+        except ValueError:
+                wx.MessageBox(message = _("Literal is not allowed!"), caption = _('Invalid input'),
+                                    style = wx.OK|wx.ICON_ERROR)
+        else:
+            event.Skip()
+        
+    def _layout(self):
+        size = (110,-1)
+        #sizers
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        pageBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Page size"))
+        pageSizer = wx.StaticBoxSizer(pageBox, wx.VERTICAL)
+        marginBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Margins"))
+        marginSizer = wx.StaticBoxSizer(marginBox, wx.VERTICAL)
+        horSizer = wx.BoxSizer(wx.HORIZONTAL) 
+        #staticText + choice
+        choices = [self.unitsList, [item['Format'] for item in self.paperTable], [_('Portrait'), _('Landscape')]]
+        propor = [0,1,1]
+        border = [5,3,3]
+        self.hBoxDict={}
+        for i, item in enumerate(self.cat[:3]):
+            hBox = wx.BoxSizer(wx.HORIZONTAL)
+            stText = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
+            choice = wx.Choice(self, id = wx.ID_ANY, choices = choices[i], size = size)
+            hBox.Add(stText, proportion = propor[i], flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = border[i])
+            hBox.Add(choice, proportion = 0, flag = wx.ALL, border = border[i])
+            if item == 'Units':
+                hBox.Add(size,1) 
+            self.hBoxDict[item] = hBox    
+
+        #staticText + TextCtrl
+        for item in self.cat[3:]:
+            hBox = wx.BoxSizer(wx.HORIZONTAL)
+            label = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
+            textctrl = wx.TextCtrl(self, id = wx.ID_ANY, size = size, value = '')
+            hBox.Add(label, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
+            hBox.Add(textctrl, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 3)
+            self.hBoxDict[item] = hBox
+         
+        sizer = list([mainSizer] + [pageSizer]*4 + [marginSizer]*4)
+        for i, item in enumerate(self.cat):
+                sizer[i].Add(self.hBoxDict[item], 0, wx.GROW|wx.RIGHT|wx.LEFT,5)
+        # OK button
+        btnSizer = wx.StdDialogButtonSizer()
+        self.btnOk = wx.Button(self, wx.ID_OK)
+        self.btnOk.SetDefault()
+        btnSizer.AddButton(self.btnOk)
+        btn = wx.Button(self, wx.ID_CANCEL)
+        btnSizer.AddButton(btn)
+        btnSizer.Realize()
+    
+    
+        horSizer.Add(pageSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM, border = 10)
+        horSizer.Add(marginSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND, border = 10)
+        mainSizer.Add(horSizer, proportion = 0, border = 10)  
+        mainSizer.Add(btnSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL,  border = 10)      
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+    
+    def OnChoice(self, event):
+        currPaper = self.paperTable[self.getCtrl('Format').GetSelection()]
+        currUnit = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
+        currOrientIdx = self.getCtrl('Orientation').GetSelection()
+        newSize = dict()
+        for item in self.cat[3:]:
+            newSize[item] = self.unitConv.convert(float(currPaper[item]), fromUnit = 'inch', toUnit = currUnit)
+
+        enable = True
+        if currPaper['Format'] != _('custom'):
+            if currOrientIdx == 1: # portrait
+                newSize['Width'], newSize['Height'] = newSize['Height'], newSize['Width']
+            for item in self.cat[3:]:
+                self.getCtrl(item).ChangeValue("%4.3f" % newSize[item])
+            enable = False
+        self.getCtrl('Width').Enable(enable)
+        self.getCtrl('Height').Enable(enable)
+        self.getCtrl('Orientation').Enable(not enable)
+
+
+    def getCtrl(self, item):
+         return self.hBoxDict[item].GetItem(1).GetWindow()
+        
+    def _toList(self, paperStr):
+        
+        sizeList = list()
+        for line in paperStr.strip().split('\n'):
+            d = dict(zip([self.cat[1]]+ self.cat[3:],line.split()))
+            sizeList.append(d)
+        d = {}.fromkeys([self.cat[1]]+ self.cat[3:], 100)
+        d.update(Format = _('custom'))
+        sizeList.append(d)
+        return sizeList
+    
+class MapDialog(PsmapDialog):
+    """!Dialog for map frame settings and optionally  raster and vector map selection"""
+    def __init__(self, parent, id, settings,  rect = None, notebook = False):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "", settings = settings)
+ 
+        self.isNotebook = notebook
+        if self.isNotebook:
+            self.objectType = ('mapNotebook',) 
+        else:
+            self.objectType = ('map',)
+
+        
+        #notebook
+        if self.isNotebook:
+            self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+            self.mPanel = MapFramePanel(parent = self.notebook, id = self.id[0], settings = self.instruction, 
+                                        rect = rect, notebook = True)
+            self.id[0] = self.mPanel.getId()
+            self.rPanel = RasterPanel(parent = self.notebook, id = self.id[1], settings = self.instruction, 
+                                        notebook = True)
+            self.id[1] = self.rPanel.getId()
+            self.vPanel = VectorPanel(parent = self.notebook, id = self.id[2], settings = self.instruction,
+                                        notebook = True)
+            self.id[2] = self.vPanel.getId()
+            self._layout(self.notebook)
+            self.SetTitle(_("Map settings"))
+        else:
+            self.mPanel = MapFramePanel(parent = self, id = self.id[0], settings = self.instruction, 
+                                        rect = rect, notebook = False)
+            self.id[0] = self.mPanel.getId()
+            self._layout(self.mPanel)
+            self.SetTitle(_("Map frame settings"))
+        
+        
+    def OnApply(self, event):
+        """!Apply changes"""
+        if self.isNotebook:
+            okV = self.vPanel.update()
+            okR = self.rPanel.update()
+            if okV and self.id[2] in self.instruction:
+                self.parent.DialogDataChanged(id = self.id[2])
+            if okR and self.id[1] in self.instruction:
+                self.parent.DialogDataChanged(id = self.id[1])
+            if not okR or not okV:
+                return False
+
+        ok = self.mPanel.update()
+        if ok:
+            self.parent.DialogDataChanged(id = self.id[0])
+            return True 
+        
+        return False
+    
+    def OnCancel(self, event):
+        """!Close dialog and remove tmp red box"""
+        self.parent.canvas.pdcTmp.RemoveId(self.parent.canvas.idZoomBoxTmp)
+        self.parent.canvas.Refresh() 
+        self.Close()
+        
+    def updateDialog(self):
+        """!Update raster and vector information"""
+        if self.mPanel.scaleChoice.GetSelection() == 0:
+            if self.mPanel.rasterTypeRadio.GetValue():
+                if 'raster' in self.parent.openDialogs:
+                    if self.parent.openDialogs['raster'].rPanel.rasterYesRadio.GetValue() and \
+                            self.parent.openDialogs['raster'].rPanel.rasterSelect.GetValue() == self.mPanel.select.GetValue():
+                            self.mPanel.drawMap.SetValue(True)
+                    else:
+                        self.mPanel.drawMap.SetValue(False)
+            else:
+                if 'vector' in self.parent.openDialogs:
+                    found = False
+                    for each in self.parent.openDialogs['vector'].vPanel.vectorList:
+                        if each[0] == self.mPanel.select.GetValue():
+                            found = True
+                    self.mPanel.drawMap.SetValue(found)    
+                        
+class MapFramePanel(wx.Panel):
+    """!wx.Panel with map (scale, region, border) settings"""
+    def __init__(self, parent, id, settings, rect, notebook = True):
+        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+
+        self.id = id
+        self.instruction = settings
+        
+        if notebook:
+            self.book = parent
+            self.book.AddPage(page = self, text = _("Map frame"))
+            self.mapDialog = self.book.GetParent()
+        else:
+            self.mapDialog = parent
+            
+        if self.id is not None:
+            self.mapFrameDict = self.instruction[self.id].GetInstruction() 
+        else:
+            self.id = wx.NewId()
+            mapFrame = MapFrame(self.id)
+            self.mapFrameDict = mapFrame.GetInstruction()
+            self.mapFrameDict['rect'] = rect
+
+            
+        self._layout()
+
+        self.scale = [None]*4
+        self.center = [None]*4
+        
+        
+        
+        self.selectedMap = self.mapFrameDict['map']
+        self.selectedRegion = self.mapFrameDict['region']
+        self.scaleType = self.mapFrameDict['scaleType']
+        self.mapType = self.mapFrameDict['mapType']
+        self.scaleChoice.SetSelection(self.mapFrameDict['scaleType'])
+        if self.instruction[self.id]:
+            self.drawMap.SetValue(self.mapFrameDict['drawMap'])
+        else:
+            self.drawMap.SetValue(True)
+        if self.mapFrameDict['scaleType'] == 0 and self.mapFrameDict['map']:
+            self.select.SetValue(self.mapFrameDict['map'])
+            if self.mapFrameDict['mapType'] == 'raster':
+                self.rasterTypeRadio.SetValue(True)
+                self.vectorTypeRadio.SetValue(False)
+            else:
+                self.rasterTypeRadio.SetValue(False)
+                self.vectorTypeRadio.SetValue(True)
+        elif self.mapFrameDict['scaleType'] == 1 and self.mapFrameDict['region']:
+            self.select.SetValue(self.mapFrameDict['region'])
+        
+        
+        self.OnMap(None)
+        self.scale[self.mapFrameDict['scaleType']] = self.mapFrameDict['scale']
+        self.center[self.mapFrameDict['scaleType']] = self.mapFrameDict['center']
+        self.OnScaleChoice(None)
+        self.OnElementType(None)
+        self.OnBorder(None)
+        
+        
+        
+    def _layout(self):
+        """!Do layout"""
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map frame"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+
+        #scale options
+        frameText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map frame options:"))
+        scaleChoices = [_("fit frame to match selected map"),
+                        _("fit frame to match saved region"),
+                        _("fit frame to match current computational region"),
+                        _("fixed scale and map center")]
+        self.scaleChoice = wx.Choice(self, id = wx.ID_ANY, choices = scaleChoices)
+        
+        
+        gridBagSizer.Add(frameText, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.scaleChoice, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        #map and region selection
+        self.staticBox = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map selection"))
+        sizerM = wx.StaticBoxSizer(self.staticBox, wx.HORIZONTAL)
+        self.mapSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+        self.rasterTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("raster"), style = wx.RB_GROUP)
+        self.vectorTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("vector"))
+        self.drawMap = wx.CheckBox(self, id = wx.ID_ANY, label = "add selected map")
+        
+        self.mapOrRegionText = [_("Map:"), _("Region:")] 
+        dc = wx.PaintDC(self)# determine size of labels
+        width = max(dc.GetTextExtent(self.mapOrRegionText[0])[0], dc.GetTextExtent(self.mapOrRegionText[1])[0])
+        self.mapText = wx.StaticText(self, id = wx.ID_ANY, label = self.mapOrRegionText[0], size = (width, -1))
+        self.select = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                             type = 'raster', multiple = False,
+                             updateOnPopup = True, onPopup = None)
+                            
+        self.mapSizer.Add(self.rasterTypeRadio, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.mapSizer.Add(self.vectorTypeRadio, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.mapSizer.Add(self.drawMap, pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        self.mapSizer.Add(self.mapText, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.mapSizer.Add(self.select, pos = (1, 1), span = (1, 3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+                 
+        sizerM.Add(self.mapSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerM, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+
+        #map scale and center
+        boxC   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map scale and center"))
+        sizerC = wx.StaticBoxSizer(boxC, wx.HORIZONTAL)
+        self.centerSizer = wx.FlexGridSizer(rows = 2, cols = 5, hgap = 5, vgap = 5)        
+                
+                           
+        centerText = wx.StaticText(self, id = wx.ID_ANY, label = _("Center:"))
+        self.eastingText = wx.StaticText(self, id = wx.ID_ANY, label = _("E:"))
+        self.northingText = wx.StaticText(self, id = wx.ID_ANY, label = _("N:"))
+        self.eastingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
+        self.northingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
+        scaleText = wx.StaticText(self, id = wx.ID_ANY, label = _("Scale:"))
+        scalePrefixText = wx.StaticText(self, id = wx.ID_ANY, label = _("1 :"))
+        self.scaleTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, value = "", style = wx.TE_RIGHT, validator = TCValidator('DIGIT_ONLY'))
+        
+        self.centerSizer.Add(centerText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
+        self.centerSizer.Add(self.eastingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        self.centerSizer.Add(self.eastingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.centerSizer.Add(self.northingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        self.centerSizer.Add(self.northingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        self.centerSizer.Add(scaleText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
+        self.centerSizer.Add(scalePrefixText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        self.centerSizer.Add(self.scaleTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizerC.Add(self.centerSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerC, pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        
+        #resolution
+        flexSizer = wx.FlexGridSizer(rows = 1, cols = 2, hgap = 5, vgap = 5)
+        
+        resolutionText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map max resolution (dpi):"))
+        self.resolutionSpin = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 1000, initial = 300)
+        
+        flexSizer.Add(resolutionText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.resolutionSpin, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.resolutionSpin.SetValue(self.mapFrameDict['resolution'])
+        
+        gridBagSizer.Add(flexSizer, pos = (4, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # border
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Border"))        
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        self.borderCheck = wx.CheckBox(self, id = wx.ID_ANY, label = (_("draw border around map frame")))
+        if self.mapFrameDict['border'] == 'y':
+            self.borderCheck.SetValue(True)
+        else: 
+            self.borderCheck.SetValue(False)
+        
+        self.borderColorText = wx.StaticText(self, id = wx.ID_ANY, label = _("border color:"))
+        self.borderWidthText = wx.StaticText(self, id = wx.ID_ANY, label = _("border width (pts):"))
+        self.borderColourPicker = wx.ColourPickerCtrl(self, id = wx.ID_ANY)
+        self.borderWidthCtrl = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 100, initial = 1)
+        
+        if self.mapFrameDict['border'] == 'y':
+            self.borderWidthCtrl.SetValue(int(self.mapFrameDict['width']))
+            self.borderColourPicker.SetColour(convertRGB(self.mapFrameDict['color']))
+        
+        
+        gridBagSizer.Add(self.borderCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.borderColorText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.borderWidthText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.borderColourPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.borderWidthCtrl, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.SetSizer(border)
+        self.Fit()
+        
+        
+        if projInfo()['proj'] == 'll':
+            self.scaleChoice.SetItems(self.scaleChoice.GetItems()[0:3])
+            boxC.Hide()
+            for each in self.centerSizer.GetChildren():
+                each.GetWindow().Hide()
+
+            
+        # bindings
+        self.scaleChoice.Bind(wx.EVT_CHOICE, self.OnScaleChoice)
+        self.select.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnMap)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.vectorTypeRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.rasterTypeRadio)
+        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.borderCheck)
+        
+        
+     
+    def OnMap(self, event):
+        """!Selected map or region changing"""
+        
+        if self.select.GetValue():
+            self.selected = self.select.GetValue() 
+        else:
+            self.selected = None
+
+        if self.scaleChoice.GetSelection() == 0:
+            self.selectedMap = self.selected
+            if self.rasterTypeRadio.GetValue():
+                mapType = 'raster' 
+            else:
+                mapType = 'vector'
+
+            self.scale[0], self.center[0], foo = AutoAdjust(self, scaleType = 0, map = self.selected,
+                                                mapType = mapType, rect = self.mapFrameDict['rect'])
+            #self.center[0] = self.RegionCenter(self.RegionDict(scaleType = 0))
+
+        elif self.scaleChoice.GetSelection() == 1:
+            self.selectedRegion = self.selected
+            self.scale[1], self.center[1],  foo = AutoAdjust(self, scaleType = 1, region = self.selected, rect = self.mapFrameDict['rect'])
+            #self.center[1] = self.RegionCenter(self.RegionDict(scaleType = 1))
+        elif self.scaleChoice.GetSelection() == 2:
+            self.scale[2], self.center[2], foo = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
+            #self.center[2] = self.RegionCenter(self.RegionDict(scaleType = 2))
+            
+        else:
+            self.scale[3] = None        
+            self.center[3] = None
+            
+        self.OnScaleChoice(None)
+        
+            
+    def OnScaleChoice(self, event):
+        """!Selected scale type changing"""
+        
+        scaleType = self.scaleChoice.GetSelection()
+        if self.scaleType != scaleType:
+            self.scaleType = scaleType
+            self.select.SetValue("")
+        
+        if scaleType in (0, 1): # automatic - region from raster map, saved region
+            if scaleType == 0:
+                # set map selection
+                self.rasterTypeRadio.Show()
+                self.vectorTypeRadio.Show()
+                self.drawMap.Show()
+                self.staticBox.SetLabel(" %s " % _("Map selection"))
+                if self.rasterTypeRadio.GetValue():
+                    stype = 'raster' 
+                else:
+                    stype = 'vector'
+
+                self.select.SetElementList(type = stype)
+                self.mapText.SetLabel(self.mapOrRegionText[0])
+                self.select.SetToolTipString(_("Region is set to match this map,\nraster or vector map must be added later"))
+                    
+            if scaleType == 1:
+                # set region selection
+                self.rasterTypeRadio.Hide()
+                self.vectorTypeRadio.Hide()
+                self.drawMap.Hide()
+                self.staticBox.SetLabel(" %s " % _("Region selection"))
+                stype = 'region'
+                self.select.SetElementList(type = stype)
+                self.mapText.SetLabel(self.mapOrRegionText[1])
+                self.select.SetToolTipString("")
+
+            for each in self.mapSizer.GetChildren():
+                each.GetWindow().Enable()
+            for each in self.centerSizer.GetChildren():
+                each.GetWindow().Disable()
+                    
+            if self.scale[scaleType]:
+                
+                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+            if self.center[scaleType]:
+                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+        elif scaleType == 2:
+            for each in self.mapSizer.GetChildren():
+                each.GetWindow().Disable()
+            for each in self.centerSizer.GetChildren():
+                each.GetWindow().Disable()
+                
+            if self.scale[scaleType]:
+                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+            if self.center[scaleType]:
+                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+        else: # fixed
+            for each in self.mapSizer.GetChildren():
+                each.GetWindow().Disable()
+            for each in self.centerSizer.GetChildren():
+                each.GetWindow().Enable()
+                    
+            if self.scale[scaleType]:
+                self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+            if self.center[scaleType]:
+                self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+                self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+                
+    def OnElementType(self, event):
+        """!Changes data in map selection tree ctrl popup"""
+        if self.rasterTypeRadio.GetValue():
+            mapType = 'raster'
+        else:
+            mapType = 'vector'
+        self.select.SetElementList(type  = mapType)
+        if self.mapType != mapType and event is not None:
+            self.mapType = mapType
+            self.select.SetValue('')
+        self.mapType = mapType    
+        
+    def OnBorder(self, event):
+        """!Enables/disable the part relating to border of map frame"""
+        for each in (self.borderColorText, self.borderWidthText, self.borderColourPicker, self.borderWidthCtrl):
+            each.Enable(self.borderCheck.GetValue())
+            
+    def getId(self):
+        """!Returns id of raster map"""
+        return self.id
+            
+    def update(self):
+        """!Save changes"""
+        mapFrameDict = dict(self.mapFrameDict)
+        # resolution
+        mapFrameDict['resolution'] = self.resolutionSpin.GetValue()
+        #scale
+        scaleType = self.scaleType
+        mapFrameDict['scaleType'] = scaleType
+        
+        if mapFrameDict['scaleType'] == 0:
+            if self.select.GetValue():
+                mapFrameDict['drawMap'] = self.drawMap.GetValue()
+                mapFrameDict['map'] = self.select.GetValue()
+                mapFrameDict['mapType'] = self.mapType
+                mapFrameDict['region'] = None
+                
+                if mapFrameDict['drawMap']:
+
+                    if mapFrameDict['mapType'] == 'raster':
+                        mapFile = grass.find_file(mapFrameDict['map'], element = 'cell')
+                        if mapFile['file'] == '':
+                            GMessage("Raster %s not found" % mapFrameDict['map'])
+                            return False
+                        raster = self.instruction.FindInstructionByType('raster')
+                        if raster:
+                            raster['raster'] = mapFrameDict['map']
+                        else:
+                            raster = Raster(wx.NewId())
+                            raster['raster'] = mapFrameDict['map']
+                            raster['isRaster'] = True
+                            self.instruction.AddInstruction(raster)
+
+                    elif mapFrameDict['mapType'] == 'vector':
+                        
+                        mapFile = grass.find_file(mapFrameDict['map'], element = 'vector')
+                        if mapFile['file'] == '':
+                            GMessage("Vector %s not found" % mapFrameDict['map'])
+                            return False
+                        
+                        vector = self.instruction.FindInstructionByType('vector')
+                        isAdded = False
+                        if vector:
+                            for each in vector['list']:
+                                if each[0] == mapFrameDict['map']:
+                                    isAdded = True
+                        if not isAdded:
+                            topoInfo = grass.vector_info_topo(map = mapFrameDict['map'])
+                            if topoInfo:
+                                if bool(topoInfo['areas']):
+                                    topoType = 'areas'
+                                elif bool(topoInfo['lines']):
+                                    topoType = 'lines'
+                                else:
+                                    topoType = 'points'
+                                label = '('.join(mapFrameDict['map'].split('@')) + ')'
+                           
+                                if not vector:
+                                    vector = Vector(wx.NewId())
+                                    vector['list'] = []
+                                    self.instruction.AddInstruction(vector)
+                                id = wx.NewId()
+                                vector['list'].insert(0, [mapFrameDict['map'], topoType, id, 1, label])
+                                vProp = VProperties(id, topoType)
+                                vProp['name'], vProp['label'], vProp['lpos'] = mapFrameDict['map'], label, 1
+                                self.instruction.AddInstruction(vProp)
+                            else:
+                                return False
+                            
+                self.scale[0], self.center[0], self.rectAdjusted = AutoAdjust(self, scaleType = 0, map = mapFrameDict['map'],
+                                                                   mapType = self.mapType, rect = self.mapFrameDict['rect'])
+                                               
+                if self.rectAdjusted:
+                    mapFrameDict['rect'] = self.rectAdjusted 
+                else:
+                    mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+                mapFrameDict['scale'] = self.scale[0]
+                
+                mapFrameDict['center'] = self.center[0]
+                # set region
+                if self.mapType == 'raster':
+                    RunCommand('g.region', rast = mapFrameDict['map'])
+                if self.mapType == 'vector':
+                    raster = self.instruction.FindInstructionByType('raster')
+                    if raster:
+                        rasterId = raster.id 
+                    else:
+                        rasterId = None
+
+                    if rasterId:
+                        
+                        RunCommand('g.region', vect = mapFrameDict['map'], rast = self.instruction[rasterId]['raster'])
+                    else:
+                        RunCommand('g.region', vect = mapFrameDict['map'])
+                
+                    
+                
+            else:
+                wx.MessageBox(message = _("No map selected!"),
+                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+                return False    
+            
+        elif mapFrameDict['scaleType'] == 1:
+            if self.select.GetValue():
+                mapFrameDict['drawMap'] = False
+                mapFrameDict['map'] = None
+                mapFrameDict['mapType'] = None
+                mapFrameDict['region'] = self.select.GetValue()
+                self.scale[1], self.center[1], self.rectAdjusted = AutoAdjust(self, scaleType = 1, region = mapFrameDict['region'],
+                                                                                rect = self.mapFrameDict['rect'])
+                if self.rectAdjusted:
+                    mapFrameDict['rect'] = self.rectAdjusted 
+                else:
+                    mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+                mapFrameDict['scale'] = self.scale[1]
+                mapFrameDict['center'] = self.center[1]
+                # set region
+                RunCommand('g.region', region = mapFrameDict['region'])
+            else:
+                wx.MessageBox(message = _("No region selected!"),
+                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+                return False 
+                               
+        elif scaleType == 2:
+            mapFrameDict['drawMap'] = False
+            mapFrameDict['map'] = None
+            mapFrameDict['mapType'] = None
+            mapFrameDict['region'] = None
+            self.scale[2], self.center[2], self.rectAdjusted = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
+            if self.rectAdjusted:
+                mapFrameDict['rect'] = self.rectAdjusted 
+            else:
+                mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+            mapFrameDict['scale'] = self.scale[2]
+            mapFrameDict['center'] = self.center[2]
+            
+            env = grass.gisenv()
+            windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
+            try:
+                windFile = open(windFilePath, 'r').read()
+                region = grass.parse_key_val(windFile, sep = ':', val_type = float)
+            except IOError:
+                region = grass.region()
+            
+            raster = self.instruction.FindInstructionByType('raster')
+            if raster:
+                rasterId = raster.id 
+            else:
+                rasterId = None
+
+            if rasterId: # because of resolution
+                RunCommand('g.region', n = region['north'], s = region['south'],
+                            e = region['east'], w = region['west'], rast = self.instruction[rasterId]['raster'])
+            else:
+                RunCommand('g.region', n = region['north'], s = region['south'],
+                           e = region['east'], w = region['west'])
+            
+        elif scaleType == 3:
+            mapFrameDict['drawMap'] = False
+            mapFrameDict['map'] = None
+            mapFrameDict['mapType'] = None
+            mapFrameDict['region'] = None
+            mapFrameDict['rect'] = self.mapFrameDict['rect']
+            try:
+                scaleNumber = float(self.scaleTextCtrl.GetValue())
+                centerE = float(self.eastingTextCtrl.GetValue()) 
+                centerN = float(self.northingTextCtrl.GetValue())
+            except (ValueError, SyntaxError):
+                wx.MessageBox(message = _("Invalid scale or map center!"),
+                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+                return False  
+            mapFrameDict['scale'] = 1/scaleNumber
+            mapFrameDict['center'] = centerE, centerN
+        
+            ComputeSetRegion(self, mapDict = mapFrameDict)
+        
+        # check resolution
+        SetResolution(dpi = mapFrameDict['resolution'], width = mapFrameDict['rect'].width,
+                                                        height = mapFrameDict['rect'].height)
+        # border
+        if self.borderCheck.GetValue():
+            mapFrameDict['border'] = 'y' 
+        else:
+            mapFrameDict['border'] = 'n'
+
+        if mapFrameDict['border'] == 'y':
+            mapFrameDict['width'] = self.borderWidthCtrl.GetValue()
+            mapFrameDict['color'] = convertRGB(self.borderColourPicker.GetColour())
+            
+        if self.id not in self.instruction:
+            mapFrame = MapFrame(self.id)
+            self.instruction.AddInstruction(mapFrame)
+        self.instruction[self.id].SetInstruction(mapFrameDict)
+
+        if self.id not in self.mapDialog.parent.objectId:
+            self.mapDialog.parent.objectId.insert(0, self.id)# map frame is drawn first
+        return True
+        
+class RasterPanel(wx.Panel):
+    """!Panel for raster map settings"""
+    def __init__(self, parent, id, settings,  notebook = True):
+        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        self.instruction = settings
+        
+        if notebook:
+            self.book = parent
+            self.book.AddPage(page = self, text = _("Raster map"))
+            self.mainDialog = self.book.GetParent()
+        else:
+            self.mainDialog = parent
+        if id:
+            self.id = id
+            self.rasterDict = self.instruction[self.id].GetInstruction()
+        else:
+            self.id = wx.NewId()
+            raster = Raster(self.id)
+            self.rasterDict = raster.GetInstruction()
+            
+            
+        self._layout()
+        self.OnRaster(None)
+            
+    def _layout(self):
+        """!Do layout"""
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        # choose raster map
+        
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Choose raster map"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        
+        self.rasterNoRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("no raster map"), style = wx.RB_GROUP)
+        self.rasterYesRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("raster:"))
+        
+        self.rasterSelect = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                             type = 'raster', multiple = False,
+                             updateOnPopup = True, onPopup = None)
+        if self.rasterDict['isRaster']:
+            self.rasterYesRadio.SetValue(True)
+            self.rasterNoRadio.SetValue(False)
+            self.rasterSelect.SetValue(self.rasterDict['raster'])
+        else:
+            self.rasterYesRadio.SetValue(False)
+            self.rasterNoRadio.SetValue(True)
+            mapId = self.instruction.FindInstructionByType('map').id
+
+            if self.instruction[mapId]['map'] and self.instruction[mapId]['mapType'] == 'raster':
+                self.rasterSelect.SetValue(self.instruction[mapId]['map'])# raster map from map frame dialog if possible
+            else:
+                self.rasterSelect.SetValue('')                
+        gridBagSizer.Add(self.rasterNoRadio, pos = (0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)            
+        gridBagSizer.Add(self.rasterYesRadio, pos = (1, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.rasterSelect, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterNoRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterYesRadio)
+        
+        self.SetSizer(border)
+        self.Fit()
+        
+    def OnRaster(self, event):
+        """!Enable/disable raster selection"""
+        self.rasterSelect.Enable(self.rasterYesRadio.GetValue())
+        
+    def update(self):
+        #draw raster
+        mapInstr = self.instruction.FindInstructionByType('map')
+        if not mapInstr: # no map frame
+            GMessage(message = _("Please, create map frame first."))
+            return
+            
+        if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
+            self.rasterDict['isRaster'] = False
+            self.rasterDict['raster'] = None
+            mapInstr['drawMap'] = False
+            if self.id in self.instruction:
+                del self.instruction[self.id]
+
+        else:
+            self.rasterDict['isRaster'] = True
+            self.rasterDict['raster'] = self.rasterSelect.GetValue()
+            if self.rasterDict['raster'] != mapInstr['drawMap']:
+                mapInstr['drawMap'] = False
+
+            raster = self.instruction.FindInstructionByType('raster')
+            if not raster:
+                raster = Raster(self.id)
+                self.instruction.AddInstruction(raster)
+                self.instruction[self.id].SetInstruction(self.rasterDict)
+            else:
+                self.instruction[raster.id].SetInstruction(self.rasterDict)
+            
+        if 'map' in self.mainDialog.parent.openDialogs:
+            self.mainDialog.parent.openDialogs['map'].updateDialog()
+        return True
+        
+    def getId(self):
+        return self.id
+  
+class VectorPanel(wx.Panel):
+    """!Panel for vector maps settings"""
+    def __init__(self, parent, id, settings, notebook = True):
+        wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        
+        self.parent = parent
+        self.instruction = settings
+        self.tmpDialogDict = {}
+        vectors = self.instruction.FindInstructionByType('vProperties', list = True)
+        for vector in vectors:
+            self.tmpDialogDict[vector.id] = dict(self.instruction[vector.id].GetInstruction())
+        
+        if id:
+            self.id = id
+            self.vectorList = deepcopy(self.instruction[id]['list'])
+        else:
+            self.id = wx.NewId()
+            self.vectorList = []
+
+        vLegend = self.instruction.FindInstructionByType('vectorLegend')
+        if vLegend:
+            self.vLegendId = vLegend.id 
+        else:
+            self.vLegendId = None
+
+         
+        self._layout()
+        
+        if notebook:
+            self.parent.AddPage(page = self, text = _("Vector maps"))
+            self.parent = self.parent.GetParent()
+            
+    def _layout(self):
+        """!Do layout"""
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        # choose vector map
+        
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Add map"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        
+        text = wx.StaticText(self, id = wx.ID_ANY, label = _("Map:"))
+        self.select = Select(self, id = wx.ID_ANY,# size = globalvar.DIALOG_GSELECT_SIZE,
+                             type = 'vector', multiple = False,
+                             updateOnPopup = True, onPopup = None)
+        topologyType = [_("points"), _("lines"), _("areas")]
+        self.vectorType = wx.RadioBox(self, id = wx.ID_ANY, label = " %s " % _("Data Type"), choices = topologyType,
+                                        majorDimension = 3, style = wx.RA_SPECIFY_COLS)
+        self.AddVector = wx.Button(self, id = wx.ID_ANY, label = _("Add"))
+        
+        gridBagSizer.Add(text, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.select, pos = (0,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.vectorType, pos = (1,1), flag = wx.ALIGN_CENTER, border = 0)
+        gridBagSizer.Add(self.AddVector, pos = (1,2), flag = wx.ALIGN_BOTTOM|wx.ALIGN_RIGHT, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # manage vector layers
+        
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Manage vector maps"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0,2)
+        gridBagSizer.AddGrowableCol(1,1)
+
+        
+        
+        text = wx.StaticText(self, id = wx.ID_ANY, label = _("The topmost vector map overlaps the others"))
+        self.listbox = wx.ListBox(self, id = wx.ID_ANY, choices = [], style = wx.LB_SINGLE|wx.LB_NEEDED_SB)
+        self.btnUp = wx.Button(self, id = wx.ID_ANY, label = _("Up"))
+        self.btnDown = wx.Button(self, id = wx.ID_ANY, label = _("Down"))
+        self.btnDel = wx.Button(self, id = wx.ID_ANY, label = _("Delete"))
+        self.btnProp = wx.Button(self, id = wx.ID_ANY, label = _("Properties..."))
+        
+        self.updateListBox(selected=0)
+        
+        
+        gridBagSizer.Add(text, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.listbox, pos = (1,0), span = (4, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.btnUp, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.btnDown, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.btnDel, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.btnProp, pos = (4,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_BUTTON, self.OnAddVector, self.AddVector)
+        self.Bind(wx.EVT_BUTTON, self.OnDelete, self.btnDel)
+        self.Bind(wx.EVT_BUTTON, self.OnUp, self.btnUp)
+        self.Bind(wx.EVT_BUTTON, self.OnDown, self.btnDown)
+        self.Bind(wx.EVT_BUTTON, self.OnProperties, self.btnProp)
+        self.select.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnVector)
+        
+        self.SetSizer(border)
+        self.Fit()
+        
+        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnProperties, self.listbox)
+
+    def OnVector(self, event):
+        """!Gets info about toplogy and enables/disables choices point/line/area"""
+        vmap = self.select.GetValue()   
+        try:     
+            topoInfo = grass.vector_info_topo(map = vmap)
+        except grass.ScriptError:
+            return
+        
+        if topoInfo:
+            self.vectorType.EnableItem(2, bool(topoInfo['areas']))
+            self.vectorType.EnableItem(1, bool(topoInfo['boundaries']) or bool(topoInfo['lines']))
+            self.vectorType.EnableItem(0, bool(topoInfo['centroids'] or bool(topoInfo['points']) ))
+            for item in range(2,-1,-1):
+                if self.vectorType.IsItemEnabled(item):
+                    self.vectorType.SetSelection(item)
+                    break
+            
+            self.AddVector.SetFocus()        
+            
+    def OnAddVector(self, event):
+        """!Adds vector map to list"""
+        vmap = self.select.GetValue()
+        if vmap:
+            mapname = vmap.split('@')[0]
+            try:
+                mapset = '(' + vmap.split('@')[1] + ')'
+            except IndexError:
+                mapset = ''
+            type = self.vectorType.GetStringSelection()
+            record = "%s - %s" % (vmap,type)
+            id = wx.NewId()
+            lpos = 1
+            label = mapname + mapset 
+            self.vectorList.insert(0, [vmap, type, id, lpos, label])
+            self.reposition()
+            self.listbox.InsertItems([record], 0)
+            
+            vector = VProperties(id, type)
+            self.tmpDialogDict[id] = vector.GetInstruction()
+            self.tmpDialogDict[id]['name'] = vmap
+
+            
+            self.listbox.SetSelection(0)  
+            self.listbox.EnsureVisible(0)
+            self.btnProp.SetFocus()
+            self.enableButtons()
+            
+    def OnDelete(self, event):
+        """!Deletes vector map from the list"""
+        if self.listbox.GetSelections():
+            pos = self.listbox.GetSelection()
+            id = self.vectorList[pos][2]
+            del self.vectorList[pos]
+            del self.tmpDialogDict[id]
+            
+            for i in range(pos, len(self.vectorList)):
+                if self.vectorList[i][3]:# can be 0
+                    self.vectorList[i][3] -= 1
+            
+            if pos < len(self.vectorList) -1:
+                selected = pos
+            else:
+                selected = len(self.vectorList) -1
+            self.updateListBox(selected = selected)
+            if self.listbox.IsEmpty():
+                self.enableButtons(False)
+            
+            
+    def OnUp(self, event):
+        """!Moves selected map to top"""
+        if self.listbox.GetSelections():
+            pos = self.listbox.GetSelection()
+            if pos:
+                self.vectorList.insert(pos - 1, self.vectorList.pop(pos))
+            if not self.vLegendId:
+                self.reposition()
+                
+            if pos > 0:
+                self.updateListBox(selected = (pos - 1)) 
+            else:
+                self.updateListBox(selected = 0)
+
+            
+    def OnDown(self, event):
+        """!Moves selected map to bottom"""
+        if self.listbox.GetSelections():
+            pos = self.listbox.GetSelection()
+            if pos != len(self.vectorList) - 1:
+                self.vectorList.insert(pos + 1, self.vectorList.pop(pos))
+                if not self.vLegendId:
+                    self.reposition()
+            if pos < len(self.vectorList) -1:
+                self.updateListBox(selected = (pos + 1)) 
+            else:
+                self.updateListBox(selected = len(self.vectorList) -1)
+
+    
+    def OnProperties(self, event):
+        """!Opens vector map properties dialog"""
+        if self.listbox.GetSelections():
+            pos = self.listbox.GetSelection()
+            id = self.vectorList[pos][2]
+
+            dlg = VPropertiesDialog(self, id = id, settings = self.instruction, 
+                                    vectors = self.vectorList, tmpSettings = self.tmpDialogDict[id])
+            dlg.ShowModal()
+            
+            self.parent.FindWindowById(wx.ID_OK).SetFocus()
+           
+    def enableButtons(self, enable = True):
+        """!Enable/disable up, down, properties, delete buttons"""
+        self.btnUp.Enable(enable)
+        self.btnDown.Enable(enable)
+        self.btnProp.Enable(enable)
+        self.btnDel.Enable(enable)
+    
+    def updateListBox(self, selected = None):
+        mapList = ["%s - %s" % (item[0], item[1]) for item in self.vectorList]
+        self.listbox.Set(mapList)
+        if self.listbox.IsEmpty():
+            self.enableButtons(False)
+        else:
+            self.enableButtons(True)
+            if selected is not None:
+                self.listbox.SetSelection(selected)  
+                self.listbox.EnsureVisible(selected)  
+              
+    def reposition(self):
+        """!Update position in legend, used only if there is no vlegend yet"""
+        for i in range(len(self.vectorList)):
+            if self.vectorList[i][3]:
+                self.vectorList[i][3] = i + 1
+                
+    def getId(self):
+        return self.id
+        
+    def update(self):
+        vectors = self.instruction.FindInstructionByType('vProperties', list = True)
+        
+        for vector in vectors:
+            del self.instruction[vector.id]
+        if self.id in self.instruction:
+            del self.instruction[self.id] 
+
+        if len(self.vectorList) > 0:
+            vector = Vector(self.id)
+            self.instruction.AddInstruction(vector)
+
+            vector.SetInstruction({'list': deepcopy(self.vectorList)})
+            
+            # save new vectors
+            for item in self.vectorList:
+                id = item[2]
+
+                vLayer = VProperties(id, item[1])
+                self.instruction.AddInstruction(vLayer)
+                vLayer.SetInstruction(self.tmpDialogDict[id])
+                vLayer['name'] = item[0]
+                vLayer['label'] = item[4]
+                vLayer['lpos'] = item[3]
+            
+        else:
+            if self.id in self.instruction:
+                del self.instruction[self.id]
+                
+        if 'map' in self.parent.parent.openDialogs:
+            self.parent.parent.openDialogs['map'].updateDialog()
+
+        return True
+    
+class RasterDialog(PsmapDialog):
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = _("Raster map settings"), settings = settings)
+        self.objectType = ('raster',)
+        
+        self.rPanel = RasterPanel(parent = self, id = self.id, settings = self.instruction, notebook = False)
+
+        self.id = self.rPanel.getId()
+        self._layout(self.rPanel)
+    
+    def update(self):
+        ok = self.rPanel.update()
+        if ok:
+            return True
+        return False
+    
+    def OnApply(self, event):
+        ok = self.update()
+        if not ok:
+            return False
+
+        if self.id in self.instruction:
+            self.parent.DialogDataChanged(id = self.id)
+        else:
+            mapId = self.instruction.FindInstructionByType('map').id
+            self.parent.DialogDataChanged(id = mapId)
+        return True
+    
+    def updateDialog(self):
+        """!Update information (not used)"""
+        pass
+##        if 'map' in self.parent.openDialogs:
+##            if self.parent.openDialogs['map'].mPanel.rasterTypeRadio.GetValue()\
+##                    and self.parent.openDialogs['map'].mPanel.select.GetValue():
+##                if self.parent.openDialogs['map'].mPanel.drawMap.IsChecked():
+##                    self.rPanel.rasterSelect.SetValue(self.parent.openDialogs['map'].mPanel.select.GetValue())   
+                
+class MainVectorDialog(PsmapDialog):
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = _("Vector maps settings"), settings = settings)
+        self.objectType = ('vector',)
+        self.vPanel = VectorPanel(parent = self, id = self.id, settings = self.instruction, notebook = False)
+
+        self.id = self.vPanel.getId()
+        self._layout(self.vPanel)
+    
+    def update(self):
+        self.vPanel.update()
+        
+    def OnApply(self, event):
+        self.update()
+        if self.id in self.instruction:
+            self.parent.DialogDataChanged(id = self.id)
+        else:
+            mapId = self.instruction.FindInstructionByType('map').id
+            self.parent.DialogDataChanged(id = mapId)
+        return True
+        
+    def updateDialog(self):
+        """!Update information (not used)"""
+        pass
+        
+class VPropertiesDialog(PsmapDialog):
+    def __init__(self, parent, id, settings, vectors, tmpSettings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "", settings = settings, apply = False)
+        
+        vectorList = vectors
+        self.vPropertiesDict = tmpSettings
+        
+        # determine map and its type
+        for item in vectorList:
+            if id == item[2]:
+                self.vectorName = item[0]
+                self.type = item[1]
+        self.SetTitle(self.vectorName + " "+ _("properties"))
+        
+        #vector map info
+        self.connection = True
+        try:
+            self.mapDBInfo = VectorDBInfo(self.vectorName)
+            self.layers = self.mapDBInfo.layers.keys()
+        except grass.ScriptError:
+            self.connection = False
+            self.layers = []
+        if not self.layers:
+            self.connection = False
+            self.layers = []
+            
+        self.currLayer = self.vPropertiesDict['layer']
+        
+        #path to symbols, patterns
+        gisbase = os.getenv("GISBASE")
+        self.symbolPath = os.path.join(gisbase, 'etc', 'symbol')
+        self.symbols = []
+        for dir in os.listdir(self.symbolPath):
+            for symbol in os.listdir(os.path.join(self.symbolPath, dir)):
+                self.symbols.append(os.path.join(dir, symbol))
+        self.patternPath = os.path.join(gisbase, 'etc', 'paint', 'patterns')
+
+        #notebook
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.DSpanel = self._DataSelectionPanel(notebook)
+        self.EnableLayerSelection(enable = self.connection)
+        selectPanel = { 'points': [self._ColorsPointAreaPanel, self._StylePointPanel], 
+                        'lines': [self._ColorsLinePanel, self._StyleLinePanel], 
+                        'areas': [self._ColorsPointAreaPanel, self._StyleAreaPanel]}
+        self.ColorsPanel = selectPanel[self.type][0](notebook)
+        
+        self.OnOutline(None)
+        if self.type in ('points', 'areas'):
+            self.OnFill(None)
+        self.OnColor(None)
+        
+        self.StylePanel = selectPanel[self.type][1](notebook)
+        if self.type == 'points':
+            self.OnSize(None)
+            self.OnRotation(None)
+        if self.type == 'areas':
+            self.OnPattern(None)
+        
+        self._layout(notebook)
+        
+    def _DataSelectionPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Data selection"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        # data type
+        self.checkType1 = self.checkType2 = None
+        if self.type in ('lines', 'points'):
+            box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Feature type"))
+            sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+            gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+            if self.type == 'points':
+                label = (_("points"), _("centroids"))
+            else: 
+                label = (_("lines"), _("boundaries"))
+            if self.type == 'points':
+                name = ("point", "centroid")
+            else:
+                name = ("line", "boundary")
+            self.checkType1 = wx.CheckBox(panel, id = wx.ID_ANY, label = label[0], name = name[0])
+            self.checkType2 = wx.CheckBox(panel, id = wx.ID_ANY, label = label[1], name = name[1])
+            self.checkType1.SetValue(self.vPropertiesDict['type'].find(name[0]) >= 0)
+            self.checkType2.SetValue(self.vPropertiesDict['type'].find(name[1]) >= 0)
+            
+            gridBagSizer.Add(self.checkType1, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            gridBagSizer.Add(self.checkType2, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+            border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # layer selection
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Layer selection"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        self.gridBagSizerL = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        self.warning =  wx.StaticText(panel, id = wx.ID_ANY, label = "")
+        if not self.connection:
+            self.warning = wx.StaticText(panel, id = wx.ID_ANY, label = _("Database connection is not defined in DB file."))
+        text = wx.StaticText(panel, id = wx.ID_ANY, label = _("Select layer:"))
+        self.layerChoice = wx.Choice(panel, id = wx.ID_ANY, choices = map(str, self.layers), size = self.spinCtrlSize)
+        
+        self.layerChoice.SetStringSelection(self.currLayer)
+                
+        if self.connection:
+            table = self.mapDBInfo.layers[int(self.currLayer)]['table'] 
+        else:
+            table = ""
+
+        self.radioWhere = wx.RadioButton(panel, id = wx.ID_ANY, label = "SELECT * FROM %s WHERE" % table, style = wx.RB_GROUP)
+        self.textCtrlWhere = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        
+        
+        if self.connection:
+            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
+        else:
+            cols = []
+
+        self.choiceColumns = wx.Choice(panel, id = wx.ID_ANY, choices = cols)
+        
+        self.radioCats = wx.RadioButton(panel, id = wx.ID_ANY, label = "Choose categories ")
+        self.textCtrlCats = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        self.textCtrlCats.SetToolTipString(_("list of categories (e.g. 1,3,5-7)"))
+        
+        if self.vPropertiesDict.has_key('cats'):
+            self.radioCats.SetValue(True)
+            self.textCtrlCats.SetValue(self.vPropertiesDict['cats'])
+        if self.vPropertiesDict.has_key('where'):
+            self.radioWhere.SetValue(True)
+            where = self.vPropertiesDict['where'].strip().split(" ",1)
+            self.choiceColumns.SetStringSelection(where[0])
+            self.textCtrlWhere.SetValue(where[1])
+            
+        row = 0
+        if not self.connection:
+            self.gridBagSizerL.Add(self.warning, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            row = 1
+        self.gridBagSizerL.Add(text, pos = (0 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerL.Add(self.layerChoice, pos = (0 + row,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        self.gridBagSizerL.Add(self.radioWhere, pos = (1 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerL.Add(self.choiceColumns, pos = (1 + row,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerL.Add(self.textCtrlWhere, pos = (1 + row,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerL.Add(self.radioCats, pos = (2 + row,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerL.Add(self.textCtrlCats, pos = (2 + row,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(self.gridBagSizerL, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #mask
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Mask"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        
+        self.mask = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Use current mask"))
+        if self.vPropertiesDict['masked'] == 'y':
+            self.mask.SetValue(True) 
+        else:
+            self.mask.SetValue(False)
+        
+        sizer.Add(self.mask, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        self.Bind(wx.EVT_CHOICE, self.OnLayer, self.layerChoice)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+    
+    def _ColorsPointAreaPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Colors"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #colors - outline
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Outline"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        self.gridBagSizerO = wx.GridBagSizer(hgap = 5, vgap = 2)
+        
+        self.outlineCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw outline"))
+        self.outlineCheck.SetValue(self.vPropertiesDict['color'] != 'none')
+        
+        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+        if fs:
+            self.widthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
+                                          increment = 0.5, value = 1, style = fs.FS_RIGHT)
+            self.widthSpin.SetFormat("%f")
+            self.widthSpin.SetDigits(2)
+        else:
+            self.widthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1,
+                                         size = self.spinCtrlSize)
+                                        
+        if self.vPropertiesDict['color'] == None:
+            self.vPropertiesDict['color'] = 'none'
+ 
+        if self.vPropertiesDict['color'] != 'none':
+            self.widthSpin.SetValue(self.vPropertiesDict['width'] )
+        else:
+            self.widthSpin.SetValue(1)
+
+        colorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:"))
+        self.colorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        if self.vPropertiesDict['color'] != 'none':
+            self.colorPicker.SetColour(convertRGB(self.vPropertiesDict['color'])) 
+        else:
+            self.colorPicker.SetColour(convertRGB('black'))
+
+        self.gridBagSizerO.Add(self.outlineCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerO.Add(widthText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerO.Add(self.widthSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
+        self.gridBagSizerO.Add(colorText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)                
+        self.gridBagSizerO.Add(self.colorPicker, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        
+        sizer.Add(self.gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OnOutline, self.outlineCheck)
+        
+        #colors - fill
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Fill")) 
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        self.gridBagSizerF = wx.GridBagSizer(hgap = 5, vgap = 2)
+       
+        self.fillCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("fill color"))
+        self.fillCheck.SetValue(self.vPropertiesDict['fcolor'] != 'none' or self.vPropertiesDict['rgbcolumn'] is not None)
+
+        self.colorPickerRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("choose color:"), style = wx.RB_GROUP)
+        #set choose color option if there is no db connection
+        if self.connection:
+            self.colorPickerRadio.SetValue(not self.vPropertiesDict['rgbcolumn'])
+        else:
+            self.colorPickerRadio.SetValue(False)            
+        self.fillColorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        if self.vPropertiesDict['fcolor'] != 'none':
+            self.fillColorPicker.SetColour(convertRGB(self.vPropertiesDict['fcolor'])) 
+        else:
+            self.fillColorPicker.SetColour(convertRGB('red'))        
+        
+        self.colorColRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("color from map table column:"))
+        self.colorColChoice = self.getColsChoice(parent = panel)
+        if self.connection:
+            if self.vPropertiesDict['rgbcolumn']:
+                self.colorColRadio.SetValue(True)
+                self.colorColChoice.SetStringSelection(self.vPropertiesDict['rgbcolumn'])
+            else:
+                self.colorColRadio.SetValue(False)
+                self.colorColChoice.SetSelection(0)
+        self.colorColChoice.Enable(self.connection)
+        self.colorColRadio.Enable(self.connection)
+        
+        self.gridBagSizerF.Add(self.fillCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerF.Add(self.colorPickerRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.fillColorPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.colorColRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.colorColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
+        
+        sizer.Add(self.gridBagSizerF, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        self.Bind(wx.EVT_CHECKBOX, self.OnFill, self.fillCheck)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorColRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorPickerRadio)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+    
+    def _ColorsLinePanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Colors"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #colors - outline
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Outline"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        self.gridBagSizerO = wx.GridBagSizer(hgap = 5, vgap = 2)
+        
+        if self.vPropertiesDict['hcolor'] == None:
+            self.vPropertiesDict['hcolor'] = 'none'
+        if self.vPropertiesDict['color'] == None:
+            self.vPropertiesDict['color'] = 'none'
+        
+        self.outlineCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw outline"))
+        self.outlineCheck.SetValue(self.vPropertiesDict['hcolor'] != 'none')
+        self.outlineCheck.SetToolTipString(_("No effect for fill color from table column"))
+        
+        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+        
+        if fs:
+            self.outWidthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
+                                             increment = 0.5, value = 1, style = fs.FS_RIGHT)
+            self.outWidthSpin.SetFormat("%f")
+            self.outWidthSpin.SetDigits(1)
+        else:
+            self.outWidthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1,
+                                         size = self.spinCtrlSize)
+        
+        if self.vPropertiesDict['hcolor'] != 'none':
+            self.outWidthSpin.SetValue(self.vPropertiesDict['hwidth'] )
+        else:
+            self.outWidthSpin.SetValue(1)
+
+        colorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color:"))
+        self.colorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        if self.vPropertiesDict['hcolor'] != 'none':
+            self.colorPicker.SetColour(convertRGB(self.vPropertiesDict['hcolor']) )
+        else:
+            self.colorPicker.SetColour(convertRGB('black'))
+
+        
+        self.gridBagSizerO.Add(self.outlineCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerO.Add(widthText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerO.Add(self.outWidthSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
+        self.gridBagSizerO.Add(colorText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)                
+        self.gridBagSizerO.Add(self.colorPicker, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        
+        sizer.Add(self.gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OnOutline, self.outlineCheck)
+        
+        #colors - fill
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Fill"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        self.gridBagSizerF = wx.GridBagSizer(hgap = 5, vgap = 2)
+       
+        fillText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Color of lines:"))
+
+        self.colorPickerRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("choose color:"), style = wx.RB_GROUP)
+
+        #set choose color option if there is no db connection
+        if self.connection:
+            self.colorPickerRadio.SetValue(not self.vPropertiesDict['rgbcolumn'])
+        else:
+            self.colorPickerRadio.SetValue(False)            
+        self.fillColorPicker = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        if self.vPropertiesDict['color'] != 'none':
+            self.fillColorPicker.SetColour(convertRGB(self.vPropertiesDict['color']) )
+        else:
+            self.fillColorPicker.SetColour(convertRGB('black'))
+        
+        self.colorColRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("color from map table column:"))
+        self.colorColChoice = self.getColsChoice(parent = panel)
+        if self.connection:
+            if self.vPropertiesDict['rgbcolumn']:
+                self.colorColRadio.SetValue(True)
+                self.colorColChoice.SetStringSelection(self.vPropertiesDict['rgbcolumn'])
+            else:
+                self.colorColRadio.SetValue(False)
+                self.colorColChoice.SetSelection(0)
+        self.colorColChoice.Enable(self.connection)
+        self.colorColRadio.Enable(self.connection)
+        
+        self.gridBagSizerF.Add(fillText, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerF.Add(self.colorPickerRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.fillColorPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.colorColRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        self.gridBagSizerF.Add(self.colorColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)        
+        
+        sizer.Add(self.gridBagSizerF, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorColRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnColor, self.colorPickerRadio)
+
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+    
+    def _StylePointPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Size and style"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #symbology
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Symbology"))        
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+    
+        self.symbolRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("symbol:"), style = wx.RB_GROUP)
+        self.symbolRadio.SetValue(bool(self.vPropertiesDict['symbol']))
+            
+         
+        self.symbolChoice = wx.Choice(panel, id = wx.ID_ANY, choices = self.symbols)
+            
+        self.epsRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("eps file:"))
+        self.epsRadio.SetValue(bool(self.vPropertiesDict['eps']))
+        
+        self.epsFileCtrl = filebrowse.FileBrowseButton(panel, id = wx.ID_ANY, labelText = '',
+                                buttonText =  _("Browse"), toolTip = _("Type filename or click browse to choose file"), 
+                                dialogTitle = _("Choose a file"), startDirectory = '', initialValue = '',
+                                fileMask = "Encapsulated PostScript (*.eps)|*.eps|All files (*.*)|*.*", fileMode = wx.OPEN)
+        if self.vPropertiesDict['symbol']:
+            self.symbolChoice.SetStringSelection(self.vPropertiesDict['symbol'])
+            self.epsFileCtrl.SetValue('')
+        else: #eps chosen
+            self.epsFileCtrl.SetValue(self.vPropertiesDict['eps'])
+            self.symbolChoice.SetSelection(0)
+            
+        gridBagSizer.Add(self.symbolRadio, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.symbolChoice, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.epsRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.epsFileCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #size
+        
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))        
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0)
+        
+        self.sizeRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("size:"), style = wx.RB_GROUP)
+        self.sizeSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 50, initial = 1)
+        self.sizecolumnRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("size from map table column:"))
+        self.sizeColChoice = self.getColsChoice(panel)
+        self.scaleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("scale:"))
+        self.scaleSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
+        
+        self.sizeRadio.SetValue(self.vPropertiesDict['size'] is not None)
+        self.sizecolumnRadio.SetValue(bool(self.vPropertiesDict['sizecolumn']))
+        if self.vPropertiesDict['size']:
+            self.sizeSpin.SetValue(self.vPropertiesDict['size'])
+        else: self.sizeSpin.SetValue(5)
+        if self.vPropertiesDict['sizecolumn']:
+            self.scaleSpin.SetValue(self.vPropertiesDict['scale'])
+            self.sizeColChoice.SetStringSelection(self.vPropertiesDict['sizecolumn'])
+        else:
+            self.scaleSpin.SetValue(1)
+            self.sizeColChoice.SetSelection(0)
+        if not self.connection:   
+            for each in (self.sizecolumnRadio, self.sizeColChoice, self.scaleSpin, self.scaleText):
+                each.Disable()
+            
+        gridBagSizer.Add(self.sizeRadio, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sizeSpin, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sizecolumnRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sizeColChoice, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.scaleText, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        gridBagSizer.Add(self.scaleSpin, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnSize, self.sizeRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnSize, self.sizecolumnRadio)
+        
+        #rotation
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+
+        
+        self.rotateCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("rotate symbols:"))
+        self.rotateRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("counterclockwise in degrees:"), style = wx.RB_GROUP)
+        self.rotateSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 360, initial = 0)
+        self.rotatecolumnRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("from map table column:"))
+        self.rotateColChoice = self.getColsChoice(panel)
+        
+        self.rotateCheck.SetValue(self.vPropertiesDict['rotation'])
+        self.rotateRadio.SetValue(self.vPropertiesDict['rotate'] is not None)
+        self.rotatecolumnRadio.SetValue(bool(self.vPropertiesDict['rotatecolumn']))
+        if self.vPropertiesDict['rotate']:
+            self.rotateSpin.SetValue(self.vPropertiesDict['rotate'])
+        else:
+            self.rotateSpin.SetValue(0)
+        if self.vPropertiesDict['rotatecolumn']:
+            self.rotateColChoice.SetStringSelection(self.vPropertiesDict['rotatecolumn'])
+        else:
+            self.rotateColChoice.SetSelection(0)
+            
+        gridBagSizer.Add(self.rotateCheck, pos = (0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.rotateRadio, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.rotateSpin, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.rotatecolumnRadio, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.rotateColChoice, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotateCheck)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRotationType, self.rotateRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRotationType, self.rotatecolumnRadio)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+    
+    def _StyleLinePanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Size and style"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #width
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Width"))       
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        widthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Set width (pts):"))
+        if fs:
+            self.widthSpin = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 30,
+                                        increment = 0.5, value = 1, style = fs.FS_RIGHT)
+            self.widthSpin.SetFormat("%f")
+            self.widthSpin.SetDigits(1)
+        else:
+            self.widthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1)
+            
+        self.cwidthCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("multiply width by category value"))
+        
+        if self.vPropertiesDict['width']:
+            self.widthSpin.SetValue(self.vPropertiesDict['width'])
+            self.cwidthCheck.SetValue(False)
+        else:
+            self.widthSpin.SetValue(self.vPropertiesDict['cwidth'])
+            self.cwidthCheck.SetValue(True)
+        
+        gridBagSizer.Add(widthText, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.widthSpin, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.cwidthCheck, pos = (1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #style
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Line style"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        styleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose line style:"))
+        penStyles = ["solid", "dashed", "dotted", "dashdotted"]
+        self.styleCombo = PenStyleComboBox(panel, choices = penStyles, validator = TCValidator(flag = 'ZERO_AND_ONE_ONLY'))
+##        self.styleCombo = wx.ComboBox(panel, id = wx.ID_ANY,
+##                            choices = ["solid", "dashed", "dotted", "dashdotted"],
+##                            validator = TCValidator(flag = 'ZERO_AND_ONE_ONLY'))
+##        self.styleCombo.SetToolTipString(_("It's possible to enter a series of 0's and 1's too. "\
+##                                    "The first block of repeated zeros or ones represents 'draw', "\
+##                                    "the second block represents 'blank'. An even number of blocks "\
+##                                    "will repeat the pattern, an odd number of blocks will alternate the pattern."))
+        linecapText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose linecap:"))
+        self.linecapChoice = wx.Choice(panel, id = wx.ID_ANY, choices = ["butt", "round", "extended_butt"])
+        
+        self.styleCombo.SetValue(self.vPropertiesDict['style'])
+        self.linecapChoice.SetStringSelection(self.vPropertiesDict['linecap'])
+        
+        gridBagSizer.Add(styleText, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.styleCombo, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(linecapText, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.linecapChoice, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+        
+    def _StyleAreaPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Size and style"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #pattern
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Pattern"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.patternCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use pattern:"))
+        self.patFileCtrl = filebrowse.FileBrowseButton(panel, id = wx.ID_ANY, labelText = _("Choose pattern file:"),
+                                buttonText =  _("Browse"), toolTip = _("Type filename or click browse to choose file"), 
+                                dialogTitle = _("Choose a file"), startDirectory = self.patternPath, initialValue = '',
+                                fileMask = "Encapsulated PostScript (*.eps)|*.eps|All files (*.*)|*.*", fileMode = wx.OPEN)
+        self.patWidthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("pattern line width (pts):"))
+        self.patWidthSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
+        self.patScaleText = wx.StaticText(panel, id = wx.ID_ANY, label = _("pattern scale factor:"))
+        self.patScaleSpin = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 25, initial = 1)
+        
+        self.patternCheck.SetValue(bool(self.vPropertiesDict['pat']))
+        if self.patternCheck.GetValue():
+            self.patFileCtrl.SetValue(self.vPropertiesDict['pat'])
+            self.patWidthSpin.SetValue(self.vPropertiesDict['pwidth'])
+            self.patScaleSpin.SetValue(self.vPropertiesDict['scale'])
+        
+        gridBagSizer.Add(self.patternCheck, pos = (0, 0),  flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.patFileCtrl, pos = (1, 0), span = (1, 2),flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.patWidthText, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.patWidthSpin, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.patScaleText, pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.patScaleSpin, pos = (3, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OnPattern, self.patternCheck)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        return panel
+
+    def OnLayer(self, event):
+        """!Change columns on layer change """
+        if self.layerChoice.GetStringSelection() == self.currLayer:
+            return
+        self.currLayer = self.layerChoice.GetStringSelection()
+        if self.connection:
+            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
+        else:
+            cols = []
+
+        self.choiceColumns.SetItems(cols)
+
+        self.choiceColumns.SetSelection(0)
+        if self.type in ('points', 'lines'):
+            self.colorColChoice.SetItems(cols)
+            self.colorColChoice.SetSelection(0)
+            
+    def OnOutline(self, event):
+        for widget in self.gridBagSizerO.GetChildren():
+            if widget.GetWindow() != self.outlineCheck:
+                widget.GetWindow().Enable(self.outlineCheck.GetValue())
+                
+    def OnFill(self, event):
+        enable = self.fillCheck.GetValue()
+        
+        self.colorColChoice.Enable(enable)
+        self.colorColRadio.Enable(enable)
+        self.fillColorPicker.Enable(enable)
+        self.colorPickerRadio.Enable(enable)
+        if enable:
+            self.OnColor(None)
+        if not self.connection:
+            self.colorColChoice.Disable()
+            self.colorColRadio.Disable()
+            
+    def OnColor(self, event):
+        self.colorColChoice.Enable(self.colorColRadio.GetValue())
+        self.fillColorPicker.Enable(self.colorPickerRadio.GetValue())
+            
+    def OnSize(self, event):
+        self.sizeSpin.Enable(self.sizeRadio.GetValue())
+        self.sizeColChoice.Enable(self.sizecolumnRadio.GetValue())
+        self.scaleText.Enable(self.sizecolumnRadio.GetValue())
+        self.scaleSpin.Enable(self.sizecolumnRadio.GetValue())
+        
+    def OnRotation(self, event):
+        for each in (self.rotateRadio, self.rotatecolumnRadio, self.rotateColChoice, self.rotateSpin):
+            if self.rotateCheck.GetValue():
+                each.Enable()
+                self.OnRotationType(event = None)     
+            else:
+                each.Disable()
+           
+    def OnRotationType(self, event):
+        self.rotateSpin.Enable(self.rotateRadio.GetValue())
+        self.rotateColChoice.Enable(self.rotatecolumnRadio.GetValue())
+        
+    def OnPattern(self, event):
+        for each in (self.patFileCtrl, self.patWidthText, self.patWidthSpin, self.patScaleText, self.patScaleSpin):
+            each.Enable(self.patternCheck.GetValue())
+            
+    def EnableLayerSelection(self, enable = True):
+        for widget in self.gridBagSizerL.GetChildren():
+            if widget.GetWindow() != self.warning:
+                widget.GetWindow().Enable(enable)
+                
+    def getColsChoice(self, parent):
+        """!Returns a wx.Choice with table columns"""
+        if self.connection:
+            cols = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[int(self.currLayer)]['table']) 
+        else:
+            cols = []
+
+        choice = wx.Choice(parent = parent, id = wx.ID_ANY, choices = cols)
+        return choice
+        
+    def update(self):
+        #feature type
+        if self.type in ('lines', 'points'):
+            featureType = None
+            if self.checkType1.GetValue():
+                featureType = self.checkType1.GetName()
+                if self.checkType2.GetValue():
+                    featureType += " or " + self.checkType2.GetName()
+            elif self.checkType2.GetValue():
+                featureType = self.checkType2.GetName()
+            if featureType:
+                self.vPropertiesDict['type'] = featureType
+            
+        # is connection
+        self.vPropertiesDict['connection'] = self.connection
+        if self.connection:
+            self.vPropertiesDict['layer'] = self.layerChoice.GetStringSelection()
+            if self.radioCats.GetValue() and not self.textCtrlCats.IsEmpty():
+                self.vPropertiesDict['cats'] = self.textCtrlCats.GetValue()
+            elif self.radioWhere.GetValue() and not self.textCtrlWhere.IsEmpty():
+                self.vPropertiesDict['where'] = self.choiceColumns.GetStringSelection() + " " \
+                                                                + self.textCtrlWhere.GetValue()
+        #mask
+        if self.mask.GetValue():
+            self.vPropertiesDict['masked'] = 'y' 
+        else:
+            self.vPropertiesDict['masked'] = 'n'
+
+        #colors
+        if self.type in ('points', 'areas'):
+            if self.outlineCheck.GetValue():
+                self.vPropertiesDict['color'] = convertRGB(self.colorPicker.GetColour())
+                self.vPropertiesDict['width'] = self.widthSpin.GetValue()
+            else:
+                self.vPropertiesDict['color'] = 'none'
+                
+            if self.fillCheck.GetValue():
+                if self.colorPickerRadio.GetValue():
+                    self.vPropertiesDict['fcolor'] = convertRGB(self.fillColorPicker.GetColour())
+                    self.vPropertiesDict['rgbcolumn'] = None
+                if self.colorColRadio.GetValue():
+                    self.vPropertiesDict['fcolor'] = 'none'# this color is taken in case of no record in rgb column
+                    self.vPropertiesDict['rgbcolumn'] = self.colorColChoice.GetStringSelection()
+            else:
+                self.vPropertiesDict['fcolor'] = 'none'    
+                
+        if self.type == 'lines':
+                #hcolor only when no rgbcolumn
+            if self.outlineCheck.GetValue():# and self.fillCheck.GetValue() and self.colorColRadio.GetValue():
+                self.vPropertiesDict['hcolor'] = convertRGB(self.colorPicker.GetColour())
+                self.vPropertiesDict['hwidth'] = self.outWidthSpin.GetValue()
+                
+            else:
+                self.vPropertiesDict['hcolor'] = 'none'
+                
+            if self.colorPickerRadio.GetValue():
+                self.vPropertiesDict['color'] = convertRGB(self.fillColorPicker.GetColour())
+                self.vPropertiesDict['rgbcolumn'] = None
+            if self.colorColRadio.GetValue():
+                self.vPropertiesDict['color'] = 'none'# this color is taken in case of no record in rgb column
+                self.vPropertiesDict['rgbcolumn'] = self.colorColChoice.GetStringSelection()
+        #
+        #size and style
+        #
+        
+        if self.type == 'points':
+            #symbols
+            if self.symbolRadio.GetValue():
+                self.vPropertiesDict['symbol'] = self.symbolChoice.GetStringSelection()
+                self.vPropertiesDict['eps'] = None
+            else:
+                self.vPropertiesDict['eps'] = self.epsFileCtrl.GetValue()
+                self.vPropertiesDict['symbol'] = None
+            #size
+            if self.sizeRadio.GetValue():
+                self.vPropertiesDict['size'] = self.sizeSpin.GetValue()
+                self.vPropertiesDict['sizecolumn'] = None
+                self.vPropertiesDict['scale'] = None
+            else:
+                self.vPropertiesDict['sizecolumn'] = self.sizeColChoice.GetStringSelection()
+                self.vPropertiesDict['scale'] = self.scaleSpin.GetValue()
+                self.vPropertiesDict['size'] = None
+            
+            #rotation
+            self.vPropertiesDict['rotate'] = None
+            self.vPropertiesDict['rotatecolumn'] = None
+            self.vPropertiesDict['rotation'] = False
+            if self.rotateCheck.GetValue():
+                self.vPropertiesDict['rotation'] = True
+            if self.rotateRadio.GetValue():
+                self.vPropertiesDict['rotate'] = self.rotateSpin.GetValue()
+            else:
+                self.vPropertiesDict['rotatecolumn'] = self.rotateColChoice.GetStringSelection()
+                
+        if self.type == 'areas':
+            #pattern
+            self.vPropertiesDict['pat'] = None 
+            if self.patternCheck.GetValue() and bool(self.patFileCtrl.GetValue()):
+                self.vPropertiesDict['pat'] = self.patFileCtrl.GetValue()
+                self.vPropertiesDict['pwidth'] = self.patWidthSpin.GetValue()
+                self.vPropertiesDict['scale'] = self.patScaleSpin.GetValue()
+                
+        if self.type == 'lines':
+            #width
+            if self.cwidthCheck.GetValue():
+                self.vPropertiesDict['cwidth'] = self.widthSpin.GetValue()
+                self.vPropertiesDict['width'] = None
+            else:
+                self.vPropertiesDict['width'] = self.widthSpin.GetValue()
+                self.vPropertiesDict['cwidth'] = None
+            #line style
+            if self.styleCombo.GetValue():
+                self.vPropertiesDict['style'] = self.styleCombo.GetValue() 
+            else:
+                self.vPropertiesDict['style'] = 'solid'
+
+            self.vPropertiesDict['linecap'] = self.linecapChoice.GetStringSelection()
+            
+    def OnOK(self, event):
+        self.update()
+        event.Skip()
+        
+class LegendDialog(PsmapDialog):
+    def __init__(self, parent, id, settings, page):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Legend settings", settings = settings)
+        self.objectType = ('rasterLegend', 'vectorLegend')
+        self.instruction = settings
+        map = self.instruction.FindInstructionByType('map')
+        if map:
+            self.mapId = map.id 
+        else:
+            self.mapId = None
+
+        vector = self.instruction.FindInstructionByType('vector')
+        if vector:
+            self.vectorId = vector.id 
+        else:
+            self.vectorId = None
+
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            self.rasterId = raster.id 
+        else:
+            self.rasterId = None
+
+        self.pageId = self.instruction.FindInstructionByType('page').id
+        currPage = self.instruction[self.pageId].GetInstruction()
+        #raster legend
+        if self.id[0] is not None:
+            self.rasterLegend = self.instruction[self.id[0]]
+            self.rLegendDict = self.rasterLegend.GetInstruction()
+        else:
+            self.id[0] = wx.NewId()
+            self.rasterLegend = RasterLegend(self.id[0])
+            self.rLegendDict = self.rasterLegend.GetInstruction()
+            self.rLegendDict['where'] = currPage['Left'], currPage['Top']
+            
+            
+        #vector legend    
+        if self.id[1] is not None:
+            self.vLegendDict = self.instruction[self.id[1]].GetInstruction()
+        else:
+            self.id[1] = wx.NewId()
+            vectorLegend = VectorLegend(self.id[1])
+            self.vLegendDict = vectorLegend.GetInstruction()
+            self.vLegendDict['where'] = currPage['Left'], currPage['Top']
+            
+        if self.rasterId:
+            self.currRaster = self.instruction[self.rasterId]['raster'] 
+        else:
+            self.currRaster = None
+
+        #notebook
+        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.panelRaster = self._rasterLegend(self.notebook)
+        self.panelVector = self._vectorLegend(self.notebook)  
+        self.OnRaster(None)
+        self.OnRange(None)
+        self.OnIsLegend(None)
+        self.OnSpan(None)
+        self.OnBorder(None)
+                
+        self._layout(self.notebook)
+        self.notebook.ChangeSelection(page)
+        self.notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        
+    def OnPageChanging(self, event):
+        """!Workaround to scroll up to see the checkbox"""
+        wx.CallAfter(self.FindWindowByName('rasterPanel').ScrollChildIntoView,
+                                            self.FindWindowByName('showRLegend'))
+        wx.CallAfter(self.FindWindowByName('vectorPanel').ScrollChildIntoView,
+                                            self.FindWindowByName('showVLegend'))
+                                            
+    def _rasterLegend(self, notebook):
+        panel = scrolled.ScrolledPanel(parent = notebook, id = wx.ID_ANY, size = (-1, 500), style = wx.TAB_TRAVERSAL)
+        panel.SetupScrolling(scroll_x = False, scroll_y = True)
+        panel.SetName('rasterPanel')
+        notebook.AddPage(page = panel, text = _("Raster legend"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        # is legend
+        self.isRLegend = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Show raster legend"))
+        self.isRLegend.SetValue(self.rLegendDict['rLegend'])
+        self.isRLegend.SetName("showRLegend")
+        border.Add(item = self.isRLegend, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        # choose raster
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Source raster"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(1)
+        
+        self.rasterDefault = wx.RadioButton(panel, id = wx.ID_ANY, label = _("current raster"), style = wx.RB_GROUP)
+        self.rasterOther = wx.RadioButton(panel, id = wx.ID_ANY, label = _("select raster"))
+        self.rasterDefault.SetValue(self.rLegendDict['rasterDefault'])#
+        self.rasterOther.SetValue(not self.rLegendDict['rasterDefault'])#
+
+        rasterType = getRasterType(map = self.currRaster)
+
+        self.rasterCurrent = wx.StaticText(panel, id = wx.ID_ANY,
+                                label = _("%(rast)s: type %(type)s") % { 'rast' : self.currRaster,
+                                                                         'type' : rasterType })
+        self.rasterSelect = Select(panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+                                    type = 'raster', multiple = False,
+                                    updateOnPopup = True, onPopup = None)
+        if not self.rLegendDict['rasterDefault']:
+            self.rasterSelect.SetValue(self.rLegendDict['raster'])
+        else:
+            self.rasterSelect.SetValue('')
+        flexSizer.Add(self.rasterDefault, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.rasterCurrent, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border = 10)
+        flexSizer.Add(self.rasterOther, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.rasterSelect, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # type of legend
+        
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Type of legend"))        
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        vbox = wx.BoxSizer(wx.VERTICAL)
+        self.discrete = wx.RadioButton(parent = panel, id = wx.ID_ANY, 
+                        label = " %s " % _("discrete legend (categorical maps)"), style = wx.RB_GROUP)
+        self.continuous = wx.RadioButton(parent = panel, id = wx.ID_ANY, 
+                        label = " %s " % _("continuous color gradient legend (floating point map)"))
+        
+        vbox.Add(self.discrete, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
+        vbox.Add(self.continuous, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 0)
+        sizer.Add(item = vbox, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # size, position and font
+        self.sizePositionFont(legendType = 'raster', parent = panel, mainSizer = border)
+        
+        # advanced settings
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Advanced legend settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        # no data
+        self.nodata = wx.CheckBox(panel, id = wx.ID_ANY, label = _('draw "no data" box'))
+        if self.rLegendDict['nodata'] == 'y':
+            self.nodata.SetValue(True)
+        else: 
+            self.nodata.SetValue(False)
+        #tickbar
+        self.ticks = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw ticks across color table"))
+        if self.rLegendDict['tickbar'] == 'y':
+            self.ticks.SetValue(True)
+        else:
+            self.ticks.SetValue(False)
+        # range
+        if self.rasterId and self.instruction[self.rasterId]['raster']:
+            rinfo = grass.raster_info(self.instruction[self.rasterId]['raster'])
+            self.minim, self.maxim = rinfo['min'], rinfo['max']
+        else:
+            self.minim, self.maxim = 0,0
+        self.range = wx.CheckBox(panel, id = wx.ID_ANY, label = _("range"))
+        self.range.SetValue(self.rLegendDict['range'])
+        self.minText =  wx.StaticText(panel, id = wx.ID_ANY, label = "min (%s)" % self.minim)
+        self.maxText =  wx.StaticText(panel, id = wx.ID_ANY, label = "max (%s)" % self.maxim)       
+        self.min = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(self.rLegendDict['min']))
+        self.max = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(self.rLegendDict['max']))
+        
+        gridBagSizer.Add(self.nodata, pos = (0,0), span = (1,5), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.ticks, pos = (1,0), span = (1,5), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.range, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.minText, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        gridBagSizer.Add(self.min, pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.maxText, pos = (2,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+        gridBagSizer.Add(self.max, pos = (2,4), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+   
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        # bindings
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterDefault)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterOther)
+        self.Bind(wx.EVT_CHECKBOX, self.OnIsLegend, self.isRLegend)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.discrete)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnDiscrete, self.continuous)
+##        self.Bind(wx.EVT_CHECKBOX, self.OnDefaultSize, panel.defaultSize)
+        self.Bind(wx.EVT_CHECKBOX, self.OnRange, self.range)
+        self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster)
+        
+        return panel
+    
+    def _vectorLegend(self, notebook):
+        panel = scrolled.ScrolledPanel(parent = notebook, id = wx.ID_ANY, size = (-1, 500), style = wx.TAB_TRAVERSAL)
+        panel.SetupScrolling(scroll_x = False, scroll_y = True)
+        panel.SetName('vectorPanel')
+        notebook.AddPage(page = panel, text = _("Vector legend"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        # is legend
+        self.isVLegend = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Show vector legend"))
+        self.isVLegend.SetValue(self.vLegendDict['vLegend'])
+        self.isVLegend.SetName("showVLegend")
+        border.Add(item = self.isVLegend, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #vector maps, their order, labels
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Source vector maps"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0,3)
+        gridBagSizer.AddGrowableCol(1,1)
+        
+        vectorText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Choose vector maps and their order in legend"))
+
+        self.vectorListCtrl = CheckListCtrl(panel)
+        
+        self.vectorListCtrl.InsertColumn(0, _("Vector map"))
+        self.vectorListCtrl.InsertColumn(1, _("Label"))
+        if self.vectorId:
+            vectors = sorted(self.instruction[self.vectorId]['list'], key = lambda x: x[3])
+            
+            for vector in vectors:
+                index = self.vectorListCtrl.InsertStringItem(sys.maxint, vector[0].split('@')[0])
+                self.vectorListCtrl.SetStringItem(index, 1, vector[4])
+                self.vectorListCtrl.SetItemData(index, index)
+                self.vectorListCtrl.CheckItem(index, True)
+                if vector[3] == 0:
+                    self.vectorListCtrl.CheckItem(index, False)
+        if not self.vectorId:
+            self.vectorListCtrl.SetColumnWidth(0, 100)
+        else:
+            self.vectorListCtrl.SetColumnWidth(0, wx.LIST_AUTOSIZE)
+        self.vectorListCtrl.SetColumnWidth(1, wx.LIST_AUTOSIZE)
+        
+        self.btnUp = wx.Button(panel, id = wx.ID_ANY, label = _("Up"))
+        self.btnDown = wx.Button(panel, id = wx.ID_ANY, label = _("Down"))
+        self.btnLabel = wx.Button(panel, id = wx.ID_ANY, label = _("Edit label"))
+      
+        gridBagSizer.Add(vectorText, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.vectorListCtrl, pos = (1,0), span = (3,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(self.btnUp, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.btnDown, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.btnLabel, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # size, position and font
+        self.sizePositionFont(legendType = 'vector', parent = panel, mainSizer = border)
+         
+        # border
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Border"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexGridSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5)
+        
+        self.borderCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("draw border around legend"))
+        self.borderColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY, style = wx.FNTP_FONTDESC_AS_LABEL)
+        if self.vLegendDict['border'] == 'none':
+            self.borderColorCtrl.SetColour(wx.BLACK)
+            self.borderCheck.SetValue(False)
+        else:
+            self.borderColorCtrl.SetColour(convertRGB(self.vLegendDict['border']))
+            self.borderCheck.SetValue(True)
+            
+        flexGridSizer.Add(self.borderCheck, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)    
+        flexGridSizer.Add(self.borderColorCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        sizer.Add(item = flexGridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(wx.EVT_BUTTON, self.OnUp, self.btnUp)
+        self.Bind(wx.EVT_BUTTON, self.OnDown, self.btnDown)  
+        self.Bind(wx.EVT_BUTTON, self.OnEditLabel, self.btnLabel)
+        self.Bind(wx.EVT_CHECKBOX, self.OnIsLegend, self.isVLegend)    
+        self.Bind(wx.EVT_CHECKBOX, self.OnSpan, panel.spanRadio)  
+        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.borderCheck)
+        self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnFont, panel.font['fontCtrl']) 
+        
+        panel.SetSizer(border)
+        
+        panel.Fit()
+        return panel
+    
+    def sizePositionFont(self, legendType, parent, mainSizer):
+        """!Insert widgets for size, position and font control"""
+        if legendType == 'raster':
+            legendDict = self.rLegendDict  
+        else:
+            legendDict = self.vLegendDict
+        panel = parent
+        border = mainSizer
+        
+        # size and position        
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size and position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        #unit
+        self.AddUnits(parent = panel, dialogDict = legendDict)
+        unitBox = wx.BoxSizer(wx.HORIZONTAL)
+        unitBox.Add(panel.units['unitsLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border = 10)
+        unitBox.Add(panel.units['unitsCtrl'], proportion = 1, flag = wx.ALL, border = 5)
+        sizer.Add(unitBox, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        hBox = wx.BoxSizer(wx.HORIZONTAL)
+        posBox = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Position"))
+        posSizer = wx.StaticBoxSizer(posBox, wx.VERTICAL)       
+        sizeBox = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))
+        sizeSizer = wx.StaticBoxSizer(sizeBox, wx.VERTICAL) 
+        posGridBagSizer = wx.GridBagSizer(hgap = 10, vgap = 5)
+        posGridBagSizer.AddGrowableRow(2)
+        
+        #position
+        self.AddPosition(parent = panel, dialogDict = legendDict)
+        
+        posGridBagSizer.Add(panel.position['xLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        posGridBagSizer.Add(panel.position['xCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        posGridBagSizer.Add(panel.position['yLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        posGridBagSizer.Add(panel.position['yCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        posGridBagSizer.Add(panel.position['comment'], pos = (2,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
+        posSizer.Add(posGridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        
+        #size
+        width = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width:"))
+        if legendDict['width']:
+            w = self.unitConv.convert(value = float(legendDict['width']), fromUnit = 'inch', toUnit = legendDict['unit'])
+        else: 
+            w = ''
+        panel.widthCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(w), validator = TCValidator("DIGIT_ONLY"))
+        panel.widthCtrl.SetToolTipString(_("Leave the edit field empty, to use default values."))
+        
+        if legendType == 'raster':
+##            panel.defaultSize = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Use default size"))
+##            panel.defaultSize.SetValue(legendDict['defaultSize'])
+            
+            panel.heightOrColumnsLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:"))
+            if legendDict['height']:
+                h = self.unitConv.convert(value = float(legendDict['height']), fromUnit = 'inch', toUnit = legendDict['unit'])
+            else:
+                h = ''
+            panel.heightOrColumnsCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = str(h), validator = TCValidator("DIGIT_ONLY"))
+            
+            self.rSizeGBSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+##            self.rSizeGBSizer.Add(panel.defaultSize, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.rSizeGBSizer.Add(width, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.rSizeGBSizer.Add(panel.widthCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.rSizeGBSizer.Add(panel.heightOrColumnsLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.rSizeGBSizer.Add(panel.heightOrColumnsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            sizeSizer.Add(self.rSizeGBSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+            
+        if legendType == 'vector':
+            panel.widthCtrl.SetToolTipString(_("Width of the color symbol (for lines)\nin front of the legend text")) 
+            #columns
+            minVect, maxVect = 0, 0
+            if self.vectorId:
+                minVect = 1
+                maxVect = min(10, len(self.instruction[self.vectorId]['list']))
+            cols = wx.StaticText(panel, id = wx.ID_ANY, label = _("Columns:"))
+            panel.colsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, value = "",
+                                        min = minVect, max = maxVect, initial = legendDict['cols'])
+            #span
+            panel.spanRadio = wx.CheckBox(panel, id = wx.ID_ANY, label = _("column span:"))
+            panel.spanTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = '')
+            panel.spanTextCtrl.SetToolTipString(_("Column separation distance between the left edges\n"\
+                                                "of two columns in a multicolumn legend"))
+            if legendDict['span']:
+                panel.spanRadio.SetValue(True)
+                s = self.unitConv.convert(value = float(legendDict['span']), fromUnit = 'inch', toUnit = legendDict['unit'])    
+                panel.spanTextCtrl.SetValue(str(s))
+            else:
+                panel.spanRadio.SetValue(False)
+                
+            self.vSizeGBSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+            self.vSizeGBSizer.AddGrowableCol(1)
+            self.vSizeGBSizer.Add(width, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.vSizeGBSizer.Add(panel.widthCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.vSizeGBSizer.Add(cols, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.vSizeGBSizer.Add(panel.colsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.vSizeGBSizer.Add(panel.spanRadio, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            self.vSizeGBSizer.Add(panel.spanTextCtrl, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+            sizeSizer.Add(self.vSizeGBSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)        
+        
+        hBox.Add(posSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 3)
+        hBox.Add(sizeSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 3)
+        sizer.Add(hBox, proportion = 0, flag = wx.EXPAND, border = 0)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+              
+        # font        
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        fontSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(1)
+        
+        if legendType == 'raster':
+            self.AddFont(parent = panel, dialogDict = legendDict, color = True)
+        else:
+            self.AddFont(parent = panel, dialogDict = legendDict, color = False)            
+        flexSizer.Add(panel.font['fontLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(panel.font['fontCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(panel.font['fontSizeLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(panel.font['fontSizeCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        if legendType == 'raster':
+            flexSizer.Add(panel.font['colorLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+            flexSizer.Add(panel.font['colorCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        fontSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = fontSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)    
+
+    #   some enable/disable methods  
+        
+    def OnIsLegend(self, event):
+        """!Enables and disables controls, it depends if raster or vector legend is checked"""
+        page = self.notebook.GetSelection()
+        if page == 0 or event is None:
+            children = self.panelRaster.GetChildren()
+            if self.isRLegend.GetValue():
+                for i,widget in enumerate(children):
+                        widget.Enable()
+                self.OnRaster(None)
+                self.OnRange(None)
+                self.OnDiscrete(None)
+            else:
+                for widget in children:
+                    if widget.GetName() != 'showRLegend':
+                        widget.Disable()
+        if page == 1 or event is None:
+            children = self.panelVector.GetChildren()
+            if self.isVLegend.GetValue():
+                for i, widget in enumerate(children):
+                        widget.Enable()
+                self.OnSpan(None)
+                self.OnBorder(None)
+            else:
+                for widget in children:
+                    if widget.GetName() != 'showVLegend':
+                        widget.Disable()
+                    
+    def OnRaster(self, event):
+        if self.rasterDefault.GetValue():#default
+            self.rasterSelect.Disable()
+            type = getRasterType(self.currRaster)
+        else:#select raster
+            self.rasterSelect.Enable()
+            map = self.rasterSelect.GetValue()
+            type = getRasterType(map)
+  
+        if type == 'CELL':
+            self.discrete.SetValue(True)
+        elif type in ('FCELL', 'DCELL'):
+            self.continuous.SetValue(True)
+        if event is None:
+            if self.rLegendDict['discrete'] == 'y':
+                self.discrete.SetValue(True)
+            elif self.rLegendDict['discrete'] == 'n':
+                self.continuous.SetValue(True)
+        self.OnDiscrete(None)
+        
+    def OnDiscrete(self, event):
+        """! Change control according to the type of legend"""
+        enabledSize = self.panelRaster.heightOrColumnsCtrl.IsEnabled()
+        self.panelRaster.heightOrColumnsCtrl.Destroy()
+        if self.discrete.GetValue():
+            self.panelRaster.heightOrColumnsLabel.SetLabel(_("Columns:"))
+            self.panelRaster.heightOrColumnsCtrl = wx.SpinCtrl(self.panelRaster, id = wx.ID_ANY, value = "", min = 1, max = 10, initial = self.rLegendDict['cols'])
+            self.panelRaster.heightOrColumnsCtrl.Enable(enabledSize)
+            self.nodata.Enable()
+            self.range.Disable()
+            self.min.Disable()
+            self.max.Disable()
+            self.minText.Disable()
+            self.maxText.Disable()
+            self.ticks.Disable()
+        else:
+            self.panelRaster.heightOrColumnsLabel.SetLabel(_("Height:"))
+            if self.rLegendDict['height']:
+                h = self.unitConv.convert(value = float(self.rLegendDict['height']), fromUnit = 'inch', toUnit = self.rLegendDict['unit'])
+            else:
+                h = ''
+            self.panelRaster.heightOrColumnsCtrl = wx.TextCtrl(self.panelRaster, id = wx.ID_ANY,
+                                                    value = str(h), validator = TCValidator("DIGIT_ONLY"))
+            self.panelRaster.heightOrColumnsCtrl.Enable(enabledSize)
+            self.nodata.Disable()
+            self.range.Enable()
+            if self.range.GetValue():
+                self.minText.Enable()
+                self.maxText.Enable()
+                self.min.Enable()
+                self.max.Enable()
+            self.ticks.Enable()
+        
+        self.rSizeGBSizer.Add(self.panelRaster.heightOrColumnsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.panelRaster.Layout()
+        self.panelRaster.Fit()   
+        
+    def OnRange(self, event):
+        if not self.range.GetValue():
+            self.min.Disable()        
+            self.max.Disable()
+            self.minText.Disable()
+            self.maxText.Disable()
+        else:
+            self.min.Enable()        
+            self.max.Enable() 
+            self.minText.Enable()
+            self.maxText.Enable()           
+     
+    def OnUp(self, event):
+        """!Moves selected map up, changes order in vector legend"""
+        if self.vectorListCtrl.GetFirstSelected() != -1:
+            pos = self.vectorListCtrl.GetFirstSelected()
+            if pos:
+                idx1 = self.vectorListCtrl.GetItemData(pos) - 1
+                idx2 = self.vectorListCtrl.GetItemData(pos - 1) + 1
+                self.vectorListCtrl.SetItemData(pos, idx1) 
+                self.vectorListCtrl.SetItemData(pos - 1, idx2) 
+                self.vectorListCtrl.SortItems(cmp)
+                if pos > 0:
+                    selected = (pos - 1) 
+                else:
+                    selected = 0
+
+                self.vectorListCtrl.Select(selected)
+       
+    def OnDown(self, event):
+        """!Moves selected map down, changes order in vector legend"""
+        if self.vectorListCtrl.GetFirstSelected() != -1:
+            pos = self.vectorListCtrl.GetFirstSelected()
+            if pos != self.vectorListCtrl.GetItemCount() - 1:
+                idx1 = self.vectorListCtrl.GetItemData(pos) + 1
+                idx2 = self.vectorListCtrl.GetItemData(pos + 1) - 1
+                self.vectorListCtrl.SetItemData(pos, idx1) 
+                self.vectorListCtrl.SetItemData(pos + 1, idx2) 
+                self.vectorListCtrl.SortItems(cmp)
+                if pos < self.vectorListCtrl.GetItemCount() -1:
+                    selected = (pos + 1) 
+                else:
+                    selected = self.vectorListCtrl.GetItemCount() -1
+
+                self.vectorListCtrl.Select(selected)
+                
+    def OnEditLabel(self, event):
+        """!Change legend label of vector map"""
+        if self.vectorListCtrl.GetFirstSelected() != -1:
+            idx = self.vectorListCtrl.GetFirstSelected()
+            default = self.vectorListCtrl.GetItem(idx, 1).GetText()
+            dlg = wx.TextEntryDialog(self, message = _("Edit legend label:"), caption = _("Edit label"),
+                                    defaultValue = default, style = wx.OK|wx.CANCEL|wx.CENTRE)
+            if dlg.ShowModal() == wx.ID_OK:
+                new = dlg.GetValue()
+                self.vectorListCtrl.SetStringItem(idx, 1, new)
+            dlg.Destroy()
+        
+    def OnSpan(self, event):
+        self.panelVector.spanTextCtrl.Enable(self.panelVector.spanRadio.GetValue())
+    def OnFont(self, event):
+        """!Changes default width according to fontsize, width [inch] = fontsize[pt]/24"""   
+##        fontsize = self.panelVector.font['fontCtrl'].GetSelectedFont().GetPointSize() 
+        fontsize = self.panelVector.font['fontSizeCtrl'].GetValue()
+        unit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
+        w = fontsize/24.
+        width = self.unitConv.convert(value = w, fromUnit = 'inch', toUnit = unit)
+        self.panelVector.widthCtrl.SetValue("%3.2f" % width)
+        
+    def OnBorder(self, event):
+        """!Enables/disables colorPickerCtrl for border"""    
+        self.borderColorCtrl.Enable(self.borderCheck.GetValue())
+    
+    def updateRasterLegend(self):
+        """!Save information from raster legend dialog to dictionary"""
+
+        #is raster legend
+        if not self.isRLegend.GetValue():
+            self.rLegendDict['rLegend'] = False
+        else:
+            self.rLegendDict['rLegend'] = True
+        #units
+        currUnit = self.unitConv.findUnit(self.panelRaster.units['unitsCtrl'].GetStringSelection())
+        self.rLegendDict['unit'] = currUnit
+        # raster
+        if self.rasterDefault.GetValue():
+            self.rLegendDict['rasterDefault'] = True
+            self.rLegendDict['raster'] = self.currRaster
+        else:
+            self.rLegendDict['rasterDefault'] = False
+            self.rLegendDict['raster'] = self.rasterSelect.GetValue()
+        if self.rLegendDict['rLegend'] and not self.rLegendDict['raster']:
+            wx.MessageBox(message = _("No raster map selected!"),
+                                    caption = _('No raster'), style = wx.OK|wx.ICON_ERROR)
+            return False
+            
+        if self.rLegendDict['raster']:
+            # type and range of map
+            rasterType = getRasterType(self.rLegendDict['raster'])
+            if rasterType is None:
+                return False
+            self.rLegendDict['type'] = rasterType
+            
+            
+            #discrete
+            if self.discrete.GetValue():
+                self.rLegendDict['discrete'] = 'y'
+            else:
+                self.rLegendDict['discrete'] = 'n'   
+                    
+            # font 
+            self.rLegendDict['font'] = self.panelRaster.font['fontCtrl'].GetStringSelection()
+            self.rLegendDict['fontsize'] = self.panelRaster.font['fontSizeCtrl'].GetValue()
+            color = self.panelRaster.font['colorCtrl'].GetColour()
+            self.rLegendDict['color'] = convertRGB(color)
+
+            # position
+            x = self.unitConv.convert(value = float(self.panelRaster.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(self.panelRaster.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+            self.rLegendDict['where'] = (x, y)
+            # estimated size
+            width = self.panelRaster.widthCtrl.GetValue()
+            try:
+                width = float(width)
+                width = self.unitConv.convert(value = width, fromUnit = currUnit, toUnit = 'inch')
+            except ValueError:
+                width = None
+            self.rLegendDict['width'] = width
+            if self.rLegendDict['discrete'] == 'n':
+                height = self.panelRaster.heightOrColumnsCtrl.GetValue()    
+                try:
+                    height = float(height)
+                    height = self.unitConv.convert(value = height, fromUnit = currUnit, toUnit = 'inch')
+                except ValueError:
+                    height = None
+                self.rLegendDict['height'] = height
+            else:
+                cols = self.panelRaster.heightOrColumnsCtrl.GetValue()
+                self.rLegendDict['cols'] = cols
+            drawHeight = self.rasterLegend.EstimateHeight(raster = self.rLegendDict['raster'], discrete = self.rLegendDict['discrete'],
+                                            fontsize = self.rLegendDict['fontsize'], cols = self.rLegendDict['cols'],
+                                            height = self.rLegendDict['height'])
+            drawWidth = self.rasterLegend.EstimateWidth(raster = self.rLegendDict['raster'], discrete = self.rLegendDict['discrete'],
+                                            fontsize = self.rLegendDict['fontsize'], cols = self.rLegendDict['cols'],
+                                            width = self.rLegendDict['width'], paperInstr = self.instruction[self.pageId])
+            self.rLegendDict['rect'] = wx.Rect2D(x = x, y = y, w = drawWidth, h = drawHeight)
+                        
+            # no data
+            if self.rLegendDict['discrete'] == 'y':
+                if self.nodata.GetValue():
+                    self.rLegendDict['nodata'] = 'y'
+                else:
+                    self.rLegendDict['nodata'] = 'n'
+            # tickbar
+            elif self.rLegendDict['discrete'] == 'n':
+                if self.ticks.GetValue():
+                    self.rLegendDict['tickbar'] = 'y'
+                else:
+                    self.rLegendDict['tickbar'] = 'n'
+            # range
+                if self.range.GetValue():
+                    self.rLegendDict['range'] = True
+                    self.rLegendDict['min'] = self.min.GetValue()
+                    self.rLegendDict['max'] = self.max.GetValue()
+                else:
+                    self.rLegendDict['range'] = False
+         
+        if not self.id[0] in self.instruction:
+            rasterLegend = RasterLegend(self.id[0])
+            self.instruction.AddInstruction(rasterLegend)
+        self.instruction[self.id[0]].SetInstruction(self.rLegendDict)
+
+        if self.id[0] not in self.parent.objectId:
+            self.parent.objectId.append(self.id[0])
+        return True
+    
+    def updateVectorLegend(self):
+        """!Save information from vector legend dialog to dictionary"""
+
+        vector = self.instruction.FindInstructionByType('vector')
+        if vector:
+            self.vectorId = vector.id 
+        else:
+            self.vectorId = None
+
+        #is vector legend
+        if not self.isVLegend.GetValue():
+            self.vLegendDict['vLegend'] = False
+        else:
+            self.vLegendDict['vLegend'] = True   
+        if self.vLegendDict['vLegend'] == True and self.vectorId is not None:
+            # labels
+            #reindex order
+            idx = 1
+            for item in range(self.vectorListCtrl.GetItemCount()):
+                if self.vectorListCtrl.IsChecked(item):
+                    self.vectorListCtrl.SetItemData(item, idx)
+                    idx += 1
+                else:
+                    self.vectorListCtrl.SetItemData(item, 0)
+            if idx == 1: 
+                self.vLegendDict['vLegend'] = False     
+            else:
+                vList = self.instruction[self.vectorId]['list']
+                for i, vector in enumerate(vList):
+                    item = self.vectorListCtrl.FindItem(start = -1, str = vector[0].split('@')[0])
+                    vList[i][3] = self.vectorListCtrl.GetItemData(item)
+                    vList[i][4] = self.vectorListCtrl.GetItem(item, 1).GetText()
+                vmaps = self.instruction.FindInstructionByType('vProperties', list = True)
+                for vmap, vector in zip(vmaps, vList):
+                    self.instruction[vmap.id]['lpos'] = vector[3]
+                    self.instruction[vmap.id]['label'] = vector[4]
+                #units
+                currUnit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
+                self.vLegendDict['unit'] = currUnit
+                # position
+                x = self.unitConv.convert(value = float(self.panelVector.position['xCtrl'].GetValue()),
+                                                                fromUnit = currUnit, toUnit = 'inch')
+                y = self.unitConv.convert(value = float(self.panelVector.position['yCtrl'].GetValue()),
+                                                                fromUnit = currUnit, toUnit = 'inch')
+                self.vLegendDict['where'] = (x, y)
+                
+                # font 
+                self.vLegendDict['font'] = self.panelVector.font['fontCtrl'].GetStringSelection()
+                self.vLegendDict['fontsize'] = self.panelVector.font['fontSizeCtrl'].GetValue()
+                dc = wx.PaintDC(self)
+                font = dc.GetFont()
+                dc.SetFont(wx.Font(pointSize = self.vLegendDict['fontsize'], family = font.GetFamily(),
+                                   style = font.GetStyle(), weight = wx.FONTWEIGHT_NORMAL))
+                #size
+                width = self.unitConv.convert(value = float(self.panelVector.widthCtrl.GetValue()),
+                                              fromUnit = currUnit, toUnit = 'inch')
+                self.vLegendDict['width'] = width
+                self.vLegendDict['cols'] = self.panelVector.colsCtrl.GetValue()
+                if self.panelVector.spanRadio.GetValue() and self.panelVector.spanTextCtrl.GetValue():
+                    self.vLegendDict['span'] = self.panelVector.spanTextCtrl.GetValue()
+                else:
+                    self.vLegendDict['span'] = None
+                    
+                # size estimation
+                vectors = self.instruction[self.vectorId]['list']
+                labels = [vector[4] for vector in vectors if vector[3] != 0]
+                extent = dc.GetTextExtent(max(labels, key = len))
+                wExtent = self.unitConv.convert(value = extent[0], fromUnit = 'pixel', toUnit = 'inch')
+                hExtent = self.unitConv.convert(value = extent[1], fromUnit = 'pixel', toUnit = 'inch')
+                w = (width + wExtent) * self.vLegendDict['cols']
+                h = len(labels) * hExtent / self.vLegendDict['cols']
+                h *= 1.1
+                self.vLegendDict['rect'] = wx.Rect2D(x, y, w, h)
+                
+                #border
+                if self.borderCheck.GetValue():
+                    color = self.borderColorCtrl.GetColour()
+                    self.vLegendDict['border'] = convertRGB(color)
+                    
+                else:
+                    self.vLegendDict['border'] = 'none'
+                                 
+        if not self.id[1] in self.instruction:
+            vectorLegend = VectorLegend(self.id[1])
+            self.instruction.AddInstruction(vectorLegend)
+        self.instruction[self.id[1]].SetInstruction(self.vLegendDict)
+        if self.id[1] not in self.parent.objectId:
+            self.parent.objectId.append(self.id[1])
+        return True
+    
+    def update(self):
+        okR = self.updateRasterLegend()
+        okV = self.updateVectorLegend()
+        if okR and okV:
+            return True
+        return False
+        
+    def updateDialog(self):
+        """!Update legend coordinates after moving"""
+        
+        # raster legend    
+        if 'rect' in self.rLegendDict:
+            x, y = self.rLegendDict['rect'][:2]
+            currUnit = self.unitConv.findUnit(self.panelRaster.units['unitsCtrl'].GetStringSelection())
+            x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+            y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+            self.panelRaster.position['xCtrl'].SetValue("%5.3f" % x)
+            self.panelRaster.position['yCtrl'].SetValue("%5.3f" % y)
+        #update name and type of raster
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            self.rasterId = raster.id 
+        else:
+            self.rasterId = None 
+
+        if raster:
+            currRaster = raster['raster'] 
+        else:
+            currRaster = None
+            
+        rasterType = getRasterType(map = currRaster)
+        self.rasterCurrent.SetLabel(_("%(rast)s: type %(type)s") % \
+                                        { 'rast' : currRaster, 'type' : str(rasterType) })
+        
+        # vector legend       
+        if 'rect' in self.vLegendDict:
+            x, y = self.vLegendDict['rect'][:2]
+            currUnit = self.unitConv.findUnit(self.panelVector.units['unitsCtrl'].GetStringSelection())
+            x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+            y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+            self.panelVector.position['xCtrl'].SetValue("%5.3f" % x)
+            self.panelVector.position['yCtrl'].SetValue("%5.3f" % y)
+        # update vector maps
+        if self.instruction.FindInstructionByType('vector'):
+            vectors = sorted(self.instruction.FindInstructionByType('vector')['list'], key = lambda x: x[3])
+            self.vectorListCtrl.DeleteAllItems()
+            for vector in vectors:
+                index = self.vectorListCtrl.InsertStringItem(sys.maxint, vector[0].split('@')[0])
+                self.vectorListCtrl.SetStringItem(index, 1, vector[4])
+                self.vectorListCtrl.SetItemData(index, index)
+                self.vectorListCtrl.CheckItem(index, True)
+                if vector[3] == 0:
+                    self.vectorListCtrl.CheckItem(index, False)
+            self.panelVector.colsCtrl.SetRange(1, min(10, len(self.instruction.FindInstructionByType('vector')['list'])))
+            self.panelVector.colsCtrl.SetValue(1)
+        else:
+            self.vectorListCtrl.DeleteAllItems()
+            self.panelVector.colsCtrl.SetRange(0,0)
+            self.panelVector.colsCtrl.SetValue(0)
+             
+class MapinfoDialog(PsmapDialog):
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Mapinfo settings", settings = settings)
+        
+        self.objectType = ('mapinfo',)
+        if self.id is not None:
+            self.mapinfo = self.instruction[self.id]
+            self.mapinfoDict = self.mapinfo.GetInstruction()
+        else:
+            self.id = wx.NewId()
+            self.mapinfo = Mapinfo(self.id)
+            self.mapinfoDict = self.mapinfo.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.mapinfoDict['where'] = page['Left'], page['Top']
+
+        self.panel = self._mapinfoPanel()
+        
+        self._layout(self.panel)
+        self.OnIsBackground(None)
+        self.OnIsBorder(None)
+
+    def _mapinfoPanel(self):
+        panel = wx.Panel(parent = self, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        #panel.SetupScrolling(scroll_x = False, scroll_y = True)
+        border = wx.BoxSizer(wx.VERTICAL)
+                
+        # position     
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddPosition(parent = panel, dialogDict = self.mapinfoDict)
+        self.AddUnits(parent = panel, dialogDict = self.mapinfoDict)
+        gridBagSizer.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # font
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddFont(parent = panel, dialogDict = self.mapinfoDict)#creates font color too, used below
+        
+        gridBagSizer.Add(panel.font['fontLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.font['fontCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.font['fontSizeLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.font['fontSizeCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.font['colorLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        gridBagSizer.Add(panel.font['colorCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(item = gridBagSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        # colors
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Color settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(1)
+        
+        self.colors = {}
+        self.colors['borderCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use border color:"))
+        self.colors['backgroundCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("use background color:"))
+        self.colors['borderColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.colors['backgroundColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        
+        if self.mapinfoDict['border'] == None:
+            self.mapinfoDict['border'] = 'none'
+        if self.mapinfoDict['border'] != 'none':
+            self.colors['borderCtrl'].SetValue(True) 
+            self.colors['borderColor'].SetColour(convertRGB(self.mapinfoDict['border']))
+        else:
+            self.colors['borderCtrl'].SetValue(False)
+            self.colors['borderColor'].SetColour(convertRGB('black'))
+            
+        if self.mapinfoDict['background'] == None:
+            self.mapinfoDict['background'] == 'none'
+        if self.mapinfoDict['background'] != 'none':
+            self.colors['backgroundCtrl'].SetValue(True) 
+            self.colors['backgroundColor'].SetColour(convertRGB(self.mapinfoDict['background']))
+        else:
+            self.colors['backgroundCtrl'].SetValue(False)
+            self.colors['backgroundColor'].SetColour(convertRGB('white'))
+                    
+        flexSizer.Add(self.colors['borderCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.colors['borderColor'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.colors['backgroundCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexSizer.Add(self.colors['backgroundColor'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        
+        self.Bind(wx.EVT_CHECKBOX, self.OnIsBorder, self.colors['borderCtrl'])
+        self.Bind(wx.EVT_CHECKBOX, self.OnIsBackground, self.colors['backgroundCtrl'])
+        
+        return panel
+    
+    def OnIsBackground(self, event):
+        if self.colors['backgroundCtrl'].GetValue():
+            self.colors['backgroundColor'].Enable()
+            self.update()
+        else:
+            self.colors['backgroundColor'].Disable()
+                        
+    def OnIsBorder(self, event):
+        if self.colors['borderCtrl'].GetValue():
+            self.colors['borderColor'].Enable()
+            self.update()
+        else:
+            self.colors['borderColor'].Disable() 
+                                           
+    def update(self):
+
+        #units
+        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
+        self.mapinfoDict['unit'] = currUnit
+        
+        # position
+        if self.panel.position['xCtrl'].GetValue():
+            x = self.panel.position['xCtrl'].GetValue() 
+        else:
+            x = self.mapinfoDict['where'][0]
+
+        if self.panel.position['yCtrl'].GetValue():
+            y = self.panel.position['yCtrl'].GetValue() 
+        else:
+            y = self.mapinfoDict['where'][1]
+
+        x = self.unitConv.convert(value = float(self.panel.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+        y = self.unitConv.convert(value = float(self.panel.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+        self.mapinfoDict['where'] = (x, y)
+        
+        # font
+        self.mapinfoDict['font'] =  self.panel.font['fontCtrl'].GetStringSelection()
+        self.mapinfoDict['fontsize'] = self.panel.font['fontSizeCtrl'].GetValue()
+
+        #colors
+        color = self.panel.font['colorCtrl'].GetColour()
+        self.mapinfoDict['color'] = convertRGB(color)
+        
+        if self.colors['backgroundCtrl'].GetValue():    
+            background = self.colors['backgroundColor'].GetColour()
+            self.mapinfoDict['background'] = convertRGB(background)
+        else:
+            self.mapinfoDict['background'] = 'none'
+
+        if self.colors['borderCtrl'].GetValue():    
+            border = self.colors['borderColor'].GetColour()
+            self.mapinfoDict['border'] = convertRGB(border)
+        else:
+            self.mapinfoDict['border'] = 'none'
+        
+        # estimation of size
+        self.mapinfoDict['rect'] = self.mapinfo.EstimateRect(self.mapinfoDict)
+
+        if self.id not in self.instruction:
+            mapinfo = Mapinfo(self.id)
+            self.instruction.AddInstruction(mapinfo)
+            
+        self.instruction[self.id].SetInstruction(self.mapinfoDict)
+
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+            
+        self.updateDialog()
+
+        return True
+    
+    def updateDialog(self):
+        """!Update mapinfo coordinates, after moving"""
+        x, y = self.mapinfoDict['where']
+        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.panel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.panel.position['yCtrl'].SetValue("%5.3f" % y)
+             
+class ScalebarDialog(PsmapDialog):
+    """!Dialog for scale bar"""
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Scale bar settings", settings = settings)
+        self.objectType = ('scalebar',)
+        if self.id is not None:
+            self.scalebar = self.instruction[id]
+            self.scalebarDict = self.scalebar.GetInstruction()
+        else:
+            self.id = wx.NewId()
+            self.scalebar = Scalebar(self.id)
+            self.scalebarDict = self.scalebar.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.scalebarDict['where'] = page['Left'], page['Top']
+
+        self.panel = self._scalebarPanel()
+        
+        self._layout(self.panel)
+        
+        self.mapUnit = projInfo()['units'].lower()
+        if projInfo()['proj'] == 'xy':
+            self.mapUnit = 'meters'
+        if self.mapUnit not in self.unitConv.getAllUnits():
+            wx.MessageBox(message = _("Units of current projection are not supported,\n meters will be used!"),
+                            caption = _('Unsupported units'),
+                                    style = wx.OK|wx.ICON_ERROR)
+            self.mapUnit = 'meters'
+            
+    def _scalebarPanel(self):
+        panel = wx.Panel(parent = self, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        border = wx.BoxSizer(wx.VERTICAL)
+        #        
+        # position
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddUnits(parent = panel, dialogDict = self.scalebarDict)
+        self.AddPosition(parent = panel, dialogDict = self.scalebarDict)
+        
+        if self.scalebarDict['rect']: # set position, ref point is center and not left top corner
+            
+            x = self.unitConv.convert(value = self.scalebarDict['where'][0] - self.scalebarDict['rect'].Get()[2]/2,
+                                                    fromUnit = 'inch', toUnit = self.scalebarDict['unit'])
+            y = self.unitConv.convert(value = self.scalebarDict['where'][1] - self.scalebarDict['rect'].Get()[3]/2,
+                                                    fromUnit = 'inch', toUnit = self.scalebarDict['unit'])
+            panel.position['xCtrl'].SetValue("%5.3f" % x)
+            panel.position['yCtrl'].SetValue("%5.3f" % y)
+        
+        gridBagSizer.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag =wx.ALIGN_BOTTOM, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        # size
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(1)
+        
+        lengthText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Length:"))
+        heightText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Height:"))
+        
+        self.lengthTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, validator = TCValidator('DIGIT_ONLY'))
+        self.lengthTextCtrl.SetToolTipString(_("Scalebar length is given in map units"))
+        
+        self.heightTextCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, validator = TCValidator('DIGIT_ONLY'))
+        self.heightTextCtrl.SetToolTipString(_("Scalebar height is real height on paper"))
+        
+        choices = [_('default')] + self.unitConv.getMapUnitsNames()
+        self.unitsLength = wx.Choice(panel, id = wx.ID_ANY, choices = choices)
+        choices = self.unitConv.getPageUnitsNames()
+        self.unitsHeight = wx.Choice(panel, id = wx.ID_ANY, choices = choices)
+        
+        # set values
+        unitName = self.unitConv.findName(self.scalebarDict['unitsLength'])
+        if unitName:
+            self.unitsLength.SetStringSelection(unitName)
+        else:
+            if self.scalebarDict['unitsLength'] == 'auto':
+                 self.unitsLength.SetSelection(0)
+            elif self.scalebarDict['unitsLength'] == 'nautmiles':
+                 self.unitsLength.SetStringSelection(self.unitConv.findName("nautical miles"))
+        self.unitsHeight.SetStringSelection(self.unitConv.findName(self.scalebarDict['unitsHeight']))
+        if self.scalebarDict['length']:
+            self.lengthTextCtrl.SetValue(str(self.scalebarDict['length']))
+        else: #estimate default
+            reg = grass.region()
+            w = int((reg['e'] - reg['w'])/3)
+            w = round(w, -len(str(w)) + 2) #12345 -> 12000
+            self.lengthTextCtrl.SetValue(str(w))
+            
+        h = self.unitConv.convert(value = self.scalebarDict['height'], fromUnit = 'inch',
+                                                toUnit =  self.scalebarDict['unitsHeight']) 
+        self.heightTextCtrl.SetValue(str(h))
+        
+        gridBagSizer.Add(lengthText, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.lengthTextCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.unitsLength, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(heightText, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.heightTextCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.unitsHeight, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+      
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        #
+        #style
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Style"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        
+        
+        sbTypeText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Type:"))
+        self.sbCombo = wx.combo.BitmapComboBox(panel, style = wx.CB_READONLY)
+        # only temporary, images must be moved away
+        imagePath = os.path.join(globalvar.ETCIMGDIR, "scalebar-fancy.png"), os.path.join(globalvar.ETCIMGDIR, "scalebar-simple.png") 
+        for item, path in zip(['fancy', 'simple'], imagePath):
+            if not os.path.exists(path):
+                bitmap = wx.EmptyBitmap(0,0)
+            else:
+                bitmap = wx.Bitmap(path)
+            self.sbCombo.Append(item = '', bitmap = bitmap, clientData = item[0])
+        #self.sbCombo.Append(item = 'simple', bitmap = wx.Bitmap("./images/scalebar-simple.png"), clientData = 's')
+        if self.scalebarDict['scalebar'] == 'f':
+            self.sbCombo.SetSelection(0)
+        elif self.scalebarDict['scalebar'] == 's':
+            self.sbCombo.SetSelection(1)
+            
+        sbSegmentsText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Number of segments:"))
+        self.sbSegmentsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 4)
+        self.sbSegmentsCtrl.SetValue(self.scalebarDict['segment'])
+        
+        sbLabelsText1 = wx.StaticText(panel, id = wx.ID_ANY, label = _("Label every "))
+        sbLabelsText2 = wx.StaticText(panel, id = wx.ID_ANY, label = _("segments"))
+        self.sbLabelsCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 1, max = 30, initial = 1)
+        self.sbLabelsCtrl.SetValue(self.scalebarDict['numbers'])
+        
+        #font
+        fontsizeText = wx.StaticText(panel, id = wx.ID_ANY, label = _("Font size:"))
+        self.fontsizeCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 4, max = 30, initial = 10)
+        self.fontsizeCtrl.SetValue(self.scalebarDict['fontsize'])
+        
+        self.backgroundCheck = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent text background"))
+        if self.scalebarDict['background'] == 'y':
+            self.backgroundCheck.SetValue(False)
+        else:
+            self.backgroundCheck.SetValue(True)
+
+        gridBagSizer.Add(sbTypeText, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sbCombo, pos = (0,1), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        gridBagSizer.Add(sbSegmentsText, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sbSegmentsCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(sbLabelsText1, pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.sbLabelsCtrl, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(sbLabelsText2, pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(fontsizeText, pos = (3,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.fontsizeCtrl, pos = (3,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.backgroundCheck, pos = (4, 0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        
+        return panel
+                           
+    def update(self):
+        """!Save information from dialog"""
+
+        #units
+        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
+        self.scalebarDict['unit'] = currUnit
+        # position
+        if self.panel.position['xCtrl'].GetValue():
+            x = self.panel.position['xCtrl'].GetValue() 
+        else:
+            x = self.scalebarDict['where'][0]
+
+        if self.panel.position['yCtrl'].GetValue():
+            y = self.panel.position['yCtrl'].GetValue() 
+        else:
+            y = self.scalebarDict['where'][1]
+
+        x = self.unitConv.convert(value = float(self.panel.position['xCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+        y = self.unitConv.convert(value = float(self.panel.position['yCtrl'].GetValue()), fromUnit = currUnit, toUnit = 'inch')
+        
+        #style
+        self.scalebarDict['scalebar'] = self.sbCombo.GetClientData(self.sbCombo.GetSelection())
+        self.scalebarDict['segment'] = self.sbSegmentsCtrl.GetValue()
+        self.scalebarDict['numbers'] = self.sbLabelsCtrl.GetValue()
+        self.scalebarDict['fontsize'] = self.fontsizeCtrl.GetValue()
+        if self.backgroundCheck.GetValue():
+            self.scalebarDict['background'] = 'n' 
+        else:
+            self.scalebarDict['background'] = 'y'
+
+        
+        # size
+        
+        # height
+        self.scalebarDict['unitsHeight'] = self.unitConv.findUnit(self.unitsHeight.GetStringSelection())
+        try:
+            height = float(self.heightTextCtrl.GetValue())  
+            height = self.unitConv.convert(value = height, fromUnit = self.scalebarDict['unitsHeight'], toUnit = 'inch') 
+        except (ValueError, SyntaxError):
+            height = 0.1 #default in inch
+        self.scalebarDict['height'] = height    
+        
+        #length
+        if self.unitsLength.GetSelection() == 0:
+            selected = 'auto'
+        else:
+            selected = self.unitConv.findUnit(self.unitsLength.GetStringSelection())
+            if selected == 'nautical miles':
+                selected = 'nautmiles'
+        self.scalebarDict['unitsLength'] = selected
+        try:
+            length = float(self.lengthTextCtrl.GetValue())
+        except (ValueError, SyntaxError):
+            wx.MessageBox(message = _("Length of scale bar is not defined"),
+                                    caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+            return False
+        self.scalebarDict['length'] = length
+            
+        # estimation of size
+        map = self.instruction.FindInstructionByType('map')
+        if not map:
+            map = self.instruction.FindInstructionByType('initMap')
+        mapId = map.id
+         
+        rectSize = self.scalebar.EstimateSize(scalebarDict = self.scalebarDict,
+                                                                scale = self.instruction[mapId]['scale'])
+        self.scalebarDict['rect'] = wx.Rect2D(x = x, y = y, w = rectSize[0], h = rectSize[1])
+        self.scalebarDict['where'] = self.scalebarDict['rect'].GetCentre() 
+
+        if self.id not in self.instruction:
+            scalebar = Scalebar(self.id)
+            self.instruction.AddInstruction(scalebar)
+        self.instruction[self.id].SetInstruction(self.scalebarDict)
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+            
+        return True
+    
+    def updateDialog(self):
+        """!Update scalebar coordinates, after moving"""
+        x, y = self.scalebarDict['rect'][:2]
+        currUnit = self.unitConv.findUnit(self.panel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.panel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.panel.position['yCtrl'].SetValue("%5.3f" % y)
+        
+ 
+        
+class TextDialog(PsmapDialog):
+    def __init__(self, parent, id, settings):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Text settings", settings = settings)
+        self.objectType = ('text',)
+        if self.id is not None:
+            self.textDict = self.instruction[id].GetInstruction()
+        else:
+            self.id = wx.NewId()  
+            text = Text(self.id)
+            self.textDict = text.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.textDict['where'] = page['Left'], page['Top'] 
+                
+        map = self.instruction.FindInstructionByType('map')
+        if not map:
+            map = self.instruction.FindInstructionByType('initMap')
+        self.mapId = map.id
+
+        self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(map = map, x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
+        
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)     
+        self.textPanel = self._textPanel(notebook)
+        self.positionPanel = self._positionPanel(notebook)
+        self.OnBackground(None)
+        self.OnHighlight(None)
+        self.OnBorder(None)
+        self.OnPositionType(None)
+        self.OnRotation(None)
+     
+        self._layout(notebook)
+
+    def _textPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Text"))
+        
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        # text entry    
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        
+        textLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Enter text:"))
+        self.textCtrl = ExpandoTextCtrl(panel, id = wx.ID_ANY, value = self.textDict['text'])
+        
+        sizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        sizer.Add(self.textCtrl, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)        
+        
+        #font       
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexGridSizer = wx.FlexGridSizer (rows = 3, cols = 2, hgap = 5, vgap = 5)
+        flexGridSizer.AddGrowableCol(1)
+        
+        self.AddFont(parent = panel, dialogDict = self.textDict)
+        
+        flexGridSizer.Add(panel.font['fontLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexGridSizer.Add(panel.font['fontCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexGridSizer.Add(panel.font['fontSizeLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexGridSizer.Add(panel.font['fontSizeCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        flexGridSizer.Add(panel.font['colorLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)        
+        flexGridSizer.Add(panel.font['colorCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(item = flexGridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #text effects        
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text effects"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+        
+        self.effect = {}
+        self.effect['backgroundCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text background"))
+        self.effect['backgroundColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        
+        self.effect['highlightCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("highlight"))
+        self.effect['highlightColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.effect['highlightWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 0, max = 5, initial = 1)
+        self.effect['highlightWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+        
+        self.effect['borderCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text border"))
+        self.effect['borderColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+        self.effect['borderWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 1, max = 25, initial = 1)
+        self.effect['borderWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+
+        #set values
+        if self.textDict['background'] == None:
+            self.textDict['background'] = 'none'
+        if self.textDict['background'] != 'none':
+            self.effect['backgroundCtrl'].SetValue(True) 
+            self.effect['backgroundColor'].SetColour(convertRGB(self.textDict['background']))
+        else:
+            self.effect['backgroundCtrl'].SetValue(False)
+            self.effect['backgroundColor'].SetColour(convertRGB('white'))
+
+        if self.textDict['hcolor'] == None:
+             self.textDict['hcolor'] = 'none'
+        if self.textDict['hcolor'] != 'none':
+            self.effect['highlightCtrl'].SetValue(True) 
+            self.effect['highlightColor'].SetColour(convertRGB(self.textDict['hcolor']))
+        else:
+            self.effect['highlightCtrl'].SetValue(False)
+            self.effect['highlightColor'].SetColour(convertRGB('grey'))
+
+        self.effect['highlightWidth'].SetValue(float(self.textDict['hwidth']))
+        
+        if self.textDict['border'] == None:
+            self.textDict['border'] = 'none'
+        if self.textDict['border'] != 'none':
+            self.effect['borderCtrl'].SetValue(True) 
+            self.effect['borderColor'].SetColour(convertRGB(self.textDict['border'])) 
+        else:
+            self.effect['borderCtrl'].SetValue(False)
+            self.effect['borderColor'].SetColour(convertRGB('black'))
+
+        self.effect['borderWidth'].SetValue(float(self.textDict['width']))
+        
+        gridBagSizer.Add(self.effect['backgroundCtrl'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['backgroundColor'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['highlightCtrl'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['highlightColor'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['highlightWidthLabel'], pos = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['highlightWidth'], pos = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['borderCtrl'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['borderColor'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['borderWidthLabel'], pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizer.Add(self.effect['borderWidth'], pos = (2,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizer.Add(item = gridBagSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textCtrl)
+        self.Bind(wx.EVT_CHECKBOX, self.OnBackground, self.effect['backgroundCtrl'])
+        self.Bind(wx.EVT_CHECKBOX, self.OnHighlight, self.effect['highlightCtrl'])
+        self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.effect['borderCtrl'])
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel 
+        
+    def _positionPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Position"))
+
+        border = wx.BoxSizer(wx.VERTICAL) 
+
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0)
+        gridBagSizer.AddGrowableCol(1)
+        
+        #Position
+        self.AddExtendedPosition(panel, gridBagSizer, self.textDict)
+        
+        #offset
+        box3   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Offset"))
+        sizerO = wx.StaticBoxSizer(box3, wx.VERTICAL)
+        gridBagSizerO = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.xoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("horizontal (pts):"))
+        self.yoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("vertical (pts):"))
+        self.xoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0)
+        self.yoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0) 
+        self.xoffCtrl.SetValue(self.textDict['xoffset'])       
+        self.yoffCtrl.SetValue(self.textDict['yoffset'])
+        gridBagSizerO.Add(self.xoffLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizerO.Add(self.yoffLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizerO.Add(self.xoffCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridBagSizerO.Add(self.yoffCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizerO.Add(gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerO, pos = (3,0), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+        # reference point
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_(" Reference point"))
+        sizerR = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer(rows = 3, cols = 3, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        flexSizer.AddGrowableCol(1)
+        flexSizer.AddGrowableCol(2)
+        ref = []
+        for row in ["upper", "center", "lower"]:
+            for col in ["left", "center", "right"]:
+                ref.append(row + " " + col)
+        self.radio = [wx.RadioButton(panel, id = wx.ID_ANY, label = '', style = wx.RB_GROUP, name = ref[0])]
+        self.radio[0].SetValue(False)
+        flexSizer.Add(self.radio[0], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+        for i in range(1,9):
+            self.radio.append(wx.RadioButton(panel, id = wx.ID_ANY, label = '', name = ref[i]))
+            self.radio[-1].SetValue(False)
+            flexSizer.Add(self.radio[-1], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+        self.FindWindowByName(self.textDict['ref']).SetValue(True)
+                
+        sizerR.Add(flexSizer, proportion = 1, flag = wx.EXPAND, border = 0)
+        gridBagSizer.Add(sizerR, pos = (3,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+                
+        #rotation
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+        self.rotCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("rotate text (counterclockwise)"))
+        self.rotValue = wx.SpinCtrl(panel, wx.ID_ANY, size = (50, -1), min = 0, max = 360, initial = 0)
+        if self.textDict['rotate']:
+            self.rotValue.SetValue(int(self.textDict['rotate']))
+            self.rotCtrl.SetValue(True)
+        else:
+            self.rotValue.SetValue(0)
+            self.rotCtrl.SetValue(False)
+        sizer.Add(self.rotCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
+        sizer.Add(self.rotValue, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
+        
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+          
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+        self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotCtrl)
+        
+        return panel
+     
+    def OnRefit(self, event):
+        self.Fit()
+        
+    def OnRotation(self, event):
+        if self.rotCtrl.GetValue():
+            self.rotValue.Enable()
+        else: 
+            self.rotValue.Disable()
+            
+    def OnPositionType(self, event):
+        if self.positionPanel.position['toPaper'].GetValue():
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Disable()
+        else:
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Disable()
+                
+    def OnBackground(self, event):
+        if self.effect['backgroundCtrl'].GetValue():
+            self.effect['backgroundColor'].Enable()
+            self.update()
+        else:
+            self.effect['backgroundColor'].Disable()
+    
+    def OnHighlight(self, event):
+        if self.effect['highlightCtrl'].GetValue():
+            self.effect['highlightColor'].Enable()
+            self.effect['highlightWidth'].Enable()
+            self.effect['highlightWidthLabel'].Enable()
+            self.update()
+        else:
+            self.effect['highlightColor'].Disable()
+            self.effect['highlightWidth'].Disable()
+            self.effect['highlightWidthLabel'].Disable()
+            
+    def OnBorder(self, event):
+        if self.effect['borderCtrl'].GetValue():
+            self.effect['borderColor'].Enable()
+            self.effect['borderWidth'].Enable()
+            self.effect['borderWidthLabel'].Enable()
+            self.update()
+        else:
+            self.effect['borderColor'].Disable()
+            self.effect['borderWidth'].Disable()
+            self.effect['borderWidthLabel'].Disable()
+            
+    def update(self): 
+        #text
+        self.textDict['text'] = self.textCtrl.GetValue()
+        if not self.textDict['text']:
+            wx.MessageBox(_("No text entered!"), _("Error"))
+            return False
+            
+        #font
+        self.textDict['font'] = self.textPanel.font['fontCtrl'].GetStringSelection()
+        self.textDict['fontsize'] = self.textPanel.font['fontSizeCtrl'].GetValue()
+        color = self.textPanel.font['colorCtrl'].GetColour()
+        self.textDict['color'] = convertRGB(color)
+
+        #effects
+        if self.effect['backgroundCtrl'].GetValue():
+            background = self.effect['backgroundColor'].GetColour()
+            self.textDict['background'] = convertRGB(background)
+        else:
+            self.textDict['background'] = 'none'        
+                
+        if self.effect['borderCtrl'].GetValue():
+            border = self.effect['borderColor'].GetColour()
+            self.textDict['border'] = convertRGB(border)
+        else:
+            self.textDict['border'] = 'none' 
+                     
+        self.textDict['width'] = self.effect['borderWidth'].GetValue()
+        
+        if self.effect['highlightCtrl'].GetValue():
+            highlight = self.effect['highlightColor'].GetColour()
+            self.textDict['hcolor'] = convertRGB(highlight)
+        else:
+            self.textDict['hcolor'] = 'none'
+
+        self.textDict['hwidth'] = self.effect['highlightWidth'].GetValue()
+        
+        #offset
+        self.textDict['xoffset'] = self.xoffCtrl.GetValue()
+        self.textDict['yoffset'] = self.yoffCtrl.GetValue()
+
+        #position
+        if self.positionPanel.position['toPaper'].GetValue():
+            self.textDict['XY'] = True
+            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+            self.textDict['unit'] = currUnit
+            if self.positionPanel.position['xCtrl'].GetValue():
+                x = self.positionPanel.position['xCtrl'].GetValue() 
+            else:
+                x = self.textDict['where'][0]
+
+            if self.positionPanel.position['yCtrl'].GetValue():
+                y = self.positionPanel.position['yCtrl'].GetValue() 
+            else:
+                y = self.textDict['where'][1]
+
+            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+            self.textDict['where'] = x, y
+            self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(self.instruction[self.mapId], x, y, paperToMap = True)
+        else:
+            self.textDict['XY'] = False
+            if self.positionPanel.position['eCtrl'].GetValue():
+                self.textDict['east'] = self.positionPanel.position['eCtrl'].GetValue() 
+            else:
+                self.textDict['east'] = self.textDict['east']
+
+            if self.positionPanel.position['nCtrl'].GetValue():
+                self.textDict['north'] = self.positionPanel.position['nCtrl'].GetValue() 
+            else:
+                self.textDict['north'] = self.textDict['north']
+
+            self.textDict['where'] = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.textDict['east']),
+                                                            y = float(self.textDict['north']), paperToMap = False)
+        #rotation
+        if self.rotCtrl.GetValue():
+            self.textDict['rotate'] = self.rotValue.GetValue()
+        else:
+            self.textDict['rotate'] = None
+        #reference point
+        for radio in self.radio:
+            if radio.GetValue() == True:
+                self.textDict['ref'] = radio.GetName()
+                
+        if self.id not in self.instruction:
+            text = Text(self.id)
+            self.instruction.AddInstruction(text)
+        self.instruction[self.id].SetInstruction(self.textDict)
+        
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+
+#        self.updateDialog()
+
+        return True
+    
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        # XY coordinates
+        x, y = self.textDict['where'][:2]
+        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+        # EN coordinates
+        e, n = self.textDict['east'], self.textDict['north']
+        self.positionPanel.position['eCtrl'].SetValue(str(self.textDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.textDict['north']))
+        
+class ImageDialog(PsmapDialog):
+    """!Dialog for setting image properties.
+    
+    It's base dialog for North Arrow dialog.
+    """
+    def __init__(self, parent, id, settings, imagePanelName = _("Image")):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Image settings",
+                             settings = settings)
+        
+        self.objectType = ('image',)
+        if self.id is not None:
+            self.imageObj = self.instruction[self.id]
+            self.imageDict = self.instruction[id].GetInstruction()
+        else:
+            self.id = wx.NewId()
+            self.imageObj = self._newObject()
+            self.imageDict = self.imageObj.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.imageDict['where'] = page['Left'], page['Top'] 
+                
+        map = self.instruction.FindInstructionByType('map')
+        if not map:
+            map = self.instruction.FindInstructionByType('initMap')
+        self.mapId = map.id
+
+        self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(map = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
+        
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.imagePanelName = imagePanelName
+        self.imagePanel = self._imagePanel(notebook)
+        self.positionPanel = self._positionPanel(notebook)
+        self.OnPositionType(None)
+        
+        if self.imageDict['epsfile']:
+            self.imagePanel.image['dir'].SetValue(os.path.dirname(self.imageDict['epsfile']))
+        else:
+            self.imagePanel.image['dir'].SetValue(self._getImageDirectory())
+        self.OnDirChanged(None)
+     
+        self._layout(notebook)
+        
+        
+    def _newObject(self):
+        """!Create corresponding instruction object"""
+        return Image(self.id, self.instruction)
+        
+    def _imagePanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = self.imagePanelName)
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # choose image
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Image"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        # choose directory
+        panel.image = {}
+        if self.imageDict['epsfile']:
+            startDir = os.path.dirname(self.imageDict['epsfile'])
+        else:
+            startDir = self._getImageDirectory()
+        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+                                         labelText = _("Choose a directory:"),
+                                         dialogTitle = _("Choose a directory with images"),
+                                         buttonText = _('Browse'),
+                                         startDirectory = startDir,
+                                         changeCallback = self.OnDirChanged)
+        panel.image['dir'] = dir
+       
+        
+        sizer.Add(item = dir, proportion = 0, flag = wx.EXPAND, border = 0)
+        
+        # image list
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        imageList = wx.ListBox(parent = panel, id = wx.ID_ANY)
+        panel.image['list'] = imageList
+        imageList.Bind(wx.EVT_LISTBOX, self.OnImageSelectionChanged)
+        
+        hSizer.Add(item = imageList, proportion = 1, flag = wx.EXPAND | wx.RIGHT, border = 10)
+        
+        # image preview
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        self.previewSize = (150, 150)
+        img = wx.EmptyImage(*self.previewSize)
+        panel.image['preview'] = wx.StaticBitmap(parent = panel, id = wx.ID_ANY,
+                                                bitmap = wx.BitmapFromImage(img))
+        vSizer.Add(item = panel.image['preview'], proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+        panel.image['sizeInfo'] = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        vSizer.Add(item = panel.image['sizeInfo'], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+        
+        hSizer.Add(item = vSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+        sizer.Add(item = hSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        epsInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                label = _("Note: only EPS format supported"))
+        sizer.Add(item = epsInfo, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 3)
+        
+        
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #
+        # rotation
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Scale And Rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        scaleLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Scale:"))
+        if fs:
+            panel.image['scale'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+                                          increment = 0.5, value = 1, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['scale'].SetFormat("%f")
+            panel.image['scale'].SetDigits(1)
+        else:
+            panel.image['scale'] = wx.TextCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                  validator = TCValidator(flag = 'DIGIT_ONLY'))
+        
+        if self.imageDict['scale']:
+            if fs:
+                value = float(self.imageDict['scale'])
+            else:
+                value = str(self.imageDict['scale'])
+        else:
+            if fs:
+                value = 0
+            else:
+                value = '0'
+        panel.image['scale'].SetValue(value)
+            
+        gridSizer.Add(item = scaleLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = panel.image['scale'], pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        
+        rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+        if fs:
+            panel.image['rotate'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 360,
+                                          increment = 0.5, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['rotate'].SetFormat("%f")
+            panel.image['rotate'].SetDigits(1)
+        else:
+            panel.image['rotate'] = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                min = 0, max = 359, initial = 0)
+        panel.image['rotate'].SetToolTipString(_("Counterclockwise rotation in degrees"))
+        if self.imageDict['rotate']:
+            panel.image['rotate'].SetValue(int(self.imageDict['rotate']))
+        else:
+            panel.image['rotate'].SetValue(0)
+            
+        gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridSizer.Add(item = panel.image['rotate'], pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        self._addConvergence(panel = panel, gridBagSizer = gridSizer)
+        sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def _positionPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Position"))
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # set position
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddExtendedPosition(panel, gridBagSizer, self.imageDict)
+        
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+        
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def OnDirChanged(self, event):
+        """!Image directory changed"""
+        path = self.imagePanel.image['dir'].GetValue()
+        try:
+            files = os.listdir(path)
+        except OSError: # no such directory
+            files = []
+        imageList = []
+        
+        # no setter for startDirectory?
+        try:
+            self.imagePanel.image['dir'].startDirectory = path
+        except AttributeError: # for sure
+            pass
+        for file in files:
+            if os.path.splitext(file)[1].lower() == '.eps':
+                imageList.append(file)
+        
+        imageList.sort()
+        self.imagePanel.image['list'].SetItems(imageList)
+        if self.imageDict['epsfile']:
+            file = os.path.basename(self.imageDict['epsfile'])
+            self.imagePanel.image['list'].SetStringSelection(file)
+        elif imageList:
+            self.imagePanel.image['list'].SetSelection(0)
+        self.OnImageSelectionChanged(None)
+        
+    def OnPositionType(self, event):
+        if self.positionPanel.position['toPaper'].GetValue():
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Disable()
+        else:
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Disable()
+                
+    def _getImageDirectory(self):
+        """!Default image directory"""
+        return os.getcwd()
+        
+    def _addConvergence(self, panel, gridBagSizer):
+        pass
+        
+    def OnImageSelectionChanged(self, event):
+        """!Image selected, show preview and size"""
+        if not self.imagePanel.image['dir']: # event is emitted when closing dialog an it causes error
+            return
+            
+        if not havePILImage:
+            self.DrawWarningText(_("PIL\nmissing"))
+            return
+        
+        imageName = self.imagePanel.image['list'].GetStringSelection()
+        if not imageName:
+            self.ClearPreview()
+            return
+        basePath = self.imagePanel.image['dir'].GetValue()
+        file = os.path.join(basePath, imageName)
+        if not os.path.exists(file):
+            return
+            
+        if os.path.splitext(file)[1].lower() == '.eps':
+            try:
+                pImg = PILImage.open(file)
+                img = PilImageToWxImage(pImg)
+            except IOError, e:
+                GError(message = _("Unable to read file %s") % file)
+                self.ClearPreview()
+                return
+            self.SetSizeInfoLabel(img)
+            img = self.ScaleToPreview(img)
+            bitmap = img.ConvertToBitmap()
+            self.DrawBitmap(bitmap)
+            
+        else:
+            # TODO: read other formats and convert by PIL to eps
+            pass
+    
+    def ScaleToPreview(self, img):
+        """!Scale image to preview size"""
+        w = img.GetWidth()
+        h = img.GetHeight()
+        if w <= self.previewSize[0] and h <= self.previewSize[1]:
+            return img
+        if w > h:
+            newW = self.previewSize[0]
+            newH = self.previewSize[0] * h / w
+        else:
+            newH = self.previewSize[0]
+            newW = self.previewSize[0] * w / h
+        return img.Scale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+        
+    def DrawWarningText(self, warning):
+        """!Draw text on preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.Brush(wx.Color(250, 250, 250)))
+        dc.Clear()
+        extent = dc.GetTextExtent(warning)
+        posX = self.previewSize[0] / 2 - extent[0] / 2
+        posY = self.previewSize[1] / 2 - extent[1] / 2
+        dc.DrawText(warning, posX, posY)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def DrawBitmap(self, bitmap):
+        """!Draw bitmap, center it if smaller than preview size"""
+        if bitmap.GetWidth() <= self.previewSize[0] and bitmap.GetHeight() <= self.previewSize[1]:
+            buffer = wx.EmptyBitmap(*self.previewSize)
+            dc = wx.MemoryDC()
+            dc.SelectObject(buffer)
+            dc.SetBrush(dc.GetBrush())
+            dc.Clear()
+            posX = self.previewSize[0] / 2 - bitmap.GetWidth() / 2
+            posY = self.previewSize[1] / 2 - bitmap.GetHeight() / 2
+            dc.DrawBitmap(bitmap, posX, posY)
+            self.imagePanel.image['preview'].SetBitmap(buffer)
+            dc.SelectObject(wx.NullBitmap)
+        else:
+            self.imagePanel.image['preview'].SetBitmap(bitmap)
+            
+    def SetSizeInfoLabel(self, image):
+        """!Update image size label"""
+        self.imagePanel.image['sizeInfo'].SetLabel(_("size: %s x %s pts") % (image.GetWidth(), image.GetHeight()))
+        self.imagePanel.image['sizeInfo'].GetContainingSizer().Layout()
+        
+    def ClearPreview(self):
+        """!Clear preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.WHITE_BRUSH)
+        dc.Clear()
+        mask = wx.Mask(buffer, wx.WHITE)
+        buffer.SetMask(mask)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def update(self): 
+        # epsfile
+        selected = self.imagePanel.image['list'].GetStringSelection()
+        basePath = self.imagePanel.image['dir'].GetValue()
+        if not selected:
+            gcmd.GMessage(parent = self, message = _("No image selected."))
+            return False
+            
+        self.imageDict['epsfile'] = os.path.join(basePath, selected)
+        
+        #position
+        if self.positionPanel.position['toPaper'].GetValue():
+            self.imageDict['XY'] = True
+            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+            self.imageDict['unit'] = currUnit
+            if self.positionPanel.position['xCtrl'].GetValue():
+                x = self.positionPanel.position['xCtrl'].GetValue() 
+            else:
+                x = self.imageDict['where'][0]
+
+            if self.positionPanel.position['yCtrl'].GetValue():
+                y = self.positionPanel.position['yCtrl'].GetValue() 
+            else:
+                y = self.imageDict['where'][1]
+
+            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+            self.imageDict['where'] = x, y
+            
+        else:
+            self.imageDict['XY'] = False
+            if self.positionPanel.position['eCtrl'].GetValue():
+                e = self.positionPanel.position['eCtrl'].GetValue() 
+            else:
+                self.imageDict['east'] = self.imageDict['east']
+
+            if self.positionPanel.position['nCtrl'].GetValue():
+                n = self.positionPanel.position['nCtrl'].GetValue() 
+            else:
+                self.imageDict['north'] = self.imageDict['north']
+
+            x, y = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.imageDict['east']),
+                                       y = float(self.imageDict['north']), paperToMap = False)
+
+        #rotation
+        rot = self.imagePanel.image['rotate'].GetValue()
+        if rot == 0:
+            self.imageDict['rotate'] = None
+        else:
+            self.imageDict['rotate'] = rot
+        
+        #scale
+        self.imageDict['scale'] = self.imagePanel.image['scale'].GetValue()
+                
+        # scale
+        w, h = self.imageObj.GetImageOrigSize(self.imageDict['epsfile'])
+        if self.imageDict['rotate']:
+            self.imageDict['size'] = BBoxAfterRotation(w, h, self.imageDict['rotate'])
+        else:
+            self.imageDict['size'] = w, h
+            
+        w = self.unitConv.convert(value = self.imageDict['size'][0],
+                                  fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = self.imageDict['size'][1],
+                                  fromUnit = 'point', toUnit = 'inch')
+                                  
+    
+        self.imageDict['rect'] = wx.Rect2D(x = x, y = y,
+                                       w = w * self.imageDict['scale'],
+                                       h = h * self.imageDict['scale'])
+        
+        if self.id not in self.instruction:
+            image = self._newObject()
+            self.instruction.AddInstruction(image)
+        self.instruction[self.id].SetInstruction(self.imageDict)
+        
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+
+        return True
+        
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        # XY coordinates
+        x, y = self.imageDict['where'][:2]
+        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+        # EN coordinates
+        e, n = self.imageDict['east'], self.imageDict['north']
+        self.positionPanel.position['eCtrl'].SetValue(str(self.imageDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.imageDict['north']))
+        
+        
+class NorthArrowDialog(ImageDialog):
+    def __init__(self, parent, id, settings):
+        ImageDialog.__init__(self, parent = parent, id = id, settings = settings,
+                             imagePanelName = _("North Arrow"))
+        
+        self.objectType = ('northArrow',)
+        self.SetTitle(_("North Arrow settings"))
+    
+    def _newObject(self):
+        return NorthArrow(self.id, self.instruction)
+        
+    def _getImageDirectory(self):
+        gisbase = os.getenv("GISBASE")
+        return os.path.join(gisbase, 'etc', 'paint', 'decorations')
+    
+    def _addConvergence(self, panel, gridBagSizer):
+        convergence = wx.Button(parent = panel, id = wx.ID_ANY,
+                                               label = _("Compute convergence"))
+        gridBagSizer.Add(item = convergence, pos = (1, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+        convergence.Bind(wx.EVT_BUTTON, self.OnConvergence)
+        panel.image['convergence'] = convergence
+        
+    def OnConvergence(self, event):
+        ret = RunCommand('g.region', read = True, flags = 'ng')
+        if ret:
+            convergence = float(ret.strip().split('=')[1])
+            if convergence < 0:
+                self.imagePanel.image['rotate'].SetValue(abs(convergence))
+            else:
+                self.imagePanel.image['rotate'].SetValue(360 - convergence)
+            
+        
+def convertRGB(rgb):
+    """!Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color,
+            or named color/r:g:b string to wx.Colour, depending on input""" 
+    # transform a wx.Colour tuple into an r:g:b string    
+    if type(rgb) == wx.Colour:
+        for name, color in grass.named_colors.items(): 
+            if  rgb.Red() == int(color[0] * 255) and\
+                rgb.Green() == int(color[1] * 255) and\
+                rgb.Blue() == int(color[2] * 255):
+                return name
+        return str(rgb.Red()) + ':' + str(rgb.Green()) + ':' + str(rgb.Blue())
+    # transform a GRASS named color or an r:g:b string into a wx.Colour tuple
+    else:
+        color = (grass.parse_color(rgb)[0]*255,
+                 grass.parse_color(rgb)[1]*255,
+                 grass.parse_color(rgb)[2]*255)
+        color = wx.Color(*color)
+        if color.IsOk():
+            return color
+        else:  
+            return None
+        
+def PaperMapCoordinates(map, x, y, paperToMap = True):
+    """!Converts paper (inch) coordinates -> map coordinates"""
+    unitConv = UnitConversion()
+    currRegionDict = grass.region()
+    cornerEasting, cornerNorthing = currRegionDict['w'], currRegionDict['n']
+    xMap = map['rect'][0]
+    yMap = map['rect'][1]
+    widthMap = map['rect'][2] * 0.0254 # to meter
+    heightMap = map['rect'][3] * 0.0254
+    xScale = widthMap / abs(currRegionDict['w'] - currRegionDict['e'])
+    yScale = heightMap / abs(currRegionDict['n'] - currRegionDict['s'])
+    currScale = (xScale + yScale) / 2
+ 
+    if not paperToMap:
+        textEasting, textNorthing = x, y
+        eastingDiff = textEasting - cornerEasting 
+        if currRegionDict['w'] > currRegionDict['e']:
+            eastingDiff = - eastingDiff
+        else:
+            eastingDiff = eastingDiff
+
+        northingDiff = textNorthing - cornerNorthing
+        if currRegionDict['n'] > currRegionDict['s']:
+            northingDiff = - northingDiff 
+        else:
+            northingDiff = northingDiff
+
+        xPaper = xMap + unitConv.convert(value = eastingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
+        yPaper = yMap + unitConv.convert(value = northingDiff, fromUnit = 'meter', toUnit = 'inch') * currScale
+        return xPaper, yPaper
+    else:
+        if currRegionDict['w'] < currRegionDict['e']:
+            eastingDiff = (x - xMap) 
+        else:
+            eastingDiff = (xMap - x)
+        if currRegionDict['n'] < currRegionDict['s']:
+            northingDiff = (y - yMap) 
+        else:
+            northingDiff = (yMap - y)
+
+        textEasting = cornerEasting + unitConv.convert(value = eastingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
+        textNorthing = cornerNorthing + unitConv.convert(value = northingDiff, fromUnit = 'inch', toUnit = 'meter') / currScale
+        return int(textEasting), int(textNorthing)
+        
+def AutoAdjust(self, scaleType,  rect, map = None, mapType = None, region = None):
+    """!Computes map scale, center and map frame rectangle to fit region (scale is not fixed)"""
+    currRegionDict = {}
+    if scaleType == 0 and map:# automatic, region from raster or vector
+        res = ''
+        if mapType == 'raster': 
+            try:
+                res = grass.read_command("g.region", flags = 'gu', rast = map)
+            except grass.ScriptError:
+                pass
+        elif mapType == 'vector':
+            res = grass.read_command("g.region", flags = 'gu', vect = map)
+        currRegionDict = grass.parse_key_val(res, val_type = float)
+    elif scaleType == 1 and region: # saved region
+        res = grass.read_command("g.region", flags = 'gu', region = region)
+        currRegionDict = grass.parse_key_val(res, val_type = float)
+    elif scaleType == 2: # current region
+        env = grass.gisenv()
+        windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
+        try:
+            windFile = open(windFilePath, 'r').read()
+        except IOError:
+            currRegionDict = grass.region()
+        regionDict = grass.parse_key_val(windFile, sep = ':', val_type = float)
+        region = grass.read_command("g.region", flags = 'gu', n = regionDict['north'], s = regionDict['south'],
+                                    e = regionDict['east'], w = regionDict['west'])
+        currRegionDict = grass.parse_key_val(region, val_type = float)
+                                                                
+    else:
+        return None, None, None
+    
+    if not currRegionDict:
+        return None, None, None
+    rX = rect.x
+    rY = rect.y
+    rW = rect.width
+    rH = rect.height
+    if not hasattr(self, 'unitConv'):
+        self.unitConv = UnitConversion(self)
+    toM = 1
+    if projInfo()['proj'] != 'xy':
+        toM = float(projInfo()['meters'])
+
+    mW = self.unitConv.convert(value = (currRegionDict['e'] - currRegionDict['w']) * toM, fromUnit = 'meter', toUnit = 'inch')
+    mH = self.unitConv.convert(value = (currRegionDict['n'] - currRegionDict['s']) * toM, fromUnit = 'meter', toUnit = 'inch')
+    scale = min(rW/mW, rH/mH)
+    
+    if rW/rH > mW/mH:
+        x = rX - (rH*(mW/mH) - rW)/2
+        y = rY
+        rWNew = rH*(mW/mH)
+        rHNew = rH
+    else:
+        x = rX
+        y = rY - (rW*(mH/mW) - rH)/2
+        rHNew = rW*(mH/mW)
+        rWNew = rW
+
+    # center
+    cE = (currRegionDict['w'] + currRegionDict['e'])/2
+    cN = (currRegionDict['n'] + currRegionDict['s'])/2
+    return scale, (cE, cN), wx.Rect2D(x, y, rWNew, rHNew) #inch
+
+def SetResolution(dpi, width, height):
+    """!If resolution is too high, lower it
+    
+    @param dpi max DPI
+    @param width map frame width
+    @param height map frame height
+    """
+    region = grass.region()
+    if region['cols'] > width * dpi or region['rows'] > height * dpi:
+        rows = height * dpi
+        cols = width * dpi
+        RunCommand('g.region', rows = rows, cols = cols)
+               
+def ComputeSetRegion(self, mapDict):
+    """!Computes and sets region from current scale, map center coordinates and map rectangle"""
+
+    if mapDict['scaleType'] == 3: # fixed scale
+        scale = mapDict['scale']
+            
+        if not hasattr(self, 'unitConv'):
+            self.unitConv = UnitConversion(self)
+        
+        fromM = 1
+        if projInfo()['proj'] != 'xy':
+            fromM = float(projInfo()['meters'])
+        rectHalfInch = (mapDict['rect'].width/2, mapDict['rect'].height/2)
+        rectHalfMeter = (self.unitConv.convert(value = rectHalfInch[0], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale,
+                         self.unitConv.convert(value = rectHalfInch[1], fromUnit = 'inch', toUnit = 'meter')/ fromM /scale) 
+        
+        centerE = mapDict['center'][0]
+        centerN = mapDict['center'][1]
+        
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            rasterId = raster.id 
+        else:
+            rasterId = None
+
+        if rasterId:
+            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
+                       s = floor(centerN - rectHalfMeter[1]),
+                       e = ceil(centerE + rectHalfMeter[0]),
+                       w = floor(centerE - rectHalfMeter[0]),
+                       rast = self.instruction[rasterId]['raster'])
+        else:
+            RunCommand('g.region', n = ceil(centerN + rectHalfMeter[1]),
+                       s = floor(centerN - rectHalfMeter[1]),
+                       e = ceil(centerE + rectHalfMeter[0]),
+                       w = floor(centerE - rectHalfMeter[0]))
+                    
+def projInfo():
+    """!Return region projection and map units information,
+    taken from render.py"""
+    
+    projinfo = dict()
+    
+    ret = RunCommand('g.proj', read = True, flags = 'p')
+    
+    if not ret:
+        return projinfo
+    
+    for line in ret.splitlines():
+        if ':' in line:
+            key, val = line.split(':')
+            projinfo[key.strip()] = val.strip()
+        elif "XY location (unprojected)" in line:
+            projinfo['proj'] = 'xy'
+            projinfo['units'] = ''
+            break
+    
+    return projinfo
+
+def GetMapBounds(filename, portrait = True):
+    """!Run ps.map -b to get information about map bounding box
+    
+        @param filename psmap input file
+        @param portrait page orientation"""
+    orient = ''
+    if not portrait:
+        orient = 'r'
+    try:
+        bb = map(float, grass.read_command('ps.map',
+                                           flags = 'b' + orient,
+                                           quiet = True,
+                                           input = filename).strip().split('=')[1].split(','))
+    except (grass.ScriptError, IndexError):
+        GError(message = _("Unable to run `ps.map -b`"))
+        return None
+    return wx.Rect2D(bb[0], bb[3], bb[2] - bb[0], bb[1] - bb[3])
+
+def getRasterType(map):
+    """!Returns type of raster map (CELL, FCELL, DCELL)"""
+    if map is None:
+        map = ''
+    file = grass.find_file(name = map, element = 'cell')
+    if file['file']:
+        rasterType = grass.raster_info(map)['datatype']
+        return rasterType
+    else:
+        return None
+   
+def PilImageToWxImage(pilImage, copyAlpha = True):
+    """!Convert PIL image to wx.Image
+    
+    Based on http://wiki.wxpython.org/WorkingWithImages
+    """
+    hasAlpha = pilImage.mode[-1] == 'A'
+    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.
+        wxImage = wx.EmptyImage( *pilImage.size )
+        pilImageCopyRGBA = pilImage.copy()
+        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+        wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4])  # Create layer and insert alpha values.
+
+    else :    # The resulting image will not have alpha.
+        wxImage = wx.EmptyImage(*pilImage.size)
+        pilImageCopy = pilImage.copy()
+        pilImageCopyRGB = pilImageCopy.convert('RGB')    # Discard any alpha from the PIL image.
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+
+    return wxImage
+
+def BBoxAfterRotation(w, h, angle):
+    """!Compute bounding box or rotated rectangle
+    
+    @param w rectangle width
+    @param h rectangle height
+    @param angle angle (0, 360) in degrees
+    """
+    angleRad = angle / 180. * pi
+    ct = cos(angleRad)
+    st = sin(angleRad)
+    
+    hct = h * ct
+    wct = w * ct
+    hst = h * st
+    wst = w * st
+    y = x = 0
+    
+    if 0 < angle <= 90:
+        y_min = y
+        y_max = y + hct + wst
+        x_min = x - hst
+        x_max = x + wct
+    elif 90 < angle <= 180:
+        y_min = y + hct
+        y_max = y + wst
+        x_min = x - hst + wct
+        x_max = x
+    elif 180 < angle <= 270:
+        y_min = y + wst + hct
+        y_max = y
+        x_min = x + wct
+        x_max = x - hst
+    elif 270 < angle <= 360:
+        y_min = y + wst
+        y_max = y + hct
+        x_min = x
+        x_max = x + wct - hst
+        
+    width = int(ceil(abs(x_max) + abs(x_min)))
+    height = int(ceil(abs(y_max) + abs(y_min)))
+    return width, height

Copied: grass/trunk/gui/wxpython/psmap/frame.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/psmap.py)
===================================================================
--- grass/trunk/gui/wxpython/psmap/frame.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/psmap/frame.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1800 @@
+"""!
+ at package psmap.frame
+
+ at brief GUI for ps.map
+
+Classes:
+ - PsMapFrame
+ - PsMapBufferedWindow
+
+(C) 2011 by Anna Kratochvilova, and 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 Anna Kratochvilova <kratochanna gmail.com> (bachelor's project)
+ at author Martin Landa <landa.martin gmail.com> (mentor)
+"""
+
+import os
+import sys
+import textwrap
+import Queue
+from math import sin, cos, pi
+try:
+    import Image as PILImage
+    havePILImage = True
+except ImportError:
+    havePILImage = False
+
+import wx
+
+try:
+    import wx.lib.agw.flatnotebook as fnb
+except ImportError:
+    import wx.lib.flatnotebook as fnb
+
+import grass.script as grass
+
+from core             import globalvar
+from gui_core.menu    import Menu
+from gui_core.goutput import CmdThread, EVT_CMD_DONE
+from psmap.toolbars   import PsMapToolbar
+from icon             import Icons, MetaIcon, iconSet
+from core.gcmd        import RunCommand, GError, GMessage
+from core.forms       import GUI
+from psmap.dialogs    import *
+
+class PsMapFrame(wx.Frame):
+    def __init__(self, parent = None, id = wx.ID_ANY,
+                 title = _("GRASS GIS Cartographic Composer"), **kwargs):
+        """!Main window of ps.map GUI
+        
+        @param parent parent window
+        @param id window id
+        @param title window title
+        
+        @param kwargs wx.Frames' arguments
+        """
+        self.parent = parent
+
+        wx.Frame.__init__(self, parent = parent, id = id, title = title, name = "PsMap", **kwargs)
+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        #menubar
+        self.menubar = Menu(parent = self, data = PsMapData())
+        self.SetMenuBar(self.menubar)
+        #toolbar
+
+        self.toolbar = PsMapToolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+        
+        self.actionOld = self.toolbar.action['id']
+        self.iconsize = (16, 16)
+        #satusbar
+        self.statusbar = self.CreateStatusBar(number = 1)
+        
+        # mouse attributes -- position on the screen, begin and end of
+        # dragging, and type of drawing
+        self.mouse = {
+            'begin': [0, 0], # screen coordinates
+            'end'  : [0, 0],
+            'use'  : "pointer",
+            }
+        # available cursors
+        self.cursors = {
+            "default" : wx.StockCursor(wx.CURSOR_ARROW),
+            "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
+            "hand"    : wx.StockCursor(wx.CURSOR_HAND),
+            "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
+            }
+        # pen and brush
+        self.pen = {
+            'paper': wx.Pen(colour = "BLACK", width = 1),
+            'margins': wx.Pen(colour = "GREY", width = 1),
+            'map': wx.Pen(colour = wx.Color(86, 122, 17), width = 2),
+            'rasterLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
+            'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
+            'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
+            'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
+            'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
+            'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
+            'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
+            'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
+            'resize': wx.Pen(colour = 'BLACK', width = 1)
+            }
+        self.brush = {
+            'paper': wx.WHITE_BRUSH,
+            'margins': wx.TRANSPARENT_BRUSH,
+            'map': wx.Brush(wx.Color(151, 214, 90)),
+            'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
+            'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
+            'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
+            'scalebar': wx.Brush(wx.Color(200, 200, 200)),
+            'image': wx.Brush(wx.Color(255, 200, 50)),
+            'northArrow': wx.Brush(wx.Color(255, 255, 255)),
+            'box': wx.TRANSPARENT_BRUSH,
+            'select':wx.TRANSPARENT_BRUSH,
+            'resize': wx.BLACK_BRUSH
+            } 
+        
+
+        # list of objects to draw
+        self.objectId = []
+        
+        # instructions
+        self.instruction = Instruction(parent = self, objectsToDraw = self.objectId)
+        # open dialogs
+        self.openDialogs = dict()
+        
+        self.pageId = wx.NewId()
+        #current page of flatnotebook
+        self.currentPage = 0
+        #canvas for draft mode
+        self.canvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, pen = self.pen,
+                                          brush = self.brush, cursors = self.cursors, 
+                                          instruction = self.instruction, openDialogs = self.openDialogs,
+                                          pageId = self.pageId, objectId = self.objectId,
+                                          preview = False)
+        
+        self.canvas.SetCursor(self.cursors["default"])
+        self.getInitMap()
+        
+        
+        # image path
+        env = grass.gisenv()
+        self.imgName = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], '.tmp', 'tmpImage.png')
+        
+        #canvas for preview
+        self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
+                                                 pen = self.pen, brush = self.brush, preview = True)
+        
+        # set WIND_OVERRIDE
+        grass.use_temp_region()
+        
+        # create queues
+        self.requestQ = Queue.Queue()
+        self.resultQ = Queue.Queue()
+        # thread
+        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
+        
+        self._layout()
+        self.SetMinSize(wx.Size(750, 600))
+        
+        self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
+        self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+        
+        if not havePILImage:
+            wx.CallAfter(self._showErrMsg)
+        
+    def _showErrMsg(self):
+        """!Show error message (missing preview)
+        """
+        GError(parent = self,
+               message = _("Python Imaging Library is not available.\n"
+                           "'Preview' functionality won't work."),
+               showTraceback = False)
+        
+    def _layout(self):
+        """!Do layout
+        """
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        if globalvar.hasAgw:
+            self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
+                                         agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
+                                         fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
+        else:
+            self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
+                                         style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
+                                         fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
+        #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
+        self.book.AddPage(self.canvas, "Draft mode")
+        self.book.AddPage(self.previewCanvas, "Preview")
+        self.book.SetSelection(0)
+        
+        mainSizer.Add(self.book,1, wx.EXPAND)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+        
+    def InstructionFile(self):
+        """!Creates mapping instructions"""
+        
+        return str(self.instruction)
+
+    def OnPSFile(self, event):
+        """!Generate PostScript"""
+        filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
+        if filename:
+            self.PSFile(filename)
+    
+    def OnPsMapDialog(self, event):
+        """!Launch ps.map dialog
+        """
+        GUI(parent = self).ParseCommand(cmd = ['ps.map'])
+
+    def OnPDFFile(self, event):
+        """!Generate PDF from PS with ps2pdf if available"""
+        try:
+            p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
+            p.stderr.close()
+        
+        except OSError:
+            GMessage(parent = self,
+                     message = _("Program ps2pdf is not available. Please install it first to create PDF."))
+            return
+        
+        filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
+        if filename:  
+            self.PSFile(filename, pdf = True)   
+            
+    def OnPreview(self, event):
+        """!Run ps.map and show result"""
+        self.PSFile()
+        
+    def PSFile(self, filename = None, pdf = False):
+        """!Create temporary instructions file and run ps.map with output = filename"""
+        instrFile = grass.tempfile()
+        instrFileFd = open(instrFile, mode = 'w')
+        instrFileFd.write(self.InstructionFile())
+        instrFileFd.flush()
+        instrFileFd.close()
+        
+        temp = False
+        regOld = grass.region()
+        
+        if pdf:
+            pdfname = filename
+        else:
+            pdfname = None
+        #preview or pdf
+        if not filename or (filename and pdf):
+            temp = True
+            filename = grass.tempfile()
+            if not pdf: # lower resolution for preview
+                if self.instruction.FindInstructionByType('map'):
+                    mapId = self.instruction.FindInstructionByType('map').id
+                    SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
+                                  height = self.instruction[mapId]['rect'][3])
+        
+        cmd = ['ps.map', '--overwrite']
+        if os.path.splitext(filename)[1] == '.eps':
+            cmd.append('-e')
+        if self.instruction[self.pageId]['Orientation'] == 'Landscape':
+            cmd.append('-r')
+        cmd.append('input=%s' % instrFile)
+        cmd.append('output=%s' % filename)
+        if pdf:
+            self.SetStatusText(_('Generating PDF...'), 0)
+        elif not temp:
+            self.SetStatusText(_('Generating PostScript...'), 0)
+        else:
+            self.SetStatusText(_('Generating preview...'), 0)
+            
+        self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
+                                               'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
+        
+    def OnCmdDone(self, event):
+        """!ps.map process finished"""
+        
+        if event.returncode != 0:
+            GMessage(parent = self,
+                     message = _("Ps.map exited with return code %s") % event.returncode)
+            
+            grass.try_remove(event.userData['instrFile'])
+            if event.userData['temp']:
+                grass.try_remove(event.userData['filename']) 
+            return
+        
+        if event.userData['pdfname']:
+            try:
+                proc = grass.Popen(['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200', 
+                                    event.userData['filename'], event.userData['pdfname']])
+                
+                ret = proc.wait()                        
+                if ret > 0:
+                    GMessage(parent = self,
+                             message = _("ps2pdf exited with return code %s") % ret)
+
+            except OSError, e:
+                GError(parent = self,
+                       message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
+                
+        # show preview only when user doesn't want to create ps or pdf 
+        if havePILImage and event.userData['temp'] and not event.userData['pdfname']:
+            RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
+## wx.BusyInfo does not display the message
+##            busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
+
+            try:
+                im = PILImage.open(event.userData['filename'])
+                if self.instruction[self.pageId]['Orientation'] == 'Landscape':
+                    im = im.rotate(270)
+                
+                im.save(self.imgName, format = 'png')
+                
+            except IOError, e:
+                GError(parent = self,
+                       message = _("Unable to generate preview. %s") % e)
+            
+            
+                
+            rect = self.previewCanvas.ImageRect()
+            self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
+            self.previewCanvas.DrawImage(rect = rect)
+            
+##            busy.Destroy()
+            self.SetStatusText(_('Preview generated'), 0)
+            self.book.SetSelection(1)
+            self.currentPage = 1
+        
+        grass.try_remove(event.userData['instrFile'])
+        if event.userData['temp']:
+            grass.try_remove(event.userData['filename'])
+        
+    def getFile(self, wildcard):
+        suffix = []
+        for filter in wildcard.split('|')[1::2]:
+            s = filter.strip('*').split('.')[1]
+            if s:
+                s = '.' + s
+            suffix.append(s)
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            rasterId = raster.id 
+        else:
+            rasterId = None
+
+
+        if rasterId and self.instruction[rasterId]['raster']:
+            mapName = self.instruction[rasterId]['raster'].split('@')[0] + suffix[0]
+        else:
+            mapName = ''
+            
+        filename = ''
+        dlg = wx.FileDialog(self, message = _("Save file as"), defaultDir = "", 
+                            defaultFile = mapName, wildcard = wildcard,
+                            style = wx.CHANGE_DIR | wx.SAVE | wx.OVERWRITE_PROMPT)
+        if dlg.ShowModal() == wx.ID_OK:
+            filename = dlg.GetPath()
+            suffix = suffix[dlg.GetFilterIndex()]
+            if not os.path.splitext(filename)[1]:
+                filename = filename + suffix
+            elif os.path.splitext(filename)[1] != suffix and suffix != '':
+                filename = os.path.splitext(filename)[0] + suffix
+            
+        dlg.Destroy()
+        return filename
+    
+    def OnInstructionFile(self, event):
+        filename = self.getFile(wildcard = "*.psmap|*.psmap|Text file(*.txt)|*.txt|All files(*.*)|*.*")        
+        if filename:    
+            instrFile = open(filename, "w")
+            instrFile.write(self.InstructionFile())
+            instrFile.close()   
+            
+    def OnLoadFile(self, event):
+        """!Load file and read instructions"""
+        #find file
+        filename = ''
+        dlg = wx.FileDialog(self, message = "Find instructions file", defaultDir = "", 
+                            defaultFile = '', wildcard = "All files (*.*)|*.*",
+                            style = wx.CHANGE_DIR|wx.OPEN)
+        if dlg.ShowModal() == wx.ID_OK:
+            filename = dlg.GetPath()
+        dlg.Destroy()
+        if not filename:
+            return
+        # load instructions
+        readObjectId = []
+        readInstruction = Instruction(parent = self, objectsToDraw = readObjectId)
+        ok = readInstruction.Read(filename)
+        if not ok:
+            GMessage(_("Failed to read file %s.") % filename)
+        else:
+            self.instruction = self.canvas.instruction = readInstruction
+            self.objectId = self.canvas.objectId = readObjectId
+            self.pageId = self.canvas.pageId = self.instruction.FindInstructionByType('page').id
+            self.canvas.UpdateMapLabel()
+            self.canvas.dragId = -1
+            self.canvas.Clear()
+            self.canvas.SetPage()
+            #self.canvas.ZoomAll()
+            
+            self.DialogDataChanged(self.objectId)
+            
+    def OnPageSetup(self, event = None):
+        """!Specify paper size, margins and orientation"""
+        id = self.instruction.FindInstructionByType('page').id
+        dlg = PageSetupDialog(self, id = id, settings = self.instruction) 
+        dlg.CenterOnScreen()
+        val = dlg.ShowModal()
+        if val == wx.ID_OK:
+            self.canvas.SetPage()
+            self.getInitMap()
+            self.canvas.RecalculatePosition(ids = self.objectId)
+        dlg.Destroy()
+        
+    def OnPointer(self, event):
+        self.toolbar.OnTool(event)
+        self.mouse["use"] = "pointer"
+        self.canvas.SetCursor(self.cursors["default"])
+        self.previewCanvas.SetCursor(self.cursors["default"])
+        
+    def OnPan(self, event):
+        self.toolbar.OnTool(event)
+        self.mouse["use"] = "pan"
+        self.canvas.SetCursor(self.cursors["hand"])
+        self.previewCanvas.SetCursor(self.cursors["hand"])
+        
+    def OnZoomIn(self, event):
+        self.toolbar.OnTool(event)
+        self.mouse["use"] = "zoomin"
+        self.canvas.SetCursor(self.cursors["cross"])
+        self.previewCanvas.SetCursor(self.cursors["cross"])
+        
+    def OnZoomOut(self, event):
+        self.toolbar.OnTool(event)
+        self.mouse["use"] = "zoomout"
+        self.canvas.SetCursor(self.cursors["cross"])
+        self.previewCanvas.SetCursor(self.cursors["cross"])
+        
+    def OnZoomAll(self, event):
+        self.mouseOld = self.mouse['use']
+        if self.currentPage == 0:
+            self.cursorOld = self.canvas.GetCursor() 
+        else:
+            self.cursorOld = self.previewCanvas.GetCursor()
+            self.previewCanvas.GetCursor()
+        self.mouse["use"] = "zoomin"
+        if self.currentPage == 0:
+            self.canvas.ZoomAll()
+        else:
+            self.previewCanvas.ZoomAll()
+        self.mouse["use"] = self.mouseOld 
+        if self.currentPage == 0:
+            self.canvas.SetCursor(self.cursorOld)
+        else:
+            self.previewCanvas.SetCursor(self.cursorOld)
+        
+        
+    def OnAddMap(self, event, notebook = False):
+        """!Add or edit map frame"""
+        if event is not None:
+            if event.GetId() != self.toolbar.action['id']:
+                self.actionOld = self.toolbar.action['id']
+                self.mouseOld = self.mouse['use']
+                self.cursorOld = self.canvas.GetCursor()
+            self.toolbar.OnTool(event)
+        
+        if self.instruction.FindInstructionByType('map'):
+            mapId = self.instruction.FindInstructionByType('map').id
+        else: mapId = None
+        id = [mapId, None, None]
+        
+        if notebook:
+            if self.instruction.FindInstructionByType('vector'):
+                vectorId = self.instruction.FindInstructionByType('vector').id
+            else: vectorId = None
+            if self.instruction.FindInstructionByType('raster'):
+                rasterId = self.instruction.FindInstructionByType('raster').id
+            else: rasterId = None
+            id[1] = rasterId
+            id[2] = vectorId
+        
+        
+        if mapId: # map exists
+            
+            self.toolbar.ToggleTool(self.actionOld, True)
+            self.toolbar.ToggleTool(self.toolbar.action['id'], False)
+            self.toolbar.action['id'] = self.actionOld
+            try:
+                self.canvas.SetCursor(self.cursorOld) 
+            except AttributeError:
+                pass
+            
+##            dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
+##                            notebook = notebook)
+##            dlg.ShowModal()  
+            if notebook:
+                #check map, raster, vector and save, destroy them
+                if 'map' in self.openDialogs:
+                    self.openDialogs['map'].OnOK(event = None)
+                if 'raster' in self.openDialogs:
+                    self.openDialogs['raster'].OnOK(event = None)
+                if 'vector' in self.openDialogs:
+                    self.openDialogs['vector'].OnOK(event = None)
+                    
+                if 'mapNotebook' not in self.openDialogs:
+                    dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
+                                    notebook = notebook)
+                    self.openDialogs['mapNotebook'] = dlg
+                self.openDialogs['mapNotebook'].Show()
+            else:
+                if 'mapNotebook' in self.openDialogs:
+                    self.openDialogs['mapNotebook'].notebook.ChangeSelection(0)
+                else:
+                    if 'map' not in self.openDialogs:
+                        dlg = MapDialog(parent = self, id  = id, settings = self.instruction,
+                                        notebook = notebook)
+                        self.openDialogs['map'] = dlg
+                    self.openDialogs['map'].Show()
+                    
+
+        else:    # sofar no map
+            self.mouse["use"] = "addMap"
+            self.canvas.SetCursor(self.cursors["cross"])
+            if self.currentPage == 1:
+                self.book.SetSelection(0)
+                self.currentPage = 0
+                
+    def OnAddRaster(self, event):
+        """!Add raster map"""
+        if self.instruction.FindInstructionByType('raster'):
+            id = self.instruction.FindInstructionByType('raster').id
+        else: id = None
+        if self.instruction.FindInstructionByType('map'):
+            mapId = self.instruction.FindInstructionByType('map').id
+        else: mapId = None
+
+        if not id:
+            if not mapId:
+                GMessage(message = _("Please, create map frame first."))
+                return
+            
+##        dlg = RasterDialog(self, id = id, settings = self.instruction)
+##        dlg.ShowModal()
+        if 'mapNotebook' in self.openDialogs:
+            self.openDialogs['mapNotebook'].notebook.ChangeSelection(1)
+        else:
+            if 'raster' not in self.openDialogs:
+                dlg = RasterDialog(self, id = id, settings = self.instruction)
+                self.openDialogs['raster'] = dlg
+            self.openDialogs['raster'].Show()
+            
+    def OnAddVect(self, event):
+        """!Add vector map"""
+        if self.instruction.FindInstructionByType('vector'):
+            id = self.instruction.FindInstructionByType('vector').id
+        else: id = None
+        if self.instruction.FindInstructionByType('map'):
+            mapId = self.instruction.FindInstructionByType('map').id
+        else: mapId = None
+        if not id:
+            if not mapId:
+                GMessage(message = _("Please, create map frame first."))
+                return
+            
+##        dlg = MainVectorDialog(self, id = id, settings = self.instruction)
+##        dlg.ShowModal()
+        if 'mapNotebook' in self.openDialogs:
+            self.openDialogs['mapNotebook'].notebook.ChangeSelection(2)
+        else:
+            if 'vector' not in self.openDialogs:
+                dlg =  MainVectorDialog(self, id = id, settings = self.instruction)
+                self.openDialogs['vector'] = dlg
+            self.openDialogs['vector'].Show()
+        
+    def OnDecoration(self, event):
+        """!Decorations overlay menu
+        """
+        decmenu = wx.Menu()
+        # legend
+        AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addLegend"].GetLabel())
+        AddLegend.SetBitmap(Icons['psMap']["addLegend"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddLegend)
+        self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
+        # mapinfo
+        AddMapinfo = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addMapinfo"].GetLabel())
+        AddMapinfo.SetBitmap(Icons['psMap']["addMapinfo"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddMapinfo)
+        self.Bind(wx.EVT_MENU, self.OnAddMapinfo, AddMapinfo) 
+        # scalebar
+        AddScalebar = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addScalebar"].GetLabel())
+        AddScalebar.SetBitmap(Icons['psMap']["addScalebar"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddScalebar)
+        self.Bind(wx.EVT_MENU, self.OnAddScalebar, AddScalebar) 
+        # text
+        AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addText"].GetLabel())
+        AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddText)
+        self.Bind(wx.EVT_MENU, self.OnAddText, AddText) 
+        # eps image
+        AddImage = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addImage"].GetLabel())
+        AddImage.SetBitmap(Icons['psMap']["addImage"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddImage)
+        self.Bind(wx.EVT_MENU, self.OnAddImage, AddImage) 
+        # north arrow image
+        AddNorthArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("North arrow"))
+        AddNorthArrow.SetBitmap(wx.ArtProvider.GetBitmap(id = wx.ART_MISSING_IMAGE,
+                                client = wx.ART_MENU, size = self.iconsize))
+        decmenu.AppendItem(AddNorthArrow)
+        self.Bind(wx.EVT_MENU, self.OnAddNorthArrow, AddNorthArrow) 
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(decmenu)
+        decmenu.Destroy()
+        
+    def OnAddScalebar(self, event):
+        """!Add scalebar"""
+        if projInfo()['proj'] == 'll':
+            GMessage(message = _("Scalebar is not appropriate for this projection"))
+            return
+        if self.instruction.FindInstructionByType('scalebar'):
+            id = self.instruction.FindInstructionByType('scalebar').id
+        else: id = None
+        
+        if 'scalebar' not in self.openDialogs:
+            dlg = ScalebarDialog(self, id = id, settings = self.instruction)
+            self.openDialogs['scalebar'] = dlg
+        self.openDialogs['scalebar'].Show()
+        
+    def OnAddLegend(self, event, page = 0):
+        """!Add raster or vector legend"""
+        if self.instruction.FindInstructionByType('rasterLegend'):
+            idR = self.instruction.FindInstructionByType('rasterLegend').id
+        else: idR = None
+        if self.instruction.FindInstructionByType('vectorLegend'):
+            idV = self.instruction.FindInstructionByType('vectorLegend').id
+        else: idV = None
+
+        if 'rasterLegend' not in self.openDialogs:    
+            dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
+            self.openDialogs['rasterLegend'] = dlg
+            self.openDialogs['vectorLegend'] = dlg
+        self.openDialogs['rasterLegend'].notebook.ChangeSelection(page)
+        self.openDialogs['rasterLegend'].Show()
+
+    def OnAddMapinfo(self, event):
+        if self.instruction.FindInstructionByType('mapinfo'):
+            id = self.instruction.FindInstructionByType('mapinfo').id
+        else: id = None
+        
+        if 'mapinfo' not in self.openDialogs:
+            dlg = MapinfoDialog(self, id = id, settings = self.instruction)
+            self.openDialogs['mapinfo'] = dlg
+        self.openDialogs['mapinfo'].Show()
+        
+    def OnAddImage(self, event, id = None):
+        """!Show dialog for image adding and editing"""
+        position = None
+        if 'image' in self.openDialogs:
+            position = self.openDialogs['image'].GetPosition()
+            self.openDialogs['image'].OnApply(event = None)
+            self.openDialogs['image'].Destroy()
+        dlg = ImageDialog(self, id = id, settings = self.instruction)
+        self.openDialogs['image'] = dlg 
+        if position: 
+            dlg.SetPosition(position)
+        dlg.Show()
+        
+    def OnAddNorthArrow(self, event, id = None):
+        """!Show dialog for north arrow adding and editing"""
+        if self.instruction.FindInstructionByType('northArrow'):
+            id = self.instruction.FindInstructionByType('northArrow').id
+        else: id = None
+        
+        if 'northArrow' not in self.openDialogs:
+            dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
+            self.openDialogs['northArrow'] = dlg
+        self.openDialogs['northArrow'].Show()
+        
+    def OnAddText(self, event, id = None):
+        """!Show dialog for text adding and editing"""
+        position = None
+        if 'text' in self.openDialogs:
+            position = self.openDialogs['text'].GetPosition()
+            self.openDialogs['text'].OnApply(event = None)
+            self.openDialogs['text'].Destroy()
+        dlg = TextDialog(self, id = id, settings = self.instruction)
+        self.openDialogs['text'] = dlg 
+        if position: 
+            dlg.SetPosition(position)
+        dlg.Show()
+        
+        
+    def getModifiedTextBounds(self, x, y, textExtent, rotation):
+        """!computes bounding box of rotated text, not very precisely"""
+        w, h = textExtent
+        rotation = float(rotation)/180*pi
+        H = float(w) * sin(rotation)
+        W = float(w) * cos(rotation)
+        X, Y = x, y
+        if pi/2 < rotation <= 3*pi/2:
+            X = x + W 
+        if 0 < rotation < pi:
+            Y = y - H
+        if rotation == 0:
+            return wx.Rect(x,y, *textExtent)
+        else:
+            return wx.Rect(X, Y, abs(W), abs(H)).Inflate(h,h) 
+
+    def makePSFont(self, textDict):
+        """!creates a wx.Font object from selected postscript font. To be
+        used for estimating bounding rectangle of text"""
+        
+        fontsize = textDict['fontsize'] * self.canvas.currScale
+        fontface = textDict['font'].split('-')[0]
+        try:
+            fontstyle = textDict['font'].split('-')[1]
+        except IndexError:
+            fontstyle = ''
+        
+        if fontface == "Times":
+            family = wx.FONTFAMILY_ROMAN
+            face = "times"
+        elif fontface == "Helvetica":
+            family = wx.FONTFAMILY_SWISS
+            face = 'helvetica'
+        elif fontface == "Courier":
+            family = wx.FONTFAMILY_TELETYPE
+            face = 'courier'
+        else:
+            family = wx.FONTFAMILY_DEFAULT
+            face = ''
+            
+        style = wx.FONTSTYLE_NORMAL
+        weight = wx.FONTWEIGHT_NORMAL
+            
+        if 'Oblique' in fontstyle:
+            style =  wx.FONTSTYLE_SLANT
+            
+        if 'Italic' in fontstyle:
+            style =  wx.FONTSTYLE_ITALIC
+            
+        if 'Bold' in fontstyle:
+            weight = wx.FONTWEIGHT_BOLD
+        
+        try:
+            fn = wx.Font(pointSize = fontsize, family = family, style = style,
+                         weight = weight, face = face)
+        except:
+            fn = wx.Font(pointSize = fontsize, family = wx.FONTFAMILY_DEFAULT, 
+                         style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_NORMAL)
+
+        return fn
+       
+       
+    def getTextExtent(self, textDict):
+        """!Estimates bounding rectangle of text"""
+        #fontsize = str(fontsize if fontsize >= 4 else 4)
+        dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
+       
+        fn = self.makePSFont(textDict)
+
+        try:
+            dc.SetFont(fn)
+            w,h,lh = dc.GetMultiLineTextExtent(textDict['text'])
+            return (w,h)
+        except:
+            return (0,0)
+    
+    def getInitMap(self):
+        """!Create default map frame when no map is selected, needed for coordinates in map units"""
+        instrFile = grass.tempfile()
+        instrFileFd = open(instrFile, mode = 'w')
+        instrFileFd.write(self.InstructionFile())
+        instrFileFd.flush()
+        instrFileFd.close()
+        
+        page = self.instruction.FindInstructionByType('page')
+        mapInitRect = GetMapBounds(instrFile, portrait = (page['Orientation'] == 'Portrait'))
+        grass.try_remove(instrFile)
+        
+        region = grass.region()
+        units = UnitConversion(self)
+        realWidth = units.convert(value = abs(region['w'] - region['e']), fromUnit = 'meter', toUnit = 'inch')
+        scale = mapInitRect.Get()[2]/realWidth  
+        
+        initMap = self.instruction.FindInstructionByType('initMap')
+        if initMap:
+            id = initMap.id 
+        else:
+            id = None
+
+        
+        if not id:
+            id = wx.NewId()
+            initMap = InitMap(id)
+            self.instruction.AddInstruction(initMap)
+        self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
+
+    def OnDelete(self, event):
+        if self.canvas.dragId != -1 and self.currentPage == 0:
+            if self.instruction[self.canvas.dragId].type == 'map':
+                self.deleteObject(self.canvas.dragId)
+                self.getInitMap()
+                self.canvas.RecalculateEN()
+            else:
+                self.deleteObject(self.canvas.dragId)   
+    
+    def deleteObject(self, id):
+        """!Deletes object, his id and redraws"""
+        #delete from canvas
+        self.canvas.pdcObj.RemoveId(id)
+        if id == self.canvas.dragId:
+            self.canvas.pdcTmp.RemoveAll()
+            self.canvas.dragId = -1
+        self.canvas.Refresh()
+        
+        # delete from instructions
+        del self.instruction[id]
+
+    def DialogDataChanged(self, id):
+        ids = id
+        if type(id) == int:
+            ids = [id]
+        for id in ids:
+            itype = self.instruction[id].type
+            
+            if itype in ('scalebar', 'mapinfo', 'image'):
+                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                self.canvas.UpdateLabel(itype = itype, id = id)
+                self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+                self.canvas.RedrawSelectBox(id)
+            if itype == 'northArrow':
+                self.canvas.UpdateLabel(itype = itype, id = id)
+                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'bitmap', bb = drawRectangle)
+                self.canvas.RedrawSelectBox(id)
+            if itype == 'text':
+                
+                if self.instruction[id]['rotate']:
+                    rot = float(self.instruction[id]['rotate']) 
+                else:
+                    rot = 0
+
+                extent = self.getTextExtent(textDict = self.instruction[id].GetInstruction())
+                rect = wx.Rect2D(self.instruction[id]['where'][0], self.instruction[id]['where'][1], 0, 0)
+                self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
+                
+                #computes text coordinates according to reference point, not precisely
+                if self.instruction[id]['ref'].split()[0] == 'lower':
+                    self.instruction[id]['coords'][1] -= extent[1]
+                elif self.instruction[id]['ref'].split()[0] == 'center':
+                    self.instruction[id]['coords'][1] -= extent[1]/2
+                if self.instruction[id]['ref'].split()[1] == 'right':
+                    self.instruction[id]['coords'][0] -= extent[0] * cos(rot/180*pi)
+                    self.instruction[id]['coords'][1] += extent[0] * sin(rot/180*pi)
+                elif self.instruction[id]['ref'].split()[1] == 'center':
+                    self.instruction[id]['coords'][0] -= extent[0]/2 * cos(rot/180*pi)
+                    self.instruction[id]['coords'][1] += extent[0]/2 * sin(rot/180*pi)
+                    
+                self.instruction[id]['coords'][0] += self.instruction[id]['xoffset']
+                self.instruction[id]['coords'][1] -= self.instruction[id]['yoffset']
+                coords = self.instruction[id]['coords']
+                self.instruction[id]['rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
+                self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
+                                        textDict = self.instruction[id].GetInstruction(),
+                                        coords = coords, bounds = bounds)
+                self.canvas.RedrawSelectBox(id)
+                
+            if itype in ('map', 'vector', 'raster'):
+                
+                if itype == 'raster':#set resolution
+                    info = grass.raster_info(self.instruction[id]['raster'])
+                    RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
+                    # change current raster in raster legend
+                    
+                if 'rasterLegend' in self.openDialogs:
+                    self.openDialogs['rasterLegend'].updateDialog()
+                id = self.instruction.FindInstructionByType('map').id
+                
+                #check resolution
+                if itype == 'raster':
+                    SetResolution(dpi = self.instruction[id]['resolution'], 
+                                  width = self.instruction[id]['rect'].width,
+                                  height = self.instruction[id]['rect'].height)   
+                rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'],
+                                                                canvasToPaper = False)
+                self.canvas.RecalculateEN()
+                self.canvas.UpdateMapLabel()
+                
+                self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
+                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
+                # redraw select box  
+                self.canvas.RedrawSelectBox(id)
+                self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
+                # redraw to get map to the bottom layer
+                #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
+                
+            if itype == 'rasterLegend':
+                if self.instruction[id]['rLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
+                    drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                    self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+                                     pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+                    self.canvas.RedrawSelectBox(id)
+                else:
+                    self.deleteObject(id)
+                    
+            if itype == 'vectorLegend':
+                if not self.instruction.FindInstructionByType('vector'):
+                    self.deleteObject(id)
+                elif self.instruction[id]['vLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
+                    drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                    self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+                                     pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+                    self.canvas.RedrawSelectBox(id)
+
+                else:
+                    self.deleteObject(id)
+                
+    def OnPageChanged(self, event):
+        """!Flatnotebook page has changed"""
+        self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
+        
+        
+    def OnPageChanging(self, event):
+        """!Flatnotebook page is changing"""
+        if self.currentPage == 0 and self.mouse['use'] == 'addMap':
+            event.Veto()
+
+    def OnHelp(self, event):
+        """!Show help"""
+        if self.parent and self.parent.GetName() == 'LayerManager':
+            log = self.parent.GetLogWindow()
+            log.RunCmd(['g.manual',
+                        'entry=wxGUI.PsMap'])
+        else:
+            RunCommand('g.manual',
+                       quiet = True,
+                       entry = 'wxGUI.PsMap')
+        
+    def OnAbout(self, event):
+        """!Display About window"""
+        info = wx.AboutDialogInfo()
+        
+        info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+        info.SetName(_('wxGUI Cartographic Composer'))
+        info.SetWebSite('http://grass.osgeo.org')
+        info.SetDescription(_('(C) 2011 by the GRASS Development Team\n\n') + 
+                            '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
+                                                      '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
+        
+        wx.AboutBox(info)
+
+    def OnCloseWindow(self, event):
+        """!Close window"""
+        try:
+            os.remove(self.imgName)
+        except OSError:
+            pass
+        grass.set_raise_on_error(False)
+        self.Destroy()
+
+
+
+class PsMapBufferedWindow(wx.Window):
+    """!A buffered window class.
+    
+    @param parent parent window
+    @param kwargs other wx.Window parameters
+    """
+    def __init__(self, parent, id =  wx.ID_ANY,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE,
+                 **kwargs):
+        wx.Window.__init__(self, parent, id = id, style = style)
+        self.parent = parent
+    
+        self.FitInside()
+        
+        # store an off screen empty bitmap for saving to file
+        self._buffer = None
+        # indicates whether or not a resize event has taken place
+        self.resize = False 
+        
+        self.mouse = kwargs['mouse']
+        self.cursors = kwargs['cursors']
+        self.preview = kwargs['preview']
+        self.pen = kwargs['pen']
+        self.brush = kwargs['brush']
+        
+        if kwargs.has_key('instruction'):
+            self.instruction = kwargs['instruction']
+        if kwargs.has_key('openDialogs'):
+            self.openDialogs = kwargs['openDialogs']
+        if kwargs.has_key('pageId'):
+            self.pageId = kwargs['pageId']
+        if kwargs.has_key('objectId'):
+            self.objectId = kwargs['objectId']
+        
+        
+        #labels
+        self.itemLabelsDict = { 'map': 'MAP FRAME',
+                                'rasterLegend': 'RASTER LEGEND',
+                                'vectorLegend': 'VECTOR LEGEND',
+                                'mapinfo': 'MAP INFO',
+                                'scalebar': 'SCALE BAR',
+                                'image': 'IMAGE',
+                                'northArrow': 'NORTH ARROW'}
+        self.itemLabels = {}
+        
+        # define PseudoDC
+        self.pdc = wx.PseudoDC()
+        self.pdcObj = wx.PseudoDC()
+        self.pdcPaper = wx.PseudoDC()
+        self.pdcTmp = wx.PseudoDC()
+        self.pdcImage = wx.PseudoDC()
+        dc = wx.PaintDC(self)
+        self.font = dc.GetFont()
+        
+        self.SetClientSize((700,510))#?
+        self._buffer = wx.EmptyBitmap(*self.GetClientSize())
+        
+        self.idBoxTmp = wx.NewId()
+        self.idZoomBoxTmp = wx.NewId()
+        self.idResizeBoxTmp = wx.NewId()
+        
+        
+
+        self.dragId = -1
+        
+        if self.preview:
+            self.image = None
+            self.imageId = 2000
+            self.imgName = self.parent.imgName
+            
+            
+            
+        self.currScale = None
+        
+        self.Clear()
+        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
+        
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE,  self.OnSize)
+        self.Bind(wx.EVT_IDLE,  self.OnIdle)
+        self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
+
+
+    def Clear(self):
+        """!Clear canvas and set paper
+        """
+        bg = wx.LIGHT_GREY_BRUSH
+        self.pdcPaper.BeginDrawing()
+        self.pdcPaper.SetBackground(bg)
+        self.pdcPaper.Clear()
+        self.pdcPaper.EndDrawing()
+        
+        self.pdcObj.RemoveAll()
+        self.pdcTmp.RemoveAll()
+        
+
+
+        if not self.preview:
+            self.SetPage()
+
+    
+    def CanvasPaperCoordinates(self, rect, canvasToPaper = True):
+        """!Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa"""
+        
+        units = UnitConversion(self)
+        
+        fromU = 'pixel'
+        toU = 'inch'
+        pRect = self.pdcPaper.GetIdBounds(self.pageId)
+        pRectx, pRecty = pRect.x, pRect.y 
+        scale = 1/self.currScale
+        if not canvasToPaper: # paper -> canvas
+            fromU = 'inch'
+            toU = 'pixel'
+            scale = self.currScale
+            pRectx = units.convert(value =  - pRect.x, fromUnit = 'pixel', toUnit = 'inch' ) /scale #inch, real, negative
+            pRecty = units.convert(value =  - pRect.y, fromUnit = 'pixel', toUnit = 'inch' ) /scale 
+        Width = units.convert(value = rect.width, fromUnit = fromU, toUnit = toU) * scale
+        Height = units.convert(value = rect.height, fromUnit = fromU, toUnit = toU) * scale
+        X = units.convert(value = (rect.x - pRectx), fromUnit = fromU, toUnit = toU) * scale
+        Y = units.convert(value = (rect.y - pRecty), fromUnit = fromU, toUnit = toU) * scale
+
+        return wx.Rect2D(X, Y, Width, Height)
+
+    
+    
+    def SetPage(self):
+        """!Sets and changes page, redraws paper"""
+        
+        page = self.instruction[self.pageId]
+        if not page:
+            page = PageSetup(id = self.pageId)
+            self.instruction.AddInstruction(page)
+        
+        ppi = wx.PaintDC(self).GetPPI()
+        cW, cH = self.GetClientSize()
+        pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
+
+        if self.currScale is None:
+            self.currScale = min(cW/pW, cH/pH)
+        pW = pW * self.currScale
+        pH = pH * self.currScale
+        
+        x = cW/2 - pW/2
+        y = cH/2 - pH/2
+        self.DrawPaper(wx.Rect(x, y, pW, pH))
+
+
+    def modifyRectangle(self, r):
+        """! Recalculates rectangle not to have negative size"""
+        if r.GetWidth() < 0:
+            r.SetX(r.GetX() + r.GetWidth())
+        if r.GetHeight() < 0:
+            r.SetY(r.GetY() + r.GetHeight())
+        r.SetWidth(abs(r.GetWidth()))
+        r.SetHeight(abs(r.GetHeight()))
+        return r 
+    
+    def RecalculateEN(self):
+        """!Recalculate east and north for texts (eps, points) after their or map's movement"""
+        try:
+            mapId = self.instruction.FindInstructionByType('map').id
+        except AttributeError:
+            mapId = self.instruction.FindInstructionByType('initMap').id
+        
+        for itemType in ('text', 'image', 'northArrow'):
+            items = self.instruction.FindInstructionByType(itemType, list = True)
+            for item in items:
+                e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[item.id]['where'][0],
+                                           y = self.instruction[item.id]['where'][1], paperToMap = True)
+                self.instruction[item.id]['east'], self.instruction[item.id]['north'] = e, n
+                
+    def OnPaint(self, event):
+        """!Draw pseudo DC to buffer
+        """
+        if not self._buffer:
+            return
+        dc = wx.BufferedPaintDC(self, self._buffer)
+        # use PrepareDC to set position correctly
+        self.PrepareDC(dc)
+        
+        dc.SetBackground(wx.LIGHT_GREY_BRUSH)
+        dc.Clear()
+        
+        # draw paper
+        if not self.preview:
+            self.pdcPaper.DrawToDC(dc)
+        # draw to the DC using the calculated clipping rect
+
+        rgn = self.GetUpdateRegion()
+        
+        if not self.preview:
+            self.pdcObj.DrawToDCClipped(dc, rgn.GetBox())
+        else: 
+            self.pdcImage.DrawToDCClipped(dc, rgn.GetBox())
+        self.pdcTmp.DrawToDCClipped(dc, rgn.GetBox())
+        
+    def OnMouse(self, event):
+
+        if event.GetWheelRotation():
+            zoom = event.GetWheelRotation()
+            use = self.mouse['use']
+            self.mouse['begin'] = event.GetPosition()
+            if zoom > 0:
+                self.mouse['use'] = 'zoomin'
+            else:
+                self.mouse['use'] = 'zoomout'
+                
+            zoomFactor, view = self.ComputeZoom(wx.Rect(0,0,0,0))
+            self.Zoom(zoomFactor, view)
+            self.mouse['use'] = use
+            
+        if event.Moving():
+            if self.mouse['use'] in ('pointer', 'resize'):
+                pos = event.GetPosition()
+                foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
+                if foundResize and foundResize[0] == self.idResizeBoxTmp:
+                    self.SetCursor(self.cursors["sizenwse"])
+                    self.parent.SetStatusText(_('Click and drag to resize object'), 0)
+                else:
+                    self.parent.SetStatusText('', 0)
+                    self.SetCursor(self.cursors["default"])
+                    
+        elif event.LeftDown():
+            self.mouse['begin'] = event.GetPosition()
+            self.begin = self.mouse['begin']
+            if self.mouse['use'] in ('pan', 'zoomin', 'zoomout', 'addMap'):
+                pass
+            
+            #select
+            if self.mouse['use'] == 'pointer':
+                found = self.pdcObj.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
+                foundResize = self.pdcTmp.FindObjects(self.mouse['begin'][0], self.mouse['begin'][1])
+
+                if foundResize and foundResize[0] == self.idResizeBoxTmp:
+                    self.mouse['use'] = 'resize'
+                    
+                    # when resizing, proportions match region
+                    if self.instruction[self.dragId].type == 'map':
+                        self.constraint = False
+                        self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
+                        if self.instruction[self.dragId]['scaleType'] in (0, 1, 2):
+                            self.constraint = True
+                            self.mapBounds = self.pdcObj.GetIdBounds(self.dragId)
+                    
+                elif found:
+                    self.dragId = found[0]  
+                    self.RedrawSelectBox(self.dragId)
+                    if self.instruction[self.dragId].type != 'map':
+                        self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+                        self.Refresh()
+                        
+                else:
+                    self.dragId = -1
+                    self.pdcTmp.RemoveId(self.idBoxTmp)
+                    self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+                    self.Refresh()           
+                    
+                    
+        elif event.Dragging() and event.LeftIsDown():
+            #draw box when zooming, creating map 
+            if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap'):
+                self.mouse['end'] = event.GetPosition()
+                r = wx.Rect(self.mouse['begin'][0], self.mouse['begin'][1],
+                            self.mouse['end'][0]-self.mouse['begin'][0], self.mouse['end'][1]-self.mouse['begin'][1])
+                r = self.modifyRectangle(r)
+                self.Draw(pen = self.pen['box'], brush = self.brush['box'], pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
+                          pdctype = 'rect', bb = r)
+                
+            # panning                
+            if self.mouse["use"] == 'pan':
+                self.mouse['end'] = event.GetPosition()
+                view = self.mouse['begin'][0] - self.mouse['end'][0], self.mouse['begin'][1] - self.mouse['end'][1]
+                zoomFactor = 1
+                self.Zoom(zoomFactor, view)
+                self.mouse['begin'] = event.GetPosition()
+                
+            #move object
+            if self.mouse['use'] == 'pointer' and self.dragId != -1:
+                
+                self.mouse['end'] = event.GetPosition()
+                dx, dy = self.mouse['end'][0] - self.begin[0], self.mouse['end'][1] - self.begin[1]
+                self.pdcObj.TranslateId(self.dragId, dx, dy)
+                self.pdcTmp.TranslateId(self.idBoxTmp, dx, dy)
+                self.pdcTmp.TranslateId(self.idResizeBoxTmp, dx, dy)
+                if self.instruction[self.dragId].type == 'text': 
+                    self.instruction[self.dragId]['coords'] = self.instruction[self.dragId]['coords'][0] + dx,\
+                        self.instruction[self.dragId]['coords'][1] + dy
+                self.begin = event.GetPosition()
+                self.Refresh()
+                
+            # resize object
+            if self.mouse['use'] == 'resize':
+                type = self.instruction[self.dragId].type
+                pos = event.GetPosition()
+                x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
+                width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
+                diffX = pos[0] - self.mouse['begin'][0]
+                diffY = pos[1] - self.mouse['begin'][1]
+                # match given region
+                if self.constraint:
+                    if width > height:
+                        newWidth = width + diffX
+                        newHeight = height + diffX * (float(height) / width)
+                    else:
+                        newWidth = width + diffY * (float(width) / height)
+                        newHeight = height + diffY
+                else:
+                    newWidth = width + diffX
+                    newHeight = height + diffY
+                    
+                if newWidth < 10 or newHeight < 10:
+                    return
+                
+                bounds = wx.Rect(x, y, newWidth, newHeight)    
+                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj, drawid = self.dragId,
+                          pdctype = 'rectText', bb = bounds)
+                self.RedrawSelectBox(self.dragId)
+                
+        elif event.LeftUp():
+            # zoom in, zoom out
+            if self.mouse['use'] in ('zoomin','zoomout'):
+                zoomR = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
+                self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+                self.Refresh()
+                zoomFactor, view = self.ComputeZoom(zoomR)
+                self.Zoom(zoomFactor, view)
+
+                
+            # draw map frame    
+            if self.mouse['use'] == 'addMap':
+                rectTmp = self.pdcTmp.GetIdBounds(self.idZoomBoxTmp)
+                # too small rectangle, it's usually some mistake
+                if rectTmp.GetWidth() < 20 or rectTmp.GetHeight() < 20:
+                    self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+                    self.Refresh()
+                    return
+                rectPaper = self.CanvasPaperCoordinates(rect = rectTmp, canvasToPaper = True)                
+                
+                dlg = MapDialog(parent = self.parent, id = [None, None, None], settings = self.instruction, 
+                                rect = rectPaper)
+                self.openDialogs['map'] = dlg
+                self.openDialogs['map'].Show()
+                
+                
+                self.mouse['use'] = self.parent.mouseOld
+
+                self.SetCursor(self.parent.cursorOld)
+                self.parent.toolbar.ToggleTool(self.parent.actionOld, True)
+                self.parent.toolbar.ToggleTool(self.parent.toolbar.action['id'], False)
+                self.parent.toolbar.action['id'] = self.parent.actionOld
+                
+
+
+            # resize resizable objects (only map sofar)
+            if self.mouse['use'] == 'resize':
+                mapId = self.instruction.FindInstructionByType('map').id
+                
+                if self.dragId == mapId:
+                    # necessary to change either map frame (scaleType 0,1,2) or region (scaletype 3)
+                    newRectCanvas = self.pdcObj.GetIdBounds(mapId)
+                    newRectPaper = self.CanvasPaperCoordinates(rect = newRectCanvas, canvasToPaper = True)
+                    self.instruction[mapId]['rect'] = newRectPaper
+                    
+                    if self.instruction[mapId]['scaleType'] in (0, 1, 2):
+                        if self.instruction[mapId]['scaleType'] == 0:
+                            
+                            scale, foo, rect = AutoAdjust(self, scaleType = 0,
+                                                          map = self.instruction[mapId]['map'],
+                                                          mapType = self.instruction[mapId]['mapType'], 
+                                                          rect = self.instruction[mapId]['rect'])
+                            
+                        elif self.instruction[mapId]['scaleType'] == 1:
+                            scale, foo, rect = AutoAdjust(self, scaleType = 1,
+                                                          region = self.instruction[mapId]['region'],
+                                                          rect = self.instruction[mapId]['rect'])
+                        else:
+                            scale, foo, rect = AutoAdjust(self, scaleType = 2,
+                                                          rect = self.instruction[mapId]['rect'])
+                        self.instruction[mapId]['rect'] = rect
+                        self.instruction[mapId]['scale'] = scale
+                        
+                        rectCanvas = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)
+                        self.Draw(pen = self.pen['map'], brush = self.brush['map'],
+                                  pdc = self.pdcObj, drawid = mapId, pdctype = 'rectText', bb = rectCanvas)
+                        
+                    elif self.instruction[mapId]['scaleType'] == 3:
+                        ComputeSetRegion(self, mapDict = self.instruction[mapId].GetInstruction())
+                    #check resolution
+                    SetResolution(dpi = self.instruction[mapId]['resolution'],
+                                  width = self.instruction[mapId]['rect'].width,
+                                  height = self.instruction[mapId]['rect'].height)
+                    
+                    self.RedrawSelectBox(mapId)
+                    self.Zoom(zoomFactor = 1, view = (0, 0))
+                self.mouse['use'] = 'pointer'
+                
+            # recalculate the position of objects after dragging    
+            if self.mouse['use'] in ('pointer', 'resize') and self.dragId != -1:
+                if self.mouse['begin'] != event.GetPosition(): #for double click
+                    
+                    self.RecalculatePosition(ids = [self.dragId])
+                    if self.instruction[self.dragId].type in self.openDialogs:
+                        self.openDialogs[self.instruction[self.dragId].type].updateDialog()
+
+        # double click launches dialogs
+        elif event.LeftDClick():
+            if self.mouse['use'] == 'pointer' and self.dragId != -1:
+                itemCall = {    'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
+                                'scalebar': self.parent.OnAddScalebar, 'image': self.parent.OnAddImage,
+                                'northArrow' : self.parent.OnAddNorthArrow,
+                                'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,  
+                                'map': self.parent.OnAddMap}
+                itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
+                            'scalebar': dict(event = None), 'image': dict(event = None, id = self.dragId),
+                            'northArrow': dict(event = None, id = self.dragId),
+                            'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
+                            'map': dict(event = None, notebook = True)}
+                type = self.instruction[self.dragId].type
+                itemCall[type](**itemArg[type])
+
+                
+                
+                
+    def RecalculatePosition(self, ids):
+        for id in ids:
+            itype = self.instruction[id].type
+            if itype == 'map':
+                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+                                                                           canvasToPaper = True)
+                self.RecalculateEN()
+                
+            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
+                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+                                                                           canvasToPaper = True)
+                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+                                                                            canvasToPaper = True)[:2] 
+                if itype in ('image', 'northArrow'):
+                    self.RecalculateEN()
+            elif  itype == 'scalebar':
+                self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+                                                                           canvasToPaper = True)
+
+                
+                self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
+                
+            elif  itype == 'text':
+                x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
+                    self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
+                extent = self.parent.getTextExtent(textDict = self.instruction[id])
+                if self.instruction[id]['rotate'] is not None:
+                    rot = float(self.instruction[id]['rotate'])/180*pi 
+                else:
+                    rot = 0
+
+                if self.instruction[id]['ref'].split()[0] == 'lower':
+                    y += extent[1]
+                elif self.instruction[id]['ref'].split()[0] == 'center':
+                    y += extent[1]/2
+                if self.instruction[id]['ref'].split()[1] == 'right':
+                    x += extent[0] * cos(rot)
+                    y -= extent[0] * sin(rot)
+                elif self.instruction[id]['ref'].split()[1] == 'center':
+                    x += extent[0]/2 * cos(rot)
+                    y -= extent[0]/2 * sin(rot)
+                
+                self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = wx.Rect2D(x, y, 0, 0),
+                                                                            canvasToPaper = True)[:2]
+                self.RecalculateEN()
+        
+    def ComputeZoom(self, rect):
+        """!Computes zoom factor and scroll view"""
+        zoomFactor = 1
+        cW, cH = self.GetClientSize()
+        cW = float(cW)
+        if rect.IsEmpty(): # clicked on canvas
+            zoomFactor = 1.5
+            if self.mouse['use'] == 'zoomout':
+                zoomFactor = 1./zoomFactor
+            x,y = self.mouse['begin']
+            xView = x - x/zoomFactor#x - cW/(zoomFactor * 2)
+            yView = y - y/zoomFactor#y - cH/(zoomFactor * 2)
+
+        else:   #dragging    
+            rW, rH = float(rect.GetWidth()), float(rect.GetHeight())
+            zoomFactor = 1/max(rW/cW, rH/cH)
+            # when zooming to full extent, in some cases, there was zoom 1.01..., which causes problem
+            if abs(zoomFactor - 1) > 0.01:
+                zoomFactor = zoomFactor 
+            else:
+                zoomFactor = 1.
+
+
+            if self.mouse['use'] == 'zoomout':
+                zoomFactor = min(rW/cW, rH/cH) 
+            if rW/rH > cW/cH:
+                yView = rect.GetY() - (rW*(cH/cW) - rH)/2
+                xView = rect.GetX()
+                
+                if self.mouse['use'] == 'zoomout':
+                    x,y = rect.GetX() + (rW-(cW/cH)*rH)/2, rect.GetY()
+                    xView, yView = -x, -y
+            else:
+                xView = rect.GetX() - (rH*(cW/cH) - rW)/2
+                yView = rect.GetY()
+                if self.mouse['use'] == 'zoomout':
+                    x,y = rect.GetX(), rect.GetY() + (rH-(cH/cW)*rW)/2
+                    xView, yView = -x, -y
+        return zoomFactor, (int(xView), int(yView))
+    
+    
+    def Zoom(self, zoomFactor, view):
+        """! Zoom to specified region, scroll view, redraw"""
+        if not self.currScale:
+            return
+        self.currScale = self.currScale*zoomFactor
+        
+        if self.currScale > 10 or self.currScale < 0.1:
+            self.currScale = self.currScale/zoomFactor
+            return 
+        if not self.preview:
+            # redraw paper
+            pRect = self.pdcPaper.GetIdBounds(self.pageId)
+            pRect.OffsetXY(-view[0], -view[1])
+            pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
+            self.DrawPaper(pRect)
+            
+            #redraw objects
+            for id in self.objectId:
+                oRect = self.CanvasPaperCoordinates(
+                    rect = self.instruction[id]['rect'], canvasToPaper = False)
+                
+                type = self.instruction[id].type
+                if type == 'text':
+                    coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
+                    self.instruction[id]['coords'] = coords = [(int(coord) - view[i]) * zoomFactor
+                                                               for i, coord in enumerate(coords)]
+                    self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
+                                     coords = coords, bounds = oRect )
+                    extent = self.parent.getTextExtent(textDict = self.instruction[id])
+                    if self.instruction[id]['rotate']:
+                        rot = float(self.instruction[id]['rotate']) 
+                    else:
+                        rot = 0
+
+                    self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
+                    self.pdcObj.SetIdBounds(id, bounds)
+                elif type == 'northArrow':
+                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
+                              drawid = id, pdctype = 'bitmap', bb = oRect)
+                else:
+                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
+                              drawid = id, pdctype = 'rectText', bb = oRect)
+            #redraw tmp objects
+            if self.dragId != -1:
+                self.RedrawSelectBox(self.dragId)
+                
+        #redraw preview
+        else: # preview mode    
+            imageRect = self.pdcImage.GetIdBounds(self.imageId)
+            imageRect.OffsetXY(-view[0], -view[1])
+            imageRect = self.ScaleRect(rect = imageRect, scale = zoomFactor)
+            self.DrawImage(imageRect)
+        
+    def ZoomAll(self):
+        """! Zoom to full extent"""  
+        if not self.preview:
+            bounds = self.pdcPaper.GetIdBounds(self.pageId)
+        else:
+            bounds = self.pdcImage.GetIdBounds(self.imageId)
+        zoomP = bounds.Inflate(bounds.width/20, bounds.height/20)
+        zoomFactor, view = self.ComputeZoom(zoomP)
+        self.Zoom(zoomFactor, view)
+        
+    def Draw(self, pen, brush, pdc, drawid = None, pdctype = 'rect', bb = wx.Rect(0,0,0,0)): 
+        """! Draw object"""    
+        if drawid is None:
+            drawid = wx.NewId()
+        bb = bb.Get()
+        pdc.BeginDrawing()
+        pdc.RemoveId(drawid)
+        pdc.SetId(drawid)
+        pdc.SetPen(pen)
+        pdc.SetBrush(brush)
+        
+        if pdctype == 'bitmap':
+            if havePILImage:
+                file = self.instruction[drawid]['epsfile']
+                rotation = self.instruction[drawid]['rotate']
+                self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
+            else: # draw only rectangle with label
+                pdctype = 'rectText'
+                
+        if pdctype in ('rect', 'rectText'):
+            pdc.DrawRectangle(*bb)
+            
+        if pdctype == 'rectText':
+            dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
+            font = self.font
+            size = 10
+            font.SetPointSize(size)
+            font.SetStyle(wx.ITALIC)
+            dc.SetFont(font)
+            pdc.SetFont(font)
+            text = '\n'.join(self.itemLabels[drawid])
+            w,h,lh = dc.GetMultiLineTextExtent(text)
+            textExtent = (w,h)
+            textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
+            r = map(int, bb)
+            while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
+                size -= 2
+                font.SetPointSize(size)
+                dc.SetFont(font)
+                pdc.SetFont(font)
+                textExtent = dc.GetTextExtent(text)
+                textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
+            pdc.SetTextForeground(wx.Color(100,100,100,200)) 
+            pdc.SetBackgroundMode(wx.TRANSPARENT)
+            pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
+                
+        pdc.SetIdBounds(drawid, bb)
+        pdc.EndDrawing()
+        self.Refresh()
+
+        return drawid
+    
+    def DrawBitmap(self, pdc, filePath, rotation, bbox):
+        """!Draw bitmap using PIL"""
+        pImg = PILImage.open(filePath)
+        if rotation:
+            # get rid of black background
+            pImg = pImg.convert("RGBA")
+            rot = pImg.rotate(rotation, expand = 1)
+            new = PILImage.new('RGBA', rot.size, (255,) * 4)
+            pImg = PILImage.composite(rot, new, rot)
+        pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
+        img = PilImageToWxImage(pImg)
+        bitmap = img.ConvertToBitmap()
+        mask = wx.Mask(bitmap, wx.WHITE)
+        bitmap.SetMask(mask)
+        pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask = True)
+        
+    def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
+        if textDict['rotate']:
+            rot = float(textDict['rotate']) 
+        else:
+            rot = 0
+
+        fontsize = textDict['fontsize'] * self.currScale
+        if textDict['background'] != 'none':
+            background = textDict['background'] 
+        else:
+            background = None
+
+        pdc.RemoveId(drawId)
+        pdc.SetId(drawId)
+        pdc.BeginDrawing()
+        
+        # border is not redrawn when zoom changes, why?
+##        if textDict['border'] != 'none' and not rot:
+##            units = UnitConversion(self)
+##            borderWidth = units.convert(value = textDict['width'],
+##                                        fromUnit = 'point', toUnit = 'pixel' ) * self.currScale
+##            pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth))
+##            pdc.DrawRectangle(*bounds)
+            
+        if background:
+            pdc.SetTextBackground(convertRGB(background))
+            pdc.SetBackgroundMode(wx.SOLID)
+        else:
+            pdc.SetBackgroundMode(wx.TRANSPARENT)
+        
+        fn = self.parent.makePSFont(textDict)
+
+        pdc.SetFont(fn)
+        pdc.SetTextForeground(convertRGB(textDict['color']))        
+        pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
+        
+        pdc.SetIdBounds(drawId, wx.Rect(*bounds))
+        self.Refresh()
+        pdc.EndDrawing()
+        
+    def DrawImage(self, rect):
+        """!Draw preview image to pseudoDC"""
+        self.pdcImage.ClearId(self.imageId)
+        self.pdcImage.SetId(self.imageId)
+        img = self.image
+        
+
+        if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
+            img = img.Scale(rect.width, rect.height)
+        bitmap = img.ConvertToBitmap()
+        
+        self.pdcImage.BeginDrawing()
+        self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
+        self.pdcImage.SetIdBounds(self.imageId, rect)
+        self.pdcImage.EndDrawing()
+        self.Refresh()
+        
+    def DrawPaper(self, rect):
+        """!Draw paper and margins"""
+        page = self.instruction[self.pageId]
+        scale = page['Width'] / rect.GetWidth()
+        w = (page['Width'] - page['Right'] - page['Left']) / scale
+        h = (page['Height'] - page['Top'] - page['Bottom']) / scale
+        x = page['Left'] / scale + rect.GetX()
+        y = page['Top'] / scale + rect.GetY()
+        
+        self.pdcPaper.BeginDrawing()
+        self.pdcPaper.RemoveId(self.pageId)
+        self.pdcPaper.SetId(self.pageId)
+        self.pdcPaper.SetPen(self.pen['paper'])
+        self.pdcPaper.SetBrush(self.brush['paper'])
+        self.pdcPaper.DrawRectangleRect(rect)
+        
+        self.pdcPaper.SetPen(self.pen['margins'])
+        self.pdcPaper.SetBrush(self.brush['margins'])
+        self.pdcPaper.DrawRectangle(x, y, w, h)
+        
+        self.pdcPaper.SetIdBounds(self.pageId, rect)
+        self.pdcPaper.EndDrawing()
+        self.Refresh()
+
+        
+    def ImageRect(self):
+        """!Returns image centered in canvas, computes scale"""
+        img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
+        cW, cH = self.GetClientSize()
+        iW, iH = img.GetWidth(), img.GetHeight()
+
+        self.currScale = min(float(cW)/iW, float(cH)/iH)
+        iW = iW * self.currScale
+        iH = iH * self.currScale
+        x = cW/2 - iW/2
+        y = cH/2 - iH/2
+        imageRect = wx.Rect(x, y, iW, iH)
+
+        return imageRect 
+    
+    def RedrawSelectBox(self, id):
+        """!Redraws select box when selected object changes its size"""
+        if self.dragId == id:
+            rect = [self.pdcObj.GetIdBounds(id).Inflate(3,3)]
+            type = ['select']
+            ids = [self.idBoxTmp]
+            if self.instruction[id].type == 'map':
+                controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
+                rect.append(wx.Rect(controlP.x, controlP.y, 10,10))
+                type.append('resize')
+                ids.append(self.idResizeBoxTmp)
+            for id, type, rect in zip(ids, type, rect):
+                self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcTmp,
+                          drawid = id, pdctype = 'rect', bb = rect)
+        
+    def UpdateMapLabel(self):
+        """!Updates map frame label"""
+
+        vector = self.instruction.FindInstructionByType('vector')
+        if vector:
+            vectorId = vector.id 
+        else:
+            vectorId = None
+
+        raster = self.instruction.FindInstructionByType('raster')
+        if raster:
+            rasterId = raster.id 
+        else:
+            rasterId = None
+
+        rasterName = 'None'
+        if rasterId:
+            rasterName = self.instruction[rasterId]['raster'].split('@')[0]
+            
+        mapId = self.instruction.FindInstructionByType('map').id
+        self.itemLabels[mapId] = []
+        self.itemLabels[mapId].append(self.itemLabelsDict['map'])
+        self.itemLabels[mapId].append("raster: " + rasterName)
+        if vectorId: 
+            for map in self.instruction[vectorId]['list']:
+                self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
+            
+    def UpdateLabel(self, itype, id):
+        self.itemLabels[id] = []
+        self.itemLabels[id].append(self.itemLabelsDict[itype])
+        if itype == 'image':
+            file = os.path.basename(self.instruction[id]['epsfile'])
+            self.itemLabels[id].append(file)
+        
+    def OnSize(self, event):
+        """!Init image size to match window size
+        """
+        # not zoom all when notebook page is changed
+        if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
+            self.ZoomAll()
+        self.OnIdle(None)
+        event.Skip()
+        
+    def OnIdle(self, event):
+        """!Only re-render a image during idle time instead of
+        multiple times during resizing.
+        """ 
+        
+        width, height = self.GetClientSize()
+        # Make new off screen bitmap: this bitmap will always have the
+        # current drawing in it, so it can be used to save the image
+        # to a file, or whatever.
+        self._buffer = wx.EmptyBitmap(width, height)
+        # re-render image on idle
+        self.resize = True
+        
+    def ScaleRect(self, rect, scale):
+        """! Scale rectangle"""
+        return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
+                       rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)   
+    
+def main():
+    import gettext
+    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+    
+    app = wx.PySimpleApp()
+    wx.InitAllImageHandlers()
+    frame = PsMapFrame()
+    frame.Show()
+    
+    app.MainLoop()
+
+if __name__ == "__main__":
+    main()

Added: grass/trunk/gui/wxpython/psmap/menudata.py
===================================================================
--- grass/trunk/gui/wxpython/psmap/menudata.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/psmap/menudata.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,39 @@
+"""!
+ at package core.menudata
+
+ at brief Complex list for menu entries for wxGUI
+
+Classes:
+ - MenuData
+
+Usage:
+ at code
+python menudata.py [action] [manager|modeler]
+ at endcode
+
+where <i>action</i>:
+ - strings (default)
+ - tree
+ - commands
+ - dump
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Yann Chemin <yann.chemin gmail.com>
+ at author Martin Landa <landa.martin gmail.com>
+ at author Glynn Clements
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import os
+import sys
+import pprint
+try:
+    import xml.etree.ElementTree as etree
+except ImportError:
+    import elementtree.ElementTree as etree # Python <= 2.4
+
+import wx


Property changes on: grass/trunk/gui/wxpython/psmap/menudata.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/psmap/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/psmap/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/psmap/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,93 @@
+"""!
+ at package psmap.toolbars
+
+ at brief wxPsMap toolbars classes
+
+Classes:
+ - PsMapToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import os
+import sys
+
+import wx
+
+from core              import globalvar
+from gui_core.toolbars import BaseToolbar
+
+sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
+from icon              import Icons
+
+class PsMapToolbar(BaseToolbar):
+    def __init__(self, parent):
+        """!Toolbar Cartographic Composer (psmap.py)
+        
+        @param parent parent window
+        """
+        AbstractToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        self.Realize()
+        
+        self.action = { 'id' : self.pointer }
+        self.defaultAction = { 'id' : self.pointer,
+                               'bind' : self.parent.OnPointer }
+        self.OnTool(None)
+        
+        from psmap import havePILImage
+        if not havePILImage:
+            self.EnableTool(self.preview, False)
+        
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        icons = Icons['psMap']
+        return self._getToolbarData((('loadFile', icons['scriptLoad'],
+                                      self.parent.OnLoadFile),                                    
+                                     ('instructionFile', icons['scriptSave'],
+                                      self.parent.OnInstructionFile),
+                                     (None, ),
+                                     ('pagesetup', icons['pageSetup'],
+                                      self.parent.OnPageSetup),
+                                     (None, ),
+                                     ("pointer", Icons["displayWindow"]["pointer"],
+                                      self.parent.OnPointer, wx.ITEM_CHECK),
+                                     ('pan', Icons["displayWindow"]['pan'],
+                                      self.parent.OnPan, wx.ITEM_CHECK),
+                                     ("zoomin", Icons["displayWindow"]["zoomIn"],
+                                      self.parent.OnZoomIn, wx.ITEM_CHECK),
+                                     ("zoomout", Icons["displayWindow"]["zoomOut"],
+                                      self.parent.OnZoomOut, wx.ITEM_CHECK),
+                                     ('zoomAll', icons['fullExtent'],
+                                      self.parent.OnZoomAll),
+                                     (None, ),
+                                     ('addMap', icons['addMap'],
+                                      self.parent.OnAddMap, wx.ITEM_CHECK),
+                                     ('addRaster', icons['addRast'],
+                                      self.parent.OnAddRaster),
+                                     ('addVector', icons['addVect'],
+                                      self.parent.OnAddVect),
+                                     ("dec", Icons["displayWindow"]["overlay"],
+                                      self.parent.OnDecoration),
+                                     ("delete", icons["deleteObj"],
+                                      self.parent.OnDelete),
+                                     (None, ),
+                                     ("preview", icons["preview"],
+                                      self.parent.OnPreview),
+                                     ('generatePS', icons['psExport'],
+                                      self.parent.OnPSFile),
+                                     ('generatePDF', icons['pdfExport'],
+                                      self.parent.OnPDFFile),
+                                     (None, ),
+                                     ("help", Icons['misc']['help'],
+                                      self.parent.OnHelp),
+                                     ('quit', icons['quit'],
+                                      self.parent.OnCloseWindow))
+                                    )


Property changes on: grass/trunk/gui/wxpython/psmap/toolbars.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Modified: grass/trunk/gui/wxpython/scripts/r.li.setup.py
===================================================================
--- grass/trunk/gui/wxpython/scripts/r.li.setup.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/scripts/r.li.setup.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -25,7 +25,7 @@
 GUIModulesPath = os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython", "gui_modules")
 sys.path.append(GUIModulesPath)
 
-import globalvar
+from core import globalvar
 
 import wx
 import wx.lib.mixins.listctrl as listmix
@@ -33,8 +33,8 @@
 import wx.lib.scrolledpanel as scrolled
 import time
 
-import gcmd
-import utils
+from core import cmd as gcmd
+from core import utils
 from grass.script import core as grass
 
 #@TODO create wizard instead of progressively increasing window

Modified: grass/trunk/gui/wxpython/scripts/vkrige.py
===================================================================
--- grass/trunk/gui/wxpython/scripts/vkrige.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/scripts/vkrige.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -36,11 +36,11 @@
 GUIModulesPath = os.path.join(os.getenv("GISBASE"), "etc", "gui", "wxpython", "gui_modules")
 sys.path.append(GUIModulesPath)
 
-import globalvar
-import gselect
-import goutput
+from core import globalvar
+import gui_core.gselect
+import gui_core.goutput
 import menuform
-from preferences import globalSettings as UserSettings
+from core.settings import UserSettings
 #import help
 
 import wx

Copied: grass/trunk/gui/wxpython/states.txt (from rev 49324, grass/trunk/gui/wxpython/gui_modules/states.txt)
===================================================================
--- grass/trunk/gui/wxpython/states.txt	                        (rev 0)
+++ grass/trunk/gui/wxpython/states.txt	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,185 @@
+Afghanistan; 59.9,28.66 75.65,39.11
+Africa; -20.2,-37.6 53.4,35.75
+Albania; 19.36,39.42 21.39,42.71
+Algeria; -9.47,17.94 13.19,38.14
+Angola; 11.31,-18.68 24.97,-3.84
+Antarctic; -180,-90 180,-66
+Antarctica; -180,-90 180,-62.83
+Arctic; -180,66 180,90
+Argentina; -74.97,-56.71 -51.76,-20.25
+Armenia; 43.53,38.68 47.07,41.48
+Asia; 40,-10 180,83.5
+Australia; 111.22,-45.73 155.72,-8.88
+Austria; 9.27,45.99 17.93,49.38
+Azerbaijan; 44.58,38.04 50.96,42.2
+Bangladesh; 87.95,20.75 93.07,26.62
+Belgium; 2.54,49.31 6.69,51.69
+Belize; -89.18,15.78 -87.78,18.64
+Benin; 0.74,5.97 4.34,12.66
+Bhutan; 88.8,26.54 92.37,28.46
+Bolivia; -70.05,-23.63 -56.72,-9.13
+Bosnia and Herzegovina; 15.76,42.38 20.02,45.45
+Botswana; 19.57,-27.41 29.94,-17.32
+Brazil; -75.64,-35.81 -32.74,7.12
+Brunei; 114.22,3.96 115.42,5.09
+Bulgaria; 22.19,40.86 29.02,44.59
+Burkina Faso; -5.72,9.19 2.98,15.54
+Burma; 91.41,9.22 102.13,29.34
+Burundi; 28.98,-4.85 31.17,-2.35
+Byelarus; 22.91,50.82 33.38,56.65
+Cambodia; 102.28,10.07 107.98,14.86
+Cameroon; 8.22,1.06 16.85,13.65
+Canada; -145.27,37.3 -48.11,87.61
+Caribbean; -91.4,27.36 -55.4,6.48
+Central African Republic; 13.96,1.5 28.11,11.67
+Central America; -94.1,21.8 -75.8,6.61
+Chad; 12.88,6.67 24.97,24.19
+Chile; -77.16,-56.79 -64.9,-15.72
+China; 70.83,15.06 137.97,56.58
+Colombia; -79.69,-5 -66.15,13.28
+Congo; 10.93,-5.41 19.19,3.98
+Costa Rica; -85.83,7.9 -82.18,11.38
+Croatia; 13.47,42.09 19.92,46.84
+Cuba; -85.03,19.36 -73.44,23.68
+Cyprus; 32.23,34.44 34.78,35.78
+Czech Republic; 12.13,48.23 19.38,51.42
+Denmark; 8.02,54.68 12.89,58
+Djibouti; 41.89,10.78 43.77,12.81
+Dominican Republic; -71.87,17.54 -67.99,20.12
+East Pacific Ocean; -180,64.8 -72.7,-75.6
+Ecuador; -81.08,-5.35 -74.68,1.72
+Egypt; 24.29,21.29 37.61,32.14
+El Salvador; -90.05,13.07 -87.41,14.6
+Equatorial Guinea; 8.39,0.76 11.59,3.82
+Eritrea; 36.31,12 43.58,18.41
+Estonia; 23.3,57.29 28.59,59.75
+Ethiopia; 32.49,2.63 48.85,15.56
+Europe; -25.1,71.3 35,34.9
+Finland; 20.46,59.3 32.14,70.44
+France; -5.29,40.65 10.4,51.82
+French Guiana; -54.37,1.84 -51.23,5.89
+Gabon; 8.71,-4.23 15.01,2.6
+Gambia; -16.71,13.02 -13.66,13.96
+Germany; 5.68,46.86 15.68,55.41
+Ghana; -3.31,4.39 1.7,11.47
+Greece; 19.99,34.62 27.19,42.01
+Greenland; -75.34,56.78 -9.36,86.6
+Guatemala; -92.24,13.59 -87.87,18.06
+Guinea; -15.19,6.77 -6.87,13.02
+Guinea-Bissau; -16.51,10.97 -13.34,12.8
+Guyana; -61.41,0.81 -56.12,8.79
+Haiti; -74.38,17.88 -71.34,20.1
+Honduras; -89.47,12.75 -82.92,16.31
+Hungary; 16.12,45.44 23.57,48.95
+Iceland; -24.55,62.81 -12.79,67.01
+India; 66.79,6.58 99.01,36.96
+Indian Ocean; 22.3,-55.4 119.5,25.2
+Indonesia; 93.11,-12.65 143.45,7.88
+Iran; 43.31,24.08 64.42,40.73
+Iraq; 38.47,28.5 49.25,37.84
+Ireland; -10.52,51.23 -5.62,55.49
+Israel; 34.17,29.25 36.09,33.31
+Italy; 6.11,36.15 19.33,47.71
+Ivory Coast; -8.64,4.03 -2.01,10.96
+Jamaica; -78.22,17.72 -76,18.63
+Japan; 128.74,30.1 146.46,46.26
+Jordan; 34.97,28.87 39.75,33.44
+Kazakhstan; 44.73,38.62 89.65,57.49
+Kenya; 33,-5.3 42.44,5.07
+Democratic People's Republic of Korea; 124.02,43.29 37.55,130.95
+Republic of Korea; 125.95,38.76 33.06,129.88
+Kuwait; 46.62,28.34 48.74,30
+Kyrgyzstan; 69.01,38.7 81.03,43.77
+Laos; 99.77,13.47 108.1,22.98
+Latvia; 20.76,55.32 28.76,58.44
+Lebanon; 35.09,32.84 36.79,34.63
+Lesotho; 27.16,-30.89 29.76,-28.59
+Liberia; -11.47,4.16 -6.95,8.66
+Libya; 8.79,18.7 26.1,33.95
+Lithuania; 20.86,53.6 27.25,56.73
+Luxembourg; 5.9,49.42 6.77,50.21
+Macedonia; 20.62,40.62 23.27,42.48
+Madagascar; 42.83,-26.31 51.38,-11.58
+Malawi; 32.55,-17.51 36.46,-9.26
+Malaysia; 99.4,-0.2 120.19,7.86
+Mali; -12.77,9.25 5.27,25.83
+Mauritania; -17.47,14.21 -4.04,27.81
+Mexico; -118.48,13.05 -85.18,34.17
+Middle East; 25,10.7 59.7,36.1
+Moldova; 26.64,45.31 30.47,48.64
+Mongolia; 86.47,40 121.62,53.65
+Montenegro; 18.56,41.77 20.67,43.64
+Morocco; -13.52,26.96 -0.28,36.48
+Mozambique; 29.67,-27.82 41.89,-9.63
+Namibia; 11.32,-29.61 25.86,-16.31
+Nepal; 79.9,26 88.84,30.88
+Netherlands; 3.54,50.56 7.62,53.59
+New Hampshire; -72.68,42.57 -70.58,45.43
+New Jersey; -75.69,38.8 -73.78,41.47
+New Mexico; -109.35,31.04 -102.7,37.3
+New Zealand; 166.05,-47.31 179.41,-33.89
+Nicaragua; -87.7,10.55 -82.87,15.24
+Niger; -0.39,10.95 16.95,24.28
+Nigeria; 2.33,3.72 15.34,14.4
+North America; -168.5,18 -50.4,85.7
+North Atlantic Ocean; -82,0 12,80
+Northern Temperate; -180,23 180,60
+Norway; 3.88,56.69 32.56,81.95
+Oman; 51.53,16.19 60.52,26.73
+Pakistan; 60.18,22.94 78.66,37.86
+Panama; -83.06,6.9 -76.63,9.95
+Papua New Guinea; 140.37,-11.3 153.05,-2.2
+Paraguay; -62.83,-27.85 -53.6,-18.87
+Peru; -82.13,-19.35 -67.52,0.79
+Philippines; 116.68,4.85 127.23,19.22
+Poland; 13.77,48.57 24.85,55.24
+Portugal; -9.6,36.75 -5.65,42.36
+Qatar; 50.97,24.33 51.89,26.17
+Romania; 20.05,43.29 30.38,48.76
+Russia; 25,23.21 180,71
+Rwanda; 28.9,-3.01 31.2,-1.03
+Saudi Arabia; 33.9,14.01 57.3,33.22
+Senegal; -17.53,12.02 -10.89,17.14
+Serbia; 18.8,41.66 23.35,46.39
+Sierra Leone; -13.16,6.71 -10.02,10.09
+Slovakia; 16.84,47.61 23.06,49.93
+Slovenia; 13.39,45.28 16.87,47.06
+Somalia; 40.53,-2.55 52.14,12.66
+South Africa; 13.68,-35.9 33.98,-21.27
+South America; -84.9,-57.6 -32.4,13.7
+South Atlantic Ocean; -67,-55.4 23,0
+Southern Ocean; -180,-77 180,-32
+Southern Temperate; -180,-60 180,-23
+Spain; -9.69,35.4 3.98,44.38
+Sri Lanka; 79.69,5.76 82.26,9.89
+Sudan; 21.06,2.6 39.77,22.86
+Suriname; -58.01,1.53 -53.42,6.23
+Swaziland; 30.93,-27.52 32.45,-25.72
+Sweden; 10.56,54.63 24.84,69.68
+Switzerland; 5.92,45.66 10.84,48.02
+Syria; 35.36,31.84 43.11,37.69
+Taiwan; 119.99,21.78 122.14,25.31
+Tajikistan; 67.34,36.34 75.59,41.46
+Tanzania United Republic of; 0,-0.54 28.96,41.23
+Thailand; 96.83,4.8 106.42,21.22
+Togo; -0.09,5.85 2.21,11.33
+Trinidad; -61.88,10.01 -60.86,10.89
+Tropics; -180,-23 180,23
+Tunisia; 7.38,29.87 12.03,37.65
+Turkey; 25.29,34.91 45.94,43
+Turkmenistan; 52.05,34.56 67.66,43.46
+Uganda; 29.45,-1.82 35.52,4.32
+Ukraine; 21.4,43.61 41.24,53.31
+United Arab Emirates; 51.06,21.82 56.87,26.25
+United Kingdom; -8.41,49.49 2.39,59.07
+United States; -180,13.71 -61.48,76.63
+Uruguay; -58.46,-35.26 -52.77,-29.97
+Uzbekistan; 55.44,36.08 74.31,46.46
+Venezuela; -73.81,-0.11 -58.91,12.92
+Vietnam; 101.43,7.75 110.25,24.05
+Virginia; -84.1,36.12 -74.82,39.88
+Western Sahara; -17.23,20.87 -8.01,28
+Yemen; 42.45,12.12 53.74,19.51
+Zaire; 11.45,-14.4 32.4,6.28
+Zambia; 21.55,-18.7 34.45,-7.69
+Zimbabwe; 25.11,-22.93 33.65,15.22

Modified: grass/trunk/gui/wxpython/tools/update_menudata.py
===================================================================
--- grass/trunk/gui/wxpython/tools/update_menudata.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/tools/update_menudata.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -174,6 +174,6 @@
     sys.path.append(os.path.join(os.getenv("GISBASE"), 'etc', 'wxpython', 'gui_modules'))
     import menudata
     import menuform
-    import globalvar
+    from core import globalvar
     
     sys.exit(main())

Added: grass/trunk/gui/wxpython/vdigit/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,753 @@
+"""!
+ at package vdigit.dialogs
+
+ at brief wxGUI vector digitizer dialogs
+
+Classes:
+ - VDigitCategoryDialog
+ - CategoryListCtrl
+ - VDigitZBulkDialog
+ - VDigitDuplicatesDialog
+ - CheckListFeature
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import sys
+import copy
+
+import wx
+import wx.lib.mixins.listctrl as listmix
+
+from core.gcmd        import RunCommand, GError
+from core.debug       import Debug
+from core.settings    import UserSettings
+
+class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin):
+    def __init__(self, parent, title,
+                 vectorName, query = None, cats = None,
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+        """!Dialog used to display/modify categories of vector objects
+        
+        @param parent
+        @param title dialog title
+        @param query {coordinates, qdist} - used by v.edit/v.what
+        @param cats  directory of lines (layer/categories) - used by vdigit
+        @param style dialog style
+        """
+        self.parent = parent       # mapdisplay.BufferedWindow class instance
+        self.digit = parent.digit
+        
+        # map name
+        self.vectorName = vectorName
+        
+        # line : {layer: [categories]}
+        self.cats = {}
+        
+        # do not display dialog if no line is found (-> self.cats)
+        if cats is None:
+            if self._getCategories(query[0], query[1]) == 0 or not self.line:
+                Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
+        else:
+            self.cats = cats
+            for line in cats.keys():
+                for layer in cats[line].keys():
+                    self.cats[line][layer] = list(cats[line][layer])
+            
+            layers = []
+            for layer in self.digit.GetLayers():
+                layers.append(str(layer))
+        
+        # make copy of cats (used for 'reload')
+        self.cats_orig = copy.deepcopy(self.cats)
+        
+        wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title,
+                           style = style, **kwargs)
+        
+        # list of categories
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("List of categories - right-click to delete"))
+        listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY,
+                                     style = wx.LC_REPORT |
+                                     wx.BORDER_NONE |
+                                     wx.LC_SORT_ASCENDING |
+                                     wx.LC_HRULES |
+                                     wx.LC_VRULES)
+        # sorter
+        self.fid = self.cats.keys()[0]
+        self.itemDataMap = self.list.Populate(self.cats[self.fid])
+        listmix.ColumnSorterMixin.__init__(self, 2)
+        self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
+                                  size = (150, -1))
+        self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
+        self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
+        if len(self.cats.keys()) == 1:
+            self.fidMulti.Show(False)
+            self.fidText.SetLabel(str(self.fid))
+        else:
+            self.fidText.Show(False)
+            choices = []
+            for fid in self.cats.keys():
+                choices.append(str(fid))
+            self.fidMulti.SetItems(choices)
+            self.fidMulti.SetSelection(0)
+        
+        listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND)
+
+        # add new category
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Add new category"))
+        addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(3)
+
+        layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                 label = "%s:" % _("Layer"))
+        self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1),
+                                  choices = layers)
+        if len(layers) > 0:
+            self.layerNew.SetSelection(0)
+        
+        catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
+                               label = "%s:" % _("Category"))
+
+        try:
+            newCat = max(self.cats[self.fid][1]) + 1
+        except KeyError:
+            newCat = 1
+        self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1),
+                                  initial = newCat, min = 0, max = 1e9)
+        btnAddCat = wx.Button(self, wx.ID_ADD)
+        flexSizer.Add(item = layerNewTxt, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = self.layerNew, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = catNewTxt, proportion = 0,
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
+                      border = 10)
+        flexSizer.Add(item = self.catNew, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = btnAddCat, proportion = 0,
+                      flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+        addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        # buttons
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnApply.SetToolTipString(_("Apply changes"))
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnCancel.SetToolTipString(_("Ignore changes and close dialog"))
+        btnOk = wx.Button(self, wx.ID_OK)
+        btnOk.SetToolTipString(_("Apply changes and close dialog"))
+        btnOk.SetDefault()
+
+        # sizers
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        #btnSizer.AddButton(btnReload)
+        #btnSizer.SetNegativeButton(btnReload)
+        btnSizer.AddButton(btnApply)
+        btnSizer.AddButton(btnOk)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = listSizer, proportion = 1,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        mainSizer.Add(item = addSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALIGN_CENTER |
+                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+        fidSizer = wx.BoxSizer(wx.HORIZONTAL)
+        fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+                                        label = _("Feature id:")),
+                     proportion = 0, border = 5,
+                     flag = wx.ALIGN_CENTER_VERTICAL)
+        fidSizer.Add(item = self.fidMulti, proportion = 0,
+                     flag = wx.EXPAND | wx.ALL,  border = 5)
+        fidSizer.Add(item = self.fidText, proportion = 0,
+                     flag = wx.EXPAND | wx.ALL,  border = 5)
+        mainSizer.Add(item = fidSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        self.SetAutoLayout(True)
+
+        # set min size for dialog
+        self.SetMinSize(self.GetBestSize())
+
+        # bindings
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
+        btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat)
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+                                     
+        # list
+        self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
+        self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
+        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
+        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
+        self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
+
+    def GetListCtrl(self):
+        """!Used by ColumnSorterMixin
+        """
+        return self.list
+
+    def OnColClick(self, event):
+        """!Click on column header (order by)
+        """
+        event.Skip()
+        
+    def OnBeginEdit(self, event):
+        """!Editing of item started
+        """
+        event.Allow()
+
+    def OnEndEdit(self, event):
+        """!Finish editing of item
+        """
+        itemIndex = event.GetIndex()
+        layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
+        catOld = int (self.list.GetItem(itemIndex, 1).GetText())
+
+        if event.GetColumn() == 0:
+            layerNew = int(event.GetLabel())
+            catNew = catOld
+        else:
+            layerNew = layerOld
+            catNew = int(event.GetLabel())
+        
+        try:
+            if layerNew not in self.cats[self.fid].keys():
+                self.cats[self.fid][layerNew] = []
+            self.cats[self.fid][layerNew].append(catNew)
+            self.cats[self.fid][layerOld].remove(catOld)
+        except:
+            event.Veto()
+            self.list.SetStringItem(itemIndex, 0, str(layerNew))
+            self.list.SetStringItem(itemIndex, 1, str(catNew))
+            dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
+                                           "Layer and category number must be integer.\n"
+                                           "Layer number must be greater then zero.") %
+                                   { 'layer': self.layerNew.GetStringSelection(),
+                                     'category' : str(self.catNew.GetValue()) },
+                                   _("Error"), wx.OK | wx.ICON_ERROR)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return False
+
+    def OnRightDown(self, event):
+        """!Mouse right button down
+        """
+        x = event.GetX()
+        y = event.GetY()
+        item, flags = self.list.HitTest((x, y))
+
+        if item !=  wx.NOT_FOUND and \
+                flags & wx.LIST_HITTEST_ONITEM:
+            self.list.Select(item)
+
+        event.Skip()
+
+    def OnRightUp(self, event):
+        """!Mouse right button up
+        """
+        if not hasattr(self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.popupID3 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnItemDelete,    id = self.popupID1)
+            self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2)
+            self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
+
+        # generate popup-menu
+        menu = wx.Menu()
+        menu.Append(self.popupID1, _("Delete selected"))
+        if self.list.GetFirstSelected() == -1:
+            menu.Enable(self.popupID1, False)
+
+        menu.Append(self.popupID2, _("Delete all"))
+        menu.AppendSeparator()
+        menu.Append(self.popupID3, _("Reload"))
+
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def OnItemSelected(self, event):
+        """!Item selected
+        """
+        event.Skip()
+
+    def OnItemDelete(self, event):
+        """!Delete selected item(s) from the list (layer/category pair)
+        """
+        item = self.list.GetFirstSelected()
+        while item != -1:
+            layer = int (self.list.GetItem(item, 0).GetText())
+            cat = int (self.list.GetItem(item, 1).GetText())
+            self.list.DeleteItem(item)
+            self.cats[self.fid][layer].remove(cat)
+
+            item = self.list.GetFirstSelected()
+            
+        event.Skip()
+        
+    def OnItemDeleteAll(self, event):
+        """!Delete all items from the list
+        """
+        self.list.DeleteAllItems()
+        self.cats[self.fid] = {}
+
+        event.Skip()
+
+    def OnFeature(self, event):
+        """!Feature id changed (on duplicates)
+        """
+        self.fid = int(event.GetString())
+        
+        self.itemDataMap = self.list.Populate(self.cats[self.fid],
+                                              update = True)
+
+        try:
+            newCat = max(self.cats[self.fid][1]) + 1
+        except KeyError:
+            newCat = 1
+            
+        self.catNew.SetValue(newCat)
+        
+        event.Skip()
+        
+    def _getCategories(self, coords, qdist):
+        """!Get layer/category pairs for all available
+        layers
+
+        Return True line found or False if not found
+        """
+        ret = RunCommand('v.what',
+                         parent = self,
+                         quiet = True,
+                         map = self.vectorName,
+                         east_north = '%f,%f' % \
+                             (float(coords[0]), float(coords[1])),
+                         distance = qdist)
+
+        if not ret:
+            return False
+
+        for item in ret.splitlines():
+            litem = item.lower()
+            if "id:" in litem: # get line id
+                self.line = int(item.split(':')[1].strip())
+            elif "layer:" in litem: # add layer
+                layer = int(item.split(':')[1].strip())
+                if layer not in self.cats.keys():
+                    self.cats[layer] = []
+            elif "category:" in litem: # add category
+                self.cats[layer].append(int(item.split(':')[1].strip()))
+
+        return True
+
+    def OnReload(self, event):
+        """!Reload button pressed
+        """
+        # restore original list
+        self.cats = copy.deepcopy(self.cats_orig)
+
+        # polulate list
+        self.itemDataMap = self.list.Populate(self.cats[self.fid],
+                                              update = True)
+
+        event.Skip()
+
+    def OnCancel(self, event):
+        """!Cancel button pressed
+        """
+        self.parent.parent.dialogs['category'] = None
+        if self.digit:
+            self.digit.GetDisplay().SetSelected([])
+            self.parent.UpdateMap(render = False)
+        else:
+            self.parent.parent.OnRender(None)
+            
+        self.Close()
+
+    def OnApply(self, event):
+        """!Apply button pressed
+        """
+        for fid in self.cats.keys():
+            newfid = self.ApplyChanges(fid)
+            if fid == self.fid and newfid > 0:
+                self.fid = newfid
+            
+    def ApplyChanges(self, fid):
+        """!Apply changes 
+
+        @param fid feature id
+        """
+        cats = self.cats[fid]
+        cats_orig = self.cats_orig[fid]
+
+        # action : (catsFrom, catsTo)
+        check = {'catadd': (cats,      cats_orig),
+                 'catdel': (cats_orig, cats)}
+
+        newfid = -1
+        
+        # add/delete new category
+        for action, catsCurr in check.iteritems():
+            for layer in catsCurr[0].keys():
+                catList = []
+                for cat in catsCurr[0][layer]:
+                    if layer not in catsCurr[1].keys() or \
+                            cat not in catsCurr[1][layer]:
+                        catList.append(cat)
+                if catList != []:
+                    if action == 'catadd':
+                        add = True
+                    else:
+                        add = False
+                        
+                    newfid = self.digit.SetLineCats(fid, layer,
+                                                    catList, add)
+                    if len(self.cats.keys()) == 1:
+                        self.fidText.SetLabel("%d" % newfid)
+                    else:
+                        choices = self.fidMulti.GetItems()
+                        choices[choices.index(str(fid))] = str(newfid)
+                        self.fidMulti.SetItems(choices)
+                        self.fidMulti.SetStringSelection(str(newfid))
+                    
+                    self.cats[newfid] = self.cats[fid]
+                    del self.cats[fid]
+                    
+                    fid = newfid
+                    if self.fid < 0:
+                        wx.MessageBox(parent = self, message = _("Unable to update vector map."),
+                                      caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
+        
+        self.cats_orig[fid] = copy.deepcopy(cats)
+        
+        return newfid
+
+    def OnOK(self, event):
+        """!OK button pressed
+        """
+        self.OnApply(event)
+        self.OnCancel(event)
+
+    def OnAddCat(self, event):
+        """!Button 'Add' new category pressed
+        """
+        try:
+            layer = int(self.layerNew.GetStringSelection())
+            cat   = int(self.catNew.GetValue())
+            if layer <= 0:
+                raise ValueError
+        except ValueError:
+            GError(parent = self,
+                   message = _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
+                               "Layer and category number must be integer.\n"
+                               "Layer number must be greater then zero.") %
+                   {'layer' : str(self.layerNew.GetValue()),
+                    'category' : str(self.catNew.GetValue())})
+            return False
+        
+        if layer not in self.cats[self.fid].keys():
+            self.cats[self.fid][layer] = []
+        
+        self.cats[self.fid][layer].append(cat)
+        
+        # reload list
+        self.itemDataMap = self.list.Populate(self.cats[self.fid],
+                                              update = True)
+        
+        # update category number for add
+        self.catNew.SetValue(cat + 1)
+        
+        event.Skip()
+
+        return True
+
+    def GetLine(self):
+        """!Get id of selected line of 'None' if no line is selected
+        """
+        return self.cats.keys()
+
+    def UpdateDialog(self, query = None, cats = None):
+        """!Update dialog
+        
+        @param query {coordinates, distance} - v.what
+        @param cats  directory layer/cats    - vdigit
+        Return True if updated otherwise False
+        """
+        # line: {layer: [categories]}
+        self.cats = {}
+        # do not display dialog if no line is found (-> self.cats)
+        if cats is None:
+            ret = self._getCategories(query[0], query[1])
+        else:
+            self.cats = cats
+            for line in cats.keys():
+                for layer in cats[line].keys():
+                    self.cats[line][layer] = list(cats[line][layer])
+            ret = 1
+        if ret == 0 or len(self.cats.keys()) < 1:
+            Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
+            return False
+        
+        # make copy of cats (used for 'reload')
+        self.cats_orig = copy.deepcopy(self.cats)
+
+        # polulate list
+        self.fid = self.cats.keys()[0]
+        self.itemDataMap = self.list.Populate(self.cats[self.fid],
+                                              update = True)
+
+        try:
+            newCat = max(self.cats[self.fid][1]) + 1
+        except KeyError:
+            newCat = 1
+        self.catNew.SetValue(newCat)
+        
+        if len(self.cats.keys()) == 1:
+            self.fidText.Show(True)
+            self.fidMulti.Show(False)
+            self.fidText.SetLabel("%d" % self.fid)
+        else:
+            self.fidText.Show(False)
+            self.fidMulti.Show(True)
+            choices = []
+            for fid in self.cats.keys():
+                choices.append(str(fid))
+            self.fidMulti.SetItems(choices)
+            self.fidMulti.SetSelection(0)
+
+        self.Layout()
+        
+        return True
+
+class CategoryListCtrl(wx.ListCtrl,
+                       listmix.ListCtrlAutoWidthMixin,
+                       listmix.TextEditMixin):
+    def __init__(self, parent, id, pos = wx.DefaultPosition,
+                 size = wx.DefaultSize, style = 0):
+        """!List of layers/categories"""
+        self.parent = parent
+        
+        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
+
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+        listmix.TextEditMixin.__init__(self)
+
+    def Populate(self, cats, update = False):
+        """!Populate the list
+        """
+        itemData = {} # requested by sorter
+
+        if not update:
+            self.InsertColumn(0, _("Layer"))
+            self.InsertColumn(1, _("Category"))
+        else:
+            self.DeleteAllItems()
+
+        i = 1
+        for layer in cats.keys():
+            catsList = cats[layer]
+            for cat in catsList:
+                index = self.InsertStringItem(sys.maxint, str(catsList[0]))
+                self.SetStringItem(index, 0, str(layer))
+                self.SetStringItem(index, 1, str(cat))
+                self.SetItemData(index, i)
+                itemData[i] = (str(layer), str(cat))
+                i = i + 1
+
+        if not update:
+            self.SetColumnWidth(0, 100)
+            self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
+
+        self.currentItem = 0
+
+        return itemData
+
+class VDigitZBulkDialog(wx.Dialog):
+    def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
+        """!Dialog used for Z bulk-labeling tool
+        """
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
+
+        self.parent = parent # mapdisplay.BufferedWindow class instance
+
+        # panel  = wx.Panel(parent=self, id=wx.ID_ANY)
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        txt = wx.StaticText(parent = self,
+                            label = _("%d lines selected for z bulk-labeling") % nselected);
+        border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        box   = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+
+        # starting value
+        txt = wx.StaticText(parent = self,
+                            label = _("Starting value"));
+        self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
+                                 initial = 0,
+                                 min = -1e6, max = 1e6)
+        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+
+        # step
+        txt = wx.StaticText(parent = self,
+                            label = _("Step"))
+        self.step  = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
+                                 initial = 0,
+                                 min = 0, max = 1e6)
+        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
+
+        # buttons
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnOk = wx.Button(self, wx.ID_OK)
+        btnOk.SetDefault()
+
+        # sizers
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        btnSizer.AddButton(btnOk)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+class VDigitDuplicatesDialog(wx.Dialog):
+    def __init__(self, parent, data, title = _("List of duplicates"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+                 pos = wx.DefaultPosition):
+        """!Show duplicated feature ids
+        """
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
+                           pos = pos)
+        
+        self.parent = parent # BufferedWindow
+        self.data = data
+        self.winList = []
+
+        # panel  = wx.Panel(parent=self, id=wx.ID_ANY)
+
+        # notebook
+        self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+
+        id = 1
+        for key in self.data.keys():
+            panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY)
+            self.notebook.AddPage(page = panel, text = " %d " % (id))
+            
+            # notebook body
+            border = wx.BoxSizer(wx.VERTICAL)
+
+            win = CheckListFeature(parent = panel, data = list(self.data[key]))
+            self.winList.append(win.GetId())
+
+            border.Add(item = win, proportion = 1,
+                       flag = wx.ALL | wx.EXPAND, border = 5)
+
+            panel.SetSizer(border)
+
+            id += 1
+
+        # buttons
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnOk = wx.Button(self, wx.ID_OK)
+        btnOk.SetDefault()
+
+        # sizers
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        btnSizer.AddButton(btnOk)
+        btnSizer.Realize()
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+        mainSizer.Add(item = btnSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+        self.SetAutoLayout(True)
+
+        # set min size for dialog
+        self.SetMinSize((250, 180))
+
+    def GetUnSelected(self):
+        """!Get unselected items (feature id)
+
+        @return list of ids
+        """
+        ids = []
+        for id in self.winList:
+            wlist = self.FindWindowById(id)
+
+            for item in range(wlist.GetItemCount()):
+                if not wlist.IsChecked(item):
+                    ids.append(int(wlist.GetItem(item, 0).GetText()))
+                    
+        return ids
+
+class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
+    def __init__(self, parent, data,
+                 pos = wx.DefaultPosition, log = None):
+        """!List of mapset/owner/group
+        """
+        self.parent = parent
+        self.data = data
+
+        wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
+                             style = wx.LC_REPORT)
+
+        listmix.CheckListCtrlMixin.__init__(self)
+
+        self.log = log
+
+        # setup mixins
+        listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+        self.LoadData(self.data)
+
+    def LoadData(self, data):
+        """!Load data into list
+        """
+        self.InsertColumn(0, _('Feature id'))
+        self.InsertColumn(1, _('Layer (Categories)'))
+
+        for item in data:
+            index = self.InsertStringItem(sys.maxint, str(item[0]))
+            self.SetStringItem(index, 1, str(item[1]))
+
+        # enable all items by default
+        for item in range(self.GetItemCount()):
+            self.CheckItem(item, True)
+
+        self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
+        self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
+                
+    def OnCheckItem(self, index, flag):
+        """!Mapset checked/unchecked
+        """
+        pass


Property changes on: grass/trunk/gui/wxpython/vdigit/dialogs.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/vdigit/main.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/main.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/main.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,34 @@
+"""!
+ at package vdigit.main
+
+ at brief wxGUI vector digitizer
+
+Classes:
+ - VDigit
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+try:
+    from vdigit.wxdigit import IVDigit, GV_LINES
+    haveVDigit = True
+    errorMsg   = ''
+except ImportError, err:
+    haveVDigit = False
+    errorMsg   = err
+    GV_LINES   = -1
+    class IVDigit:
+        def __init__(self):
+            pass
+
+class VDigit(IVDigit):
+    def __init__(self, mapwindow):
+        """!Base class of vector digitizer
+        
+        @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance
+        """
+        IVDigit.__init__(self, mapwindow)


Property changes on: grass/trunk/gui/wxpython/vdigit/main.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/vdigit/mapwindow.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/mapdisp_vdigit.py)
===================================================================
--- grass/trunk/gui/wxpython/vdigit/mapwindow.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/mapwindow.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1075 @@
+"""!
+ at package vdigit.mapwindow
+
+ at brief Map display canvas for wxGUI vector digitizer
+
+Classes:
+ - VDigitWindow
+
+(C) 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import wx
+
+from dbm.dialogs    import DisplayAttributesDialog
+from core.gcmd      import RunCommand, GMessage, GError
+from core.debug     import Debug
+from mapdisp.window import BufferedWindow
+from core.settings  import UserSettings
+from core.utils     import ListOfCatsToRange
+from core.globalvar import QUERYLAYER
+from vdigit.dialogs import VDigitCategoryDialog, DigitZBulkDialog, VDigitDuplicatesDialog
+
+class VDigitWindow(BufferedWindow):
+    """!A Buffered window extended for vector digitizer.
+    """
+    def __init__(self, parent, id = wx.ID_ANY,
+                 Map = None, tree = None, lmgr = None,
+                 style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
+        BufferedWindow.__init__(self, parent, id, Map, tree, lmgr,
+                                style, **kwargs)
+        
+        self.pdcVector = wx.PseudoDC()
+        self.toolbar   = self.parent.GetToolbar('vdigit')
+        self.digit     = None # wxvdigit.IVDigit
+        
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        
+    def SetToolbar(self, toolbar):
+        """!Set up related toolbar
+        """
+        self.toolbar = toolbar
+        
+    def _onMotion(self, coord, precision):
+        """!Track mouse motion and update statusbar (see self.Motion)
+
+        @parem coord easting, northing
+        @param precision formatting precision
+        """
+        e, n = coord
+        
+        if self.toolbar.GetAction() != 'addLine' or \
+                self.toolbar.GetAction('type') not in ('line', 'boundary') or \
+                len(self.polycoords) == 0:
+            return False
+        
+        # for linear feature show segment and total length
+        distance_seg = self.Distance(self.polycoords[-1],
+                                     (e, n), screen = False)[0]
+        distance_tot = distance_seg
+        for idx in range(1, len(self.polycoords)):
+            distance_tot += self.Distance(self.polycoords[idx-1],
+                                          self.polycoords[idx],
+                                          screen = False)[0]
+        self.parent.SetStatusText("%.*f, %.*f (seg: %.*f; tot: %.*f)" % \
+                                                (precision, e, precision, n,
+                                                 precision, distance_seg,
+                                                 precision, distance_tot), 0)
+        
+        return True
+    
+    def OnKeyDown(self, event):
+        """!Key pressed"""
+        shift = event.ShiftDown()
+        kc = event.GetKeyCode()
+        
+        event = None
+        if not shift:
+            if kc == ord('P'):
+                event = wx.CommandEvent(winid = self.toolbar.addPoint)
+                tool = self.toolbar.OnAddPoint
+            elif kc == ord('L'):
+                event = wx.CommandEvent(winid = self.toolbar.addLine)
+                tool = self.toolbar.OnAddLine
+        if event:
+            self.toolbar.OnTool(event)
+            tool(event)
+        
+    def _updateMap(self):
+        if not self.toolbar or \
+                not self.toolbar.GetLayer():
+            return
+        
+        # set region
+        self.digit.GetDisplay().UpdateRegion()
+        # re-calculate threshold for digitization tool
+        # self.parent.digit.GetDisplay().GetThreshold()
+        # draw map
+        # self.pdcVector.Clear()
+        self.pdcVector.RemoveAll()
+        
+        item = None
+        if self.tree:
+            try:
+                item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer())
+            except TypeError:
+                pass
+        
+        if not self.tree or \
+                (self.tree and item and \
+                     self.tree.IsItemChecked(item)):
+            self.redrawAll = True
+            self.digit.GetDisplay().DrawMap()
+        
+        # translate tmp objects (pointer position)
+        if self.toolbar.GetAction() == 'moveLine' and \
+                hasattr(self, "moveInfo"):
+            if 'beginDiff' in self.moveInfo:
+                # move line
+                for id in self.moveInfo['id']:
+                    self.pdcTmp.TranslateId(id,
+                                            self.moveInfo['beginDiff'][0],
+                                            self.moveInfo['beginDiff'][1])
+                del self.moveInfo['beginDiff']
+        
+    def OnLeftDownAddLine(self, event):
+        """!Left mouse button pressed - add new feature
+        """
+        try:
+            mapLayer = self.toolbar.GetLayer().GetName()
+        except:
+            return
+        
+        if self.toolbar.GetAction('type') in ['point', 'centroid']:
+            # add new point / centroiud
+            east, north = self.Pixel2Cell(self.mouse['begin'])
+            nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), [(east, north)])
+            if nfeat < 1:
+                return
+            
+            self.UpdateMap(render = False) # redraw map
+            
+            # add new record into atribute table
+            if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'):
+                # select attributes based on layer and category
+                cats = { fids[0] : {
+                        UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
+                            (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
+                        }}
+                
+                posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
+                                                 self.mouse['end'][1] + self.dialogOffset))
+                
+                addRecordDlg = DisplayAttributesDialog(parent = self, map = mapLayer,
+                                                       cats = cats,
+                                                       pos = posWindow,
+                                                       action = "add", ignoreError = True)
+                
+                if self.toolbar.GetAction('type') == 'centroid':
+                    for fid in fids:
+                        self._geomAttrb(fid, addRecordDlg, 'area')
+                        self._geomAttrb(fid, addRecordDlg, 'perimeter')
+                
+                if addRecordDlg.IsFound() and \
+                        addRecordDlg.ShowModal() == wx.ID_OK:
+                    sqlfile = tempfile.NamedTemporaryFile(mode = "w")
+                    for sql in addRecordDlg.GetSQLString():
+                        sqlfile.file.write(sql + ";\n")
+                    sqlfile.file.flush()
+                    
+                    RunCommand('db.execute',
+                               parent = self,
+                               quiet = True, 
+                               input = sqlfile.name)
+                
+                if addRecordDlg.mapDBInfo:
+                    self._updateATM()
+        
+        elif self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
+            # add new point to the line
+            self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
+            self.DrawLines(pdc = self.pdcTmp)
+        
+    def _geomAttrb(self, fid, dialog, attrb):
+        """!Define geometry attributes
+        """
+        mapLayer = self.toolbar.GetLayer()
+        if self.tree:
+            item = self.tree.FindItemByData('maplayer', mapLayer)
+            vdigit = self.tree.GetPyData(item)[0]['vdigit']
+        else:
+            item = vdigit = None
+        
+        if not vdigit or \
+                'geomAttr' not in vdigit or \
+                attrb not in vdigit['geomAttr']:
+            return
+        
+        val = -1
+        if attrb == 'length':
+            val = self.digit.GetLineLength(fid)
+            type = attrb
+        elif attrb == 'area':
+            val = self.digit.GetAreaSize(fid)
+            type = attrb
+        elif attrb == 'perimeter':
+            val = self.digit.GetAreaPerimeter(fid)
+            type = 'length'
+        
+        if val > 0:
+            layer = int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value'))
+            column = vdigit['geomAttr'][attrb]['column']
+            val = UnitsConvertValue(val, type, vdigit['geomAttr'][attrb]['units'])
+            dialog.SetColumnValue(layer, column, val)
+            dialog.OnReset()
+        
+    def _geomAttrbUpdate(self, fids):
+        """!Update geometry atrributes of currently selected features
+        
+        @param fid list feature id
+        """
+        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
+        vectorName =  mapLayer.GetName()
+        if self.tree:
+            item = self.tree.FindItemByData('maplayer', mapLayer)
+            vdigit = self.tree.GetPyData(item)[0]['vdigit']
+        else:
+            item = vdigit = None
+        
+        if not vdigit or 'geomAttr' not in vdigit:
+            return
+        
+        dbInfo = gselect.VectorDBInfo(vectorName)
+        sqlfile = tempfile.NamedTemporaryFile(mode = "w")
+        for fid in fids:
+            for layer, cats in self.digit.GetLineCats(fid).iteritems():
+                table = dbInfo.GetTable(layer)
+                for attrb, item in vdigit['geomAttr'].iteritems():
+                    val = -1
+                    if attrb == 'length':
+                        val = self.digit.GetLineLength(fid)
+                        type = attrb
+                    elif attrb == 'area':
+                        val = self.digit.GetAreaSize(fid)
+                        type = attrb
+                    elif attrb == 'perimeter':
+                        val = self.digit.GetAreaPerimeter(fid)
+                        type = 'length'
+                    
+                    if val < 0:
+                        continue
+                    val = UnitsConvertValue(val, type, item['units'])
+                    
+                    for cat in cats:
+                        sqlfile.write('UPDATE %s SET %s = %f WHERE %s = %d;\n' % \
+                                          (table, item['column'], val,
+                                           dbInfo.GetKeyColumn(layer), cat))
+            
+            sqlfile.file.flush()
+            RunCommand('db.execute',
+                       parent = True,
+                       quiet = True,
+                       input = sqlfile.name)
+            
+    def _updateATM(self):
+        """!Update open Attribute Table Manager
+        
+        @todo: use AddDataRow() instead
+        """
+        # update ATM
+        digitVector = self.toolbar.GetLayer().GetName()
+                            
+        for atm in self.lmgr.dialogs['atm']:
+            atmVector = atm.GetVectorName()
+            if atmVector == digitVector:
+                layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
+                # TODO: use AddDataRow instead
+                atm.LoadData(layer)
+        
+    def OnLeftDownEditLine(self, event):
+        """!Left mouse button pressed - edit linear feature - add new
+        vertex.
+        """
+        self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
+        self.moveInfo['id'].append(wx.NewId())
+        self.DrawLines(pdc = self.pdcTmp)
+        
+    def OnLeftDownMoveLine(self, event):
+        """!Left mouse button pressed - vector digitizer move
+        feature/vertex, edit linear feature
+        """
+        self.moveInfo = dict()
+        # geographic coordinates of initial position (left-down)
+        self.moveInfo['begin'] = None
+        # list of ids to modify    
+        self.moveInfo['id'] = list()
+        
+        # set pen
+        if self.toolbar.GetAction() in ["moveVertex", "editLine"]:
+            pcolor = UserSettings.Get(group = 'vdigit', key = "symbol",
+                                      subkey = ["highlight", "color"])
+            self.pen = self.polypen = wx.Pen(colour = pcolor,
+                                             width = 2, style = wx.SHORT_DASH)
+            self.pdcTmp.SetPen(self.polypen)
+        
+    def OnLeftDownDisplayCA(self, event):
+        """!Left mouse button pressed - vector digitizer display categories
+        or attributes action
+        """
+        try:
+            mapLayer = self.toolbar.GetLayer().GetName()
+        except:
+            return
+        
+        coords = self.Pixel2Cell(self.mouse['begin'])
+        
+        # unselect
+        self.digit.GetDisplay().SetSelected([])
+        
+        # select feature by point
+        cats = {}
+        self.digit.GetDisplay().SelectLineByPoint(coords) 
+        
+        if not self.digit.GetDisplay().GetSelected():
+            for key in ('attributes', 'category'):
+                if self.parent.dialogs[key] and \
+                        self.parent.dialogs[key].IsShown():
+                    self.parent.dialogs[key].Hide()
+            self.UpdateMap(render = False, renderVector = True)
+            return
+        
+        if UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
+                            subkey = 'enabled'):
+            lines = self.digit.GetDisplay().GetSelected()
+        else:
+            lines = (self.digit.GetDisplay().GetSelected()[0],) # only first found
+                        
+        for line in lines:
+            cats[line] = self.digit.GetLineCats(line)
+        
+        posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
+                                         self.mouse['end'][1] + self.dialogOffset))
+        
+        if self.toolbar.GetAction() == "displayAttrs":
+            # select attributes based on coordinates (all layers)
+            if self.parent.dialogs['attributes'] is None:
+                self.parent.dialogs['attributes'] = \
+                    DisplayAttributesDialog(parent = self, map = mapLayer,
+                                            cats = cats,
+                                            action = "update")
+            else:
+                # upgrade dialog
+                self.parent.dialogs['attributes'].UpdateDialog(cats = cats)
+           
+            if self.parent.dialogs['attributes'] and \
+                    self.parent.dialogs['attributes'].mapDBInfo:
+                if len(cats.keys()) > 0:
+                    # highlight feature & re-draw map
+                    if not self.parent.dialogs['attributes'].IsShown():
+                        self.parent.dialogs['attributes'].Show()
+                else:
+                    if self.parent.dialogs['attributes'] and \
+                            self.parent.dialogs['attributes'].IsShown():
+                        self.parent.dialogs['attributes'].Hide()
+        
+        else: # displayCats
+            if self.parent.dialogs['category'] is None:
+                # open new dialog
+                dlg = VDigitCategoryDialog(parent = self,
+                                           vectorName = mapLayer,
+                                           cats = cats,
+                                           pos = posWindow,
+                                           title = _("Update categories"))
+                self.parent.dialogs['category'] = dlg
+            else:
+                # update currently open dialog
+                self.parent.dialogs['category'].UpdateDialog(cats = cats)
+                
+            if self.parent.dialogs['category']:
+                if len(cats.keys()) > 0:
+                    # highlight feature & re-draw map
+                    if not self.parent.dialogs['category'].IsShown():
+                        self.parent.dialogs['category'].Show()
+                else:
+                    if self.parent.dialogs['category'].IsShown():
+                        self.parent.dialogs['category'].Hide()
+        
+        self.UpdateMap(render = False, renderVector = True)
+        
+    def OnLeftDownCopyCA(self, event):
+        """!Left mouse button pressed - vector digitizer copy
+        categories or attributes action
+        """
+        if not hasattr(self, "copyCatsList"):
+            self.copyCatsList = []
+        else:
+            self.copyCatsIds = []
+            self.mouse['box'] = 'box'
+        
+    def OnLeftDownCopyLine(self, event):
+        """!Left mouse button pressed - vector digitizer copy lines
+        action
+        """
+        if not hasattr(self, "copyIds"):
+            self.copyIds = []
+            self.layerTmp = None
+        
+    def OnLeftDownBulkLine(self, event):
+        """!Left mouse button pressed - vector digitizer label 3D
+        vector lines
+        """
+        if len(self.polycoords) > 1: # start new line
+            self.polycoords = []
+            self.ClearLines(pdc = self.pdcTmp)
+        self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
+        if len(self.polycoords) == 1:
+            begin = self.Pixel2Cell(self.polycoords[-1])
+            end   = self.Pixel2Cell(self.mouse['end'])
+        else:
+            end   = self.Pixel2Cell(self.polycoords[-1])
+            begin = self.Pixel2Cell(self.mouse['begin'])
+            
+            self.DrawLines(self.pdcTmp, polycoords = (begin, end))
+        
+    def OnLeftDownUndo(self, event):
+        """!Left mouse button pressed with control key - vector
+        digitizer undo functionality
+        """
+        if self.mouse["use"] != "pointer" or not self.toolbar:
+            return
+        
+        action = self.toolbar.GetAction()
+        if (action == "addLine" and \
+                self.toolbar.GetAction('type') in ["line", "boundary", "area"]) or \
+                action == "editLine":
+            # add line or boundary -> remove last point from the line
+            try:
+                removed = self.polycoords.pop()
+                Debug.msg(4, "BufferedWindow.OnMiddleDown(): polycoords_poped=%s" % \
+                              [removed,])
+                # self.mouse['begin'] = self.Cell2Pixel(self.polycoords[-1])
+            except:
+                pass
+            
+        if action == "editLine":
+            # remove last vertex & line
+            if len(self.moveInfo['id']) > 1:
+                self.moveInfo['id'].pop()
+                
+            self.UpdateMap(render = False, renderVector = False)
+            
+        elif action in ["deleteLine", "moveLine", "splitLine",
+                        "addVertex", "removeVertex", "moveVertex",
+                        "copyCats", "flipLine", "mergeLine",
+                        "snapLine", "connectLine", "copyLine",
+                        "queryLine", "breakLine", "typeConv"]:
+            # varios tools -> unselected selected features
+            self.digit.GetDisplay().SetSelected([])
+            if action in ["moveLine", "moveVertex", "editLine"] and \
+                    hasattr(self, "moveInfo"):
+                del self.moveInfo
+                
+            elif action == "copyCats":
+                try:
+                    del self.copyCatsList
+                    del self.copyCatsIds
+                except AttributeError:
+                    pass
+                
+            elif action == "copyLine":
+                del self.copyIds
+                if self.layerTmp:
+                    self.Map.DeleteLayer(self.layerTmp)
+                    self.UpdateMap(render = True, renderVector = False)
+                del self.layerTmp
+
+            self.polycoords = []
+            self.UpdateMap(render = False) # render vector
+        
+        elif action == "zbulkLine":
+            # reset polyline
+            self.polycoords = []
+            self.digit.GetDisplay().SetSelected([])
+            self.UpdateMap(render = False)
+        
+        self.redrawAll = True
+        self.UpdateMap(render = False, renderVector = False)
+
+    def _onLeftDown(self, event):
+        """!Left mouse button donw - vector digitizer various actions
+        """
+        try:
+            mapLayer = self.toolbar.GetLayer().GetName()
+        except:
+            GMessage(parent = self,
+                     message = _("No vector map selected for editing."))
+            event.Skip()
+            return
+        
+        action = self.toolbar.GetAction()
+        if not action:
+            return
+        
+        if action not in ("moveVertex",
+                          "addVertex",
+                          "removeVertex",
+                          "editLine"):
+            # set pen
+            self.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
+            self.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SOLID)
+            
+        if action in ("addVertex",
+                      "removeVertex",
+                      "splitLines"):
+            # unselect
+            self.digit.GetDisplay().SetSelected([])
+        
+        if action == "addLine":
+            self.OnLeftDownAddLine(event)
+        
+        elif action == "editLine" and \
+                hasattr(self, "moveInfo"):
+            self.OnLeftDownEditLine(event)
+
+        elif action in ("moveLine", "moveVertex", "editLine") and \
+                not hasattr(self, "moveInfo"):
+            self.OnLeftDownMoveLine(event)
+        
+        elif action in ("displayAttrs"
+                        "displayCats"):
+            self.OnLeftDownDisplayCA(event)
+            
+        elif action in ("copyCats",
+                        "copyAttrs"):
+            self.OnLeftDownCopyCA(event)
+            
+        elif action == "copyLine":
+            self.OnLeftDownCopyLine(event)
+            
+        elif action == "zbulkLine":
+            self.OnLeftDownBulkLine(event)
+        
+    def OnLeftUpVarious(self, event):
+        """!Left mouse button released - vector digitizer various
+        actions
+        """
+        pos1 = self.Pixel2Cell(self.mouse['begin'])
+        pos2 = self.Pixel2Cell(self.mouse['end'])
+        
+        nselected = 0
+        action = self.toolbar.GetAction()
+        # -> delete line || move line || move vertex
+        if action in ("moveVertex",
+                      "editLine"):
+            if len(self.digit.GetDisplay().GetSelected()) == 0:
+                nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
+                
+                if action == "editLine":
+                    try:
+                        selVertex = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
+                    except IndexError:
+                        selVertex = None
+                        
+                    if selVertex:
+                        # self.UpdateMap(render=False)
+                        ids = self.digit.GetDisplay().GetSelected(grassId = False)
+                        # move this line to tmp layer
+                        self.polycoords = []
+                        for id in ids:
+                            if id % 2: # register only vertices
+                                e, n = self.Pixel2Cell(self.pdcVector.GetIdBounds(id)[0:2])
+                                self.polycoords.append((e, n))
+                        self.digit.GetDisplay().DrawSelected(False) 
+                                
+                        if selVertex < ids[-1] / 2:
+                            # choose first or last node of line
+                            self.moveInfo['id'].reverse()
+                            self.polycoords.reverse()
+                    else:
+                        # unselect
+                        self.digit.GetDisplay().SetSelected([])
+                        del self.moveInfo
+                
+                    self.UpdateMap(render = False)
+            
+        elif action in ("copyCats",
+                        "copyAttrs"):
+            if not hasattr(self, "copyCatsIds"):
+                # 'from' -> select by point
+                nselected = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
+                if nselected:
+                    self.copyCatsList = self.digit.GetDisplay().GetSelected()
+            else:
+                # -> 'to' -> select by bbox
+                self.digit.GetDisplay().SetSelected([])
+                # return number of selected features (by box/point)
+                nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
+                if nselected == 0:
+                    if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
+                        nselected = 1
+                        
+                if nselected > 0:
+                    self.copyCatsIds = self.digit.GetDisplay().GetSelected()
+        
+        elif action == "queryLine":
+            selected = self.digit.SelectLinesByQuery(bbox = (pos1, pos2))
+            nselected = len(selected)
+            if nselected > 0:
+                self.digit.GetDisplay().SetSelected(selected)
+        
+        else:
+            # -> moveLine || deleteLine, etc. (select by point/box)
+            if action == 'moveLine' and \
+                    len(self.digit.GetDisplay().GetSelected()) > 0:
+                nselected = 0
+            else:
+                if action == 'moveLine':
+                    drawSeg = True
+                else:
+                    drawSeg = False
+                
+                nselected = self.digit.GetDisplay().SelectLinesByBox(bbox = (pos1, pos2),
+                                                                     drawSeg = drawSeg)
+                if nselected == 0:
+                    if self.digit.GetDisplay().SelectLineByPoint(pos1) is not None:
+                        nselected = 1
+        
+        if nselected > 0:
+            if action in ("moveLine", "moveVertex") and \
+                    hasattr(self, "moveInfo"):
+                # get pseudoDC id of objects which should be redrawn
+                if action == "moveLine":
+                    # -> move line
+                    self.moveInfo['id'] = self.digit.GetDisplay().GetSelected(grassId = False)
+                else: # moveVertex
+                    self.moveInfo['id'] = self.digit.GetDisplay().GetSelectedVertex(pos1)
+                    if len(self.moveInfo['id']) == 0: # no vertex found
+                        self.digit.GetDisplay().SetSelected([])
+            
+            #
+            # check for duplicates
+            #
+            if UserSettings.Get(group = 'vdigit', key = 'checkForDupl', subkey = 'enabled'):
+                dupl = self.digit.GetDisplay().GetDuplicates()
+                self.UpdateMap(render = False)
+                    
+                if dupl:
+                    posWindow = self.ClientToScreen((self.mouse['end'][0] + self.dialogOffset,
+                                                     self.mouse['end'][1] + self.dialogOffset))
+                    
+                    dlg = VDigitDuplicatesDialog(parent = self, data = dupl, pos = posWindow)
+                    
+                    if dlg.ShowModal() == wx.ID_OK:
+                        self.digit.GetDisplay().UnSelect(dlg.GetUnSelected())
+                        # update selected
+                        self.UpdateMap(render = False)
+                
+            if action != "editLine":
+                # -> move line || move vertex
+                self.UpdateMap(render = False)
+        
+        else: # no vector object found
+            if not (action in ("moveLine",
+                                                 "moveVertex") and \
+                        hasattr(self, "moveInfo") and \
+                        len(self.moveInfo['id']) > 0):
+                # avoid left-click when features are already selected
+                self.UpdateMap(render = False, renderVector = False)
+        
+    def OnLeftUpModifyLine(self, event):
+        """!Left mouse button released - vector digitizer split line,
+        add/remove vertex action
+        """
+        pos1 = self.Pixel2Cell(self.mouse['begin'])
+        
+        pointOnLine = self.digit.GetDisplay().SelectLineByPoint(pos1)['point']
+        if not pointOnLine:
+            return
+        
+        if self.toolbar.GetAction() in ["splitLine", "addVertex"]:
+            self.UpdateMap(render = False) # highlight object
+            self.DrawCross(pdc = self.pdcTmp, coords = self.Cell2Pixel((pointOnLine[0], pointOnLine[1])),
+                           size = 5)
+        else: # removeVertex
+            # get only id of vertex
+            try:
+                id = self.digit.GetDisplay().GetSelectedVertex(pos1)[0]
+            except IndexError:
+                id = None
+            
+            if id:
+                x, y = self.pdcVector.GetIdBounds(id)[0:2]
+                self.pdcVector.RemoveId(id)
+                self.UpdateMap(render = False) # highlight object
+                self.DrawCross(pdc = self.pdcTmp, coords = (x, y),
+                               size = 5)
+            else:
+                # unselect
+                self.digit.GetDisplay().SetSelected([])
+                self.UpdateMap(render = False)
+        
+    def OnLeftUpCopyLine(self, event):
+        """!Left mouse button released - vector digitizer copy feature
+        action
+        """
+        pos1 = self.Pixel2Cell(self.mouse['begin'])
+        pos2 = self.Pixel2Cell(self.mouse['end'])
+        
+        if UserSettings.Get(group = 'vdigit', key = 'bgmap',
+                            subkey = 'value', internal = True) == '':
+            # no background map -> copy from current vector map layer
+            nselected = self.bdigit.GetDisplay().SelectLinesByBox((pos1, pos2))
+            
+            if nselected > 0:
+                # highlight selected features
+                self.UpdateMap(render = False)
+            else:
+                self.UpdateMap(render = False, renderVector = False)
+        else:
+            # copy features from background map
+            self.copyIds = self.digit.SelectLinesFromBackgroundMap(bbox = (pos1, pos2))
+            if len(self.copyIds) > 0:
+                color = UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                         subkey = ['highlight', 'color'])
+                colorStr = str(color[0]) + ":" + str(color[1]) + ":" + str(color[2])
+                dVectTmp = ['d.vect',
+                            'map=%s' % UserSettings.Get(group = 'vdigit', key = 'bgmap',
+                                                        subkey = 'value', internal = True),
+                            'cats=%s' % ListOfCatsToRange(self.copyIds),
+                            '-i',
+                            'color=%s' % colorStr,
+                            'fcolor=%s' % colorStr,
+                            'type=point,line,boundary,centroid',
+                            'width=2']
+                
+                if not self.layerTmp:
+                    self.layerTmp = self.Map.AddLayer(type = 'vector',
+                                                      name = QUERYLAYER,
+                                                      command = dVectTmp)
+                else:
+                    self.layerTmp.SetCmd(dVectTmp)
+            else:
+                if self.layerTmp:
+                    self.Map.DeleteLayer(self.layerTmp)
+                    self.layerTmp = None
+            
+            self.UpdateMap(render = True, renderVector = True)
+            
+    def OnLeftUpBulkLine(self, event):
+        """!Left mouse button released - vector digitizer z-bulk line
+        action
+        """
+        # select lines to be labeled
+        pos1 = self.polycoords[0]
+        pos2 = self.polycoords[1]
+        nselected = self.digit.GetDisplay().SelectLinesByBox((pos1, pos2))
+        
+        if nselected > 0:
+            # highlight selected features
+            self.UpdateMap(render = False)
+            self.DrawLines(pdc = self.pdcTmp) # redraw temp line
+        else:
+            self.UpdateMap(render = False, renderVector = False)
+            
+    def OnLeftUpConnectLine(self, event):
+        """!Left mouse button released - vector digitizer connect line
+        action
+        """
+        if len(self.digit.GetDisplay().GetSelected()) > 0:
+            self.UpdateMap(render = False)
+        
+    def _onLeftUp(self, event):
+        """!Left mouse button released"""
+        if hasattr(self, "moveInfo"):
+            if len(self.digit.GetDisplay().GetSelected()) == 0:
+                self.moveInfo['begin'] = self.Pixel2Cell(self.mouse['begin']) # left down
+            
+            # eliminate initial mouse moving efect
+            self.mouse['begin'] = self.mouse['end'] 
+        
+        action = self.toolbar.GetAction()
+        if action in ("deleteLine",
+                      "moveLine",
+                      "moveVertex",
+                      "copyCats",
+                      "copyAttrs",
+                      "editLine",
+                      "flipLine",
+                      "mergeLine",
+                      "snapLine",
+                      "queryLine",
+                      "breakLine",
+                      "typeConv",
+                      "connectLine"):
+            self.OnLeftUpVarious(event)
+        
+        elif action in ("splitLine",
+                        "addVertex",
+                        "removeVertex"):
+            self.OnLeftUpModifyLine(event)
+        
+        elif action == "copyLine":
+            self.OnLeftUpCopyLine(event)
+            
+        elif action == "zbulkLine" and \
+                len(self.polycoords) == 2:
+            self.OnLeftUpBulkLine(event)
+        
+        elif action == "connectLine":
+            self.OnLeftUpConnectLine(event)
+        
+        if len(self.digit.GetDisplay().GetSelected()) > 0:
+            self.redrawAll = None
+        
+    def _onRightDown(self, event):
+        # digitization tool (confirm action)
+        action = self.toolbar.GetAction()
+        if action in ("moveLine", "moveVertex") and \
+                hasattr(self, "moveInfo"):
+            pFrom = self.moveInfo['begin']
+            pTo = self.Pixel2Cell(event.GetPositionTuple())
+            
+            move = (pTo[0] - pFrom[0],
+                    pTo[1] - pFrom[1])
+            
+            if action == "moveLine":
+                # move line
+                if self.digit.MoveSelectedLines(move) < 0:
+                    return
+            elif action == "moveVertex":
+                # move vertex
+                fid = self.digit.MoveSelectedVertex(pFrom, move)
+                if fid < 0:
+                    return
+                
+                self._geomAttrbUpdate([fid,])
+            
+            del self.moveInfo
+        
+    def _onRightUp(self, event):
+        """!Right mouse button released (confirm action)
+        """
+        action = self.toolbar.GetAction()
+        if action == "addLine" and \
+                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
+            # -> add new line / boundary
+            try:
+                mapName = self.toolbar.GetLayer().GetName()
+            except:
+                mapName = None
+                GError(parent = self,
+                       message = _("No vector map selected for editing."))
+                    
+            if mapName:
+                if self.toolbar.GetAction('type') == 'line':
+                    line = True
+                else:
+                    line = False
+                    
+                if len(self.polycoords) < 2: # ignore 'one-point' lines
+                    return
+                    
+                nfeat, fids = self.digit.AddFeature(self.toolbar.GetAction('type'), self.polycoords)
+                if nfeat < 0:
+                    return
+                    
+                position = self.Cell2Pixel(self.polycoords[-1])
+                self.polycoords = []
+                self.UpdateMap(render = False)
+                self.redrawAll = True
+                self.Refresh()
+                
+                # add new record into atribute table
+                if UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled') and \
+                        (line is True or \
+                             (not line and nfeat > 0)):
+                    posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
+                                                     position[1] + self.dialogOffset))
+                        
+                    # select attributes based on layer and category
+                    cats = { fids[0] : {
+                            UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') :
+                                (UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), )
+                            }}
+                    
+                    addRecordDlg = DisplayAttributesDialog(parent = self, map = mapName,
+                                                           cats = cats,
+                                                           pos = posWindow,
+                                                           action = "add", ignoreError = True)
+                    
+                    for fid in fids:
+                        self._geomAttrb(fid, addRecordDlg, 'length')
+                        # auto-placing centroid
+                        self._geomAttrb(fid, addRecordDlg, 'area')
+                        self._geomAttrb(fid, addRecordDlg, 'perimeter')
+
+                    
+                    if addRecordDlg.mapDBInfo and \
+                            addRecordDlg.ShowModal() == wx.ID_OK:
+                        sqlfile = tempfile.NamedTemporaryFile(mode = "w")
+                        for sql in addRecordDlg.GetSQLString():
+                            sqlfile.file.write(sql + ";\n")
+                        sqlfile.file.flush()
+                        RunCommand('db.execute',
+                                   parent = True,
+                                   quiet = True,
+                                   input = sqlfile.name)
+                        
+                    if addRecordDlg.mapDBInfo:
+                        self._updateATM()
+            
+        elif action == "deleteLine":
+            # -> delete selected vector features
+            if self.digit.DeleteSelectedLines() < 0:
+                return
+            self._updateATM()
+        elif action == "splitLine":
+            # split line
+            if self.digit.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
+                return
+        elif action == "addVertex":
+            # add vertex
+            fid = self.digit.AddVertex(self.Pixel2Cell(self.mouse['begin']))
+            if fid < 0:
+                return
+        elif action == "removeVertex":
+            # remove vertex
+            fid = self.digit.RemoveVertex(self.Pixel2Cell(self.mouse['begin']))
+            if fid < 0:
+                return
+            self._geomAttrbUpdate([fid,])
+        elif action in ("copyCats", "copyAttrs"):
+            if action == 'copyCats':
+                if self.digit.CopyCats(self.copyCatsList,
+                                       self.copyCatsIds, copyAttrb = False) < 0:
+                    return
+            else:
+                if self.digit.CopyCats(self.copyCatsList,
+                                       self.copyCatsIds, copyAttrb = True) < 0:
+                    return
+                
+            del self.copyCatsList
+            del self.copyCatsIds
+            
+            self._updateATM()
+                
+        elif action == "editLine" and \
+                hasattr(self, "moveInfo"):
+            line = self.digit.GetDisplay().GetSelected()[0]
+            if self.digit.EditLine(line, self.polycoords) < 0:
+                return
+                
+            del self.moveInfo
+                
+        elif action == "flipLine":
+            if self.digit.FlipLine() < 0:
+                return
+        elif action == "mergeLine":
+            if self.digit.MergeLine() < 0:
+                return
+        elif action == "breakLine":
+            if self.digit.BreakLine() < 0:
+                return
+        elif action == "snapLine":
+            if self.digit.SnapLine() < 0:
+                return
+        elif action == "connectLine":
+            if len(self.digit.GetDisplay().GetSelected()) > 1:
+                if self.digit.ConnectLine() < 0:
+                    return
+        elif action == "copyLine":
+            if self.digit.CopyLine(self.copyIds) < 0:
+                return
+            del self.copyIds
+            if self.layerTmp:
+                self.Map.DeleteLayer(self.layerTmp)
+                self.UpdateMap(render = True, renderVector = False)
+            del self.layerTmp
+        
+        elif action == "zbulkLine" and len(self.polycoords) == 2:
+            pos1 = self.polycoords[0]
+            pos2 = self.polycoords[1]
+            
+            selected = self.digit.GetDisplay().GetSelected()
+            dlg = VDigitZBulkDialog(parent = self, title = _("Z bulk-labeling dialog"),
+                                    nselected = len(selected))
+            if dlg.ShowModal() == wx.ID_OK:
+                if self.digit.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
+                                         dlg.step.GetValue()) < 0:
+                    return
+            self.UpdateMap(render = False)
+        elif action == "typeConv":
+            # -> feature type conversion
+            # - point <-> centroid
+            # - line <-> boundary
+            if self.digit.TypeConvForSelectedLines() < 0:
+                return
+
+        if action != "addLine":
+            # unselect and re-render
+            self.digit.GetDisplay().SetSelected([])
+            self.polycoords = []
+            self.UpdateMap(render = False)
+        
+    def _onMouseMoving(self, event):
+        self.mouse['end'] = event.GetPositionTuple()[:]
+        
+        Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
+                       (self.mouse['end'][0], self.mouse['end'][1]))
+
+        action = self.toolbar.GetAction()
+        if action == "addLine" and \
+                self.toolbar.GetAction('type') in ["line", "boundary", "area"]:
+            if len(self.polycoords) > 0:
+                self.MouseDraw(pdc = self.pdcTmp, begin = self.Cell2Pixel(self.polycoords[-1]))
+        
+        elif action in ["moveLine", "moveVertex", "editLine"] \
+                and hasattr(self, "moveInfo"):
+            dx = self.mouse['end'][0] - self.mouse['begin'][0]
+            dy = self.mouse['end'][1] - self.mouse['begin'][1]
+        
+            # draw lines on new position
+            if action == "moveLine" and \
+                    len(self.moveInfo['id']) > 0:
+                # move line
+                for id in self.moveInfo['id']:
+                    self.pdcTmp.TranslateId(id, dx, dy)
+            elif action in ["moveVertex", "editLine"]:
+                # move vertex ->
+                # (vertex, left vertex, left line,
+                # right vertex, right line)
+                
+                # do not draw static lines
+                if action == "moveVertex" and \
+                        len(self.moveInfo['id']) > 0:
+                    self.polycoords = []
+                    self.pdcTmp.RemoveId(self.moveInfo['id'][0])
+                    if self.moveInfo['id'][1] > 0: # previous vertex
+                        x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][1])[0:2])
+                        self.pdcTmp.RemoveId(self.moveInfo['id'][1] + 1)
+                        self.polycoords.append((x, y))
+                    self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
+
+                    if self.moveInfo['id'][2] > 0: # next vertex
+                        x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.moveInfo['id'][2])[0:2])
+                        self.pdcTmp.RemoveId(self.moveInfo['id'][2]-1)
+                        self.polycoords.append((x, y))
+                    
+                    self.ClearLines(pdc = self.pdcTmp)
+                    self.DrawLines(pdc = self.pdcTmp)
+                        
+                if action == "editLine":
+                    self.MouseDraw(pdc = self.pdcTmp,
+                                   begin = self.Cell2Pixel(self.polycoords[-1]))
+                
+            self.Refresh() # TODO: use RefreshRect()
+            self.mouse['begin'] = self.mouse['end']
+            
+        elif action == "zbulkLine":
+            if len(self.polycoords) == 1:
+                # draw mouse moving
+                self.MouseDraw(self.pdcTmp)
+                
+    def _zoom(self, event):
+        tmp1 = self.mouse['end']
+        tmp2 = self.Cell2Pixel(self.moveInfo['begin'])
+        dx = tmp1[0] - tmp2[0]
+        dy = tmp1[1] - tmp2[1]
+        self.moveInfo['beginDiff'] = (dx, dy)
+        for id in self.moveInfo['id']:
+            self.pdcTmp.RemoveId(id)
+        

Copied: grass/trunk/gui/wxpython/vdigit/preferences.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/vdigit.py)
===================================================================
--- grass/trunk/gui/wxpython/vdigit/preferences.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/preferences.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,781 @@
+"""!
+ at package vdigit.preferences
+
+ at brief wxGUI vector digitizer preferences dialogs
+
+Classes:
+ - VDigitSettingsDialog
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import textwrap
+
+import wx
+import wx.lib.colourselect as csel
+
+from core             import globalvar
+from core.debug       import Debug
+from gui_core.gselect import ColumnSelect
+from core.units       import Units
+from core.settings    import UserSettings
+
+class VDigitSettingsDialog(wx.Dialog):
+    def __init__(self, parent, title, style = wx.DEFAULT_DIALOG_STYLE):
+        """!Standard settings dialog for digitization purposes
+        """
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
+
+        self.parent = parent # mapdisplay.MapFrame class instance
+        self.digit = self.parent.MapWindow.digit
+        
+        # notebook
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self._createSymbologyPage(notebook)
+        self.digit.SetCategory()
+        self._createGeneralPage(notebook)
+        self._createAttributesPage(notebook)
+        self._createQueryPage(notebook)
+
+        # buttons
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnSave = wx.Button(self, wx.ID_SAVE)
+        btnSave.SetDefault()
+
+        # bindigs
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnApply.SetToolTipString(_("Apply changes for this session"))
+        btnApply.SetDefault()
+        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        btnSave.SetToolTipString(_("Close dialog and save changes to user settings file"))
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+        
+        # sizers
+        btnSizer = wx.StdDialogButtonSizer()
+        btnSizer.AddButton(btnCancel)
+        btnSizer.AddButton(btnApply)
+        btnSizer.AddButton(btnSave)
+        btnSizer.Realize()
+        
+        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.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+        
+        self.Bind(wx.EVT_CLOSE, self.OnCancel)
+        
+        self.SetSizer(mainSizer)
+        mainSizer.Fit(self)
+
+    def _createSymbologyPage(self, notebook):
+        """!Create notebook page concerning symbology settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Symbology"))
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+
+        self.symbology = {}
+        for label, key in self._symbologyData():
+            textLabel = wx.StaticText(panel, wx.ID_ANY, label)
+            color = csel.ColourSelect(panel, id = wx.ID_ANY,
+                                      colour = UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                                              subkey = [key, 'color']), size = globalvar.DIALOG_COLOR_SIZE)
+            isEnabled = UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                         subkey = [key, 'enabled'])
+            if isEnabled is not None:
+                enabled = wx.CheckBox(panel, id = wx.ID_ANY, label = "")
+                enabled.SetValue(isEnabled)
+                self.symbology[key] = (enabled, color)
+            else:
+                enabled = (1, 1)
+                self.symbology[key] = (None, color)
+            
+            flexSizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+            flexSizer.Add(enabled, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+            flexSizer.Add(color, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+            color.SetName("GetColour")
+        
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 10)
+        
+        panel.SetSizer(sizer)
+        
+        return panel
+
+    def _createGeneralPage(self, notebook):
+        """!Create notebook page concerning general settings"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("General"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        
+        #
+        # display section
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Display"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        # line width
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width"))
+        self.lineWidthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
+                                          initial = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'value'),
+                                          min = 1, max = 1e6)
+        units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
+                              label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
+                              style = wx.ALIGN_LEFT)
+        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.lineWidthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
+                      border = 10)
+
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        #
+        # snapping section
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Snapping"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        flexSizer = wx.FlexGridSizer(cols = 3, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+
+        # snapping
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold"))
+        self.snappingValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
+                                         initial = UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'value'),
+                                         min = -1, max = 1e6)
+        self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue)
+        self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue)
+        self.snappingUnit = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
+                                      choices = [_("screen pixels"), _("map units")])
+        self.snappingUnit.SetStringSelection(UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'units'))
+        self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits)
+        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.snappingValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(self.snappingUnit, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
+
+        vertexSizer = wx.BoxSizer(wx.VERTICAL)
+        self.snapVertex = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                      label = _("Snap also to vertex"))
+        self.snapVertex.SetValue(UserSettings.Get(group = 'vdigit', key = "snapToVertex", subkey = 'enabled'))
+        vertexSizer.Add(item = self.snapVertex, proportion = 0, flag = wx.EXPAND)
+        self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
+        self.snappingInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                          label = _("Snapping threshold is %(value).1f %(units)s") % \
+                                              {'value' : self.digit.GetDisplay().GetThreshold(),
+                                               'units' : self.mapUnits})
+        vertexSizer.Add(item = self.snappingInfo, proportion = 0,
+                        flag = wx.ALL | wx.EXPAND, border = 1)
+
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.EXPAND)
+        sizer.Add(item = vertexSizer, proportion = 1, flag = wx.EXPAND)
+        border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        #
+        # select box
+        #
+        box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Select vector features"))
+        # feature type
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        inSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.selectFeature = {}
+        for feature in ('point', 'line',
+                        'centroid', 'boundary'):
+            chkbox = wx.CheckBox(parent = panel, label = feature)
+            self.selectFeature[feature] = chkbox.GetId()
+            chkbox.SetValue(UserSettings.Get(group = 'vdigit', key = 'selectType',
+                                             subkey = [feature, 'enabled']))
+            inSizer.Add(item = chkbox, proportion = 0,
+                        flag = wx.EXPAND | wx.ALL, border = 5)
+        sizer.Add(item = inSizer, proportion = 0, flag = wx.EXPAND)
+        # threshold
+        flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select threshold"))
+        self.selectThreshValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1),
+                                             initial = UserSettings.Get(group = 'vdigit', key = "selectThresh", subkey = 'value'),
+                                             min = 1, max = 1e6)
+        units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1),
+                              label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'),
+                              style = wx.ALIGN_LEFT)
+        flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.selectThreshValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT,
+                      border = 10)
+
+        self.selectIn = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                    label = _("Select only features inside of selection bounding box"))
+        self.selectIn.SetValue(UserSettings.Get(group = 'vdigit', key = "selectInside", subkey = 'enabled'))
+        self.selectIn.SetToolTipString(_("By default are selected all features overlapping selection bounding box "))
+        
+        self.checkForDupl = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                        label = _("Check for duplicates"))
+        self.checkForDupl.SetValue(UserSettings.Get(group = 'vdigit', key = "checkForDupl", subkey = 'enabled'))
+
+
+        sizer.Add(item = flexSizer, proportion = 0, flag = wx.EXPAND)
+        sizer.Add(item = self.selectIn, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)
+        sizer.Add(item = self.checkForDupl, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1)        
+        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+
+        #
+        # digitize lines box
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize line features"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        self.intersect = wx.CheckBox(parent = panel, label = _("Break lines at intersection"))
+        self.intersect.SetValue(UserSettings.Get(group = 'vdigit', key = 'breakLines', subkey = 'enabled'))
+        
+        sizer.Add(item = self.intersect, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+
+        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+
+        #
+        # save-on-exit box
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Save changes"))
+        # save changes on exit?
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        self.save = wx.CheckBox(parent = panel, label = _("Save changes on exit"))
+        self.save.SetValue(UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled'))
+        sizer.Add(item = self.save, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createQueryPage(self, notebook):
+        """!Create notebook page for query tool"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Query tool"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+
+        #
+        # query tool box
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Choose query tool"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units']
+
+        self.queryBox = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select by box"))
+        self.queryBox.SetValue(UserSettings.Get(group = 'vdigit', key = "query", subkey = 'box'))
+
+        sizer.Add(item = self.queryBox, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        sizer.Add((0, 5))
+
+        #
+        # length
+        #
+        self.queryLength = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("length"))
+        self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
+        sizer.Add(item = self.queryLength, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select lines"))
+        self.queryLengthSL = wx.Choice (parent = panel, id = wx.ID_ANY, 
+                                        choices  =  [_("shorter than"), _("longer than")])
+        self.queryLengthSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection'))
+        self.queryLengthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
+                                            initial = 1,
+                                            min = 0, max = 1e6)
+        self.queryLengthValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'thresh'))
+        units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
+        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.queryLengthSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(self.queryLengthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+
+        #
+        # dangle
+        #
+        self.queryDangle = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("dangle"))
+        self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery)
+        sizer.Add(item = self.queryDangle, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5)
+        flexSizer.AddGrowableCol(0)
+        txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select dangles"))
+        self.queryDangleSL = wx.Choice (parent = panel, id = wx.ID_ANY, 
+                                        choices = [_("shorter than"), _("longer than")])
+        self.queryDangleSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection'))
+        self.queryDangleValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1),
+                                       initial = 1,
+                                       min = 0, max = 1e6)
+        self.queryDangleValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'thresh'))
+        units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits)
+        flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(self.queryDangleSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(self.queryDangleValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+        flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+
+        if UserSettings.Get(group = 'vdigit', key = "query", subkey = 'selection') == 0:
+            self.queryLength.SetValue(True)
+        else:
+            self.queryDangle.SetValue(True)
+
+        # enable & disable items
+        self.OnChangeQuery(None)
+
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _createAttributesPage(self, notebook):
+        """!Create notebook page for attributes"""
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+        notebook.AddPage(page = panel, text = _("Attributes"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+
+        #
+        # add new record
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize new feature"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        # checkbox
+        self.addRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                     label = _("Add new record into table"))
+        self.addRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled'))
+        sizer.Add(item = self.addRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        # settings
+        flexSizer = wx.FlexGridSizer(cols = 2, hgap = 3, vgap = 3)
+        flexSizer.AddGrowableCol(0)
+        settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use")))
+        # layer
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Layer"))
+        self.layer = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
+                                 min = 1, max = 1e3)
+        self.layer.SetValue(int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')))
+        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = self.layer, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+        # category number
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category number"))
+        self.category = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1),
+                                    initial = UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'),
+                                    min = -1e9, max = 1e9) 
+        if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') != 1:
+            self.category.Enable(False)
+        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = self.category, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+        # category mode
+        text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category mode"))
+        self.categoryMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1),
+                                      choices = [_("Next to use"), _("Manual entry"), _("No category")])
+        self.categoryMode.SetSelection(UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection'))
+        flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        flexSizer.Add(item = self.categoryMode, proportion = 0,
+                      flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+
+        sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0,
+                   flag = wx.ALL | wx.EXPAND, border = 5)
+
+        #
+        # delete existing record
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Delete existing feature(s)"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        # checkbox
+        self.deleteRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                        label = _("Delete record from table"))
+        self.deleteRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "delRecord", subkey = 'enabled'))
+        sizer.Add(item = self.deleteRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0,
+                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        #
+        # geometry attributes (currently only length and area are supported)
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY,
+                              label = " %s " % _("Geometry attributes"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
+        gridSizer.AddGrowableCol(0)
+        self.geomAttrb = { 'length' : { 'label' : _('length') },
+                           'area' : { 'label' : _('area') },
+                           'perimeter' : { 'label' : _('perimeter') } }
+
+        digitToolbar = self.parent.toolbars['vdigit']
+        try:
+            vectorName = digitToolbar.GetLayer().GetName()
+        except AttributeError:
+            vectorName = None # no vector selected for editing
+        layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
+        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
+        tree = self.parent.tree
+        item = tree.FindItemByData('maplayer', mapLayer)
+        row = 0
+        for attrb in ['length', 'area', 'perimeter']:
+            # checkbox
+            check = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+                                label = self.geomAttrb[attrb]['label'])
+            ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled'))
+            check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb)
+            # column (only numeric)
+            column = ColumnSelect(parent = panel, size = (200, -1))
+            column.InsertColumns(vector = vectorName,
+                                 layer = layer, excludeKey = True,
+                                 type = ['integer', 'double precision'])
+            # units 
+            if attrb == 'area':
+                choices = Units.GetUnitsList('area')
+            else:
+                choices = Units.GetUnitsList('length')
+            win_units = wx.Choice(parent = panel, id = wx.ID_ANY,
+                                  choices = choices, size = (120, -1))
+            
+            # default values
+            check.SetValue(False)
+            if item and tree.GetPyData(item)[0]['vdigit'] and \
+                    'geomAttr' in tree.GetPyData(item)[0]['vdigit'] and \
+                    attrb in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
+                check.SetValue(True)
+                column.SetStringSelection(tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['column'])
+                if attrb == 'area':
+                    type = 'area'
+                else:
+                    type = 'length'
+                unitsIdx = Units.GetUnitsIndex(type, 
+                                                tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['units'])
+                win_units.SetSelection(unitsIdx)
+
+            if not vectorName:
+                check.Enable(False)
+                column.Enable(False)
+            
+            if not check.IsChecked():
+                column.Enable(False)
+            
+            self.geomAttrb[attrb]['check']  = check.GetId()
+            self.geomAttrb[attrb]['column'] = column.GetId()
+            self.geomAttrb[attrb]['units']  = win_units.GetId()
+
+            gridSizer.Add(item = check,
+                          flag = wx.ALIGN_CENTER_VERTICAL,
+                          pos = (row, 0))
+            gridSizer.Add(item = column,
+                          pos = (row, 1))
+            gridSizer.Add(item = win_units,
+                          pos = (row, 2))
+            row += 1
+        
+        note = '\n'.join(textwrap.wrap(_("Note: These settings are stored "
+                                         "in the workspace not in the vector digitizer "
+                                         "preferences."), 55))
+        gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                           label = note),
+                      pos = (3, 0), span = (1, 3))
+                      
+        sizer.Add(item = gridSizer, proportion = 1,
+                  flag = wx.ALL | wx.EXPAND, border = 1)
+        border.Add(item = sizer, proportion = 0,
+                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        # bindings
+        self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord)
+        self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode)
+        self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer)
+
+        panel.SetSizer(border)
+        
+        return panel
+
+    def _symbologyData(self):
+        """!Data for _createSymbologyPage()
+
+        label | checkbox | color
+        """
+
+        return (
+            #            ("Background", "symbolBackground"),
+            (_("Highlight"), "highlight"),
+            (_("Highlight (duplicates)"), "highlightDupl"),
+            (_("Point"), "point"),
+            (_("Line"), "line"),
+            (_("Boundary (no area)"), "boundaryNo"),
+            (_("Boundary (one area)"), "boundaryOne"),
+            (_("Boundary (two areas)"), "boundaryTwo"),
+            (_("Centroid (in area)"), "centroidIn"),
+            (_("Centroid (outside area)"), "centroidOut"),
+            (_("Centroid (duplicate in area)"), "centroidDup"),
+            (_("Node (one line)"), "nodeOne"),
+            (_("Node (two lines)"), "nodeTwo"),
+            (_("Vertex"), "vertex"),
+            (_("Area (closed boundary + centroid)"), "area"),
+            (_("Direction"), "direction"),)
+
+    def OnGeomAttrb(self, event):
+        """!Register geometry attributes (enable/disable)
+        """
+        checked = event.IsChecked()
+        id = event.GetId()
+        key = None
+        for attrb, val in self.geomAttrb.iteritems():
+            if val['check'] == id:
+                key = attrb
+                break
+        
+        column = self.FindWindowById(self.geomAttrb[key]['column'])
+        if checked:
+            column.Enable()
+        else:
+            column.Enable(False)
+        
+    def OnChangeCategoryMode(self, event):
+        """!Change category mode
+        """
+        mode = event.GetSelection()
+        UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = mode)
+        if mode == 1: # manual entry
+            self.category.Enable(True)
+        elif self.category.IsEnabled(): # disable
+            self.category.Enable(False)
+        
+        if mode == 2 and self.addRecord.IsChecked(): # no category
+            self.addRecord.SetValue(False)
+        
+        self.digit.SetCategory()
+        self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
+
+    def OnChangeLayer(self, event):
+        """!Layer changed
+        """
+        layer = event.GetInt()
+        if layer > 0:
+            UserSettings.Set(group = 'vdigit', key = 'layer', subkey = 'value', value = layer)
+            self.digit.SetCategory()
+            self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value'))
+            
+        event.Skip()
+
+    def OnChangeAddRecord(self, event):
+        """!Checkbox 'Add new record' status changed
+        """
+        pass
+        # self.category.SetValue(self.digit.SetCategory())
+            
+    def OnChangeSnappingValue(self, event):
+        """!Change snapping value - update static text
+        """
+        value = self.snappingValue.GetValue()
+        
+        if value < 0:
+            region = self.parent.MapWindow.Map.GetRegion()
+            res = (region['nsres'] + region['ewres']) / 2.
+            threshold = self.digit.GetDisplay().GetThreshold(value = res)
+        else:
+            if self.snappingUnit.GetStringSelection() == "map units":
+                threshold = value
+            else:
+                threshold = self.digit.GetDisplay().GetThreshold(value = value)
+            
+        if value == 0:
+            self.snappingInfo.SetLabel(_("Snapping disabled"))
+        elif value < 0:
+            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s "
+                                         "(based on comp. resolution)") % 
+                                       {'value' : threshold,
+                                        'units' : self.mapUnits.lower()})
+        else:
+            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
+                                       {'value' : threshold,
+                                        'units' : self.mapUnits.lower()})
+        
+        event.Skip()
+
+    def OnChangeSnappingUnits(self, event):
+        """!Snapping units change -> update static text
+        """
+        value = self.snappingValue.GetValue()
+        units = self.snappingUnit.GetStringSelection()
+        threshold = self.digit.GetDisplay().GetThreshold(value = value, units = units)
+
+        if units == "map units":
+            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
+                                       {'value' : value,
+                                        'units' : self.mapUnits})
+        else:
+            self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 
+                                       {'value' : threshold,
+                                        'units' : self.mapUnits})
+            
+        event.Skip()
+
+    def OnChangeQuery(self, event):
+        """!Change query
+        """
+        if self.queryLength.GetValue():
+            # length
+            self.queryLengthSL.Enable(True)
+            self.queryLengthValue.Enable(True)
+            self.queryDangleSL.Enable(False)
+            self.queryDangleValue.Enable(False)
+        else:
+            # dangle
+            self.queryLengthSL.Enable(False)
+            self.queryLengthValue.Enable(False)
+            self.queryDangleSL.Enable(True)
+            self.queryDangleValue.Enable(True)
+
+    def OnSave(self, event):
+        """!Button 'Save' pressed
+        """
+        self.UpdateSettings()
+        self.parent.toolbars['vdigit'].settingsDialog = None
+
+        fileSettings = {}
+        UserSettings.ReadSettingsFile(settings = fileSettings)
+        fileSettings['vdigit'] = UserSettings.Get(group = 'vdigit')
+        
+        file = UserSettings.SaveToFile(fileSettings)
+        self.parent.GetLayerManager().goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file)
+        
+        self.Destroy()
+
+        event.Skip()
+        
+    def OnApply(self, event):
+        """!Button 'Apply' pressed
+        """
+        self.UpdateSettings()
+
+    def OnCancel(self, event):
+        """!Button 'Cancel' pressed
+        """
+        self.parent.toolbars['vdigit'].settingsDialog = None
+        self.Destroy()
+
+        if event:
+            event.Skip()
+        
+    def UpdateSettings(self):
+        """!Update digitizer settings
+        """
+        self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes
+        # symbology
+        for key, (enabled, color) in self.symbology.iteritems():
+            if enabled:
+                UserSettings.Set(group = 'vdigit', key = 'symbol',
+                                 subkey = [key, 'enabled'],
+                                 value = enabled.IsChecked())
+                UserSettings.Set(group = 'vdigit', key = 'symbol',
+                                 subkey = [key, 'color'],
+                                 value = tuple(color.GetColour()))
+            else:
+                UserSettings.Set(group = 'vdigit', key = 'symbol',
+                                 subkey = [key, 'color'],
+                                 value = tuple(color.GetColour()))
+        # display
+        UserSettings.Set(group = 'vdigit', key = "lineWidth", subkey = 'value',
+                         value = int(self.lineWidthValue.GetValue()))
+
+        # snapping
+        UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'value',
+                         value = int(self.snappingValue.GetValue()))
+        UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'units',
+                         value = self.snappingUnit.GetStringSelection())
+        UserSettings.Set(group = 'vdigit', key = "snapToVertex", subkey = 'enabled',
+                         value = self.snapVertex.IsChecked())
+        
+        # digitize new feature
+        UserSettings.Set(group = 'vdigit', key = "addRecord", subkey = 'enabled',
+                         value = self.addRecord.IsChecked())
+        UserSettings.Set(group = 'vdigit', key = "layer", subkey = 'value',
+                         value = int(self.layer.GetValue()))
+        UserSettings.Set(group = 'vdigit', key = "category", subkey = 'value',
+                         value = int(self.category.GetValue()))
+        UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection',
+                         value = self.categoryMode.GetSelection())
+
+        # delete existing feature
+        UserSettings.Set(group = 'vdigit', key = "delRecord", subkey = 'enabled',
+                         value = self.deleteRecord.IsChecked())
+
+        # geometry attributes (workspace)
+        mapLayer = self.parent.toolbars['vdigit'].GetLayer()
+        tree = self.parent.tree
+        item = tree.FindItemByData('maplayer', mapLayer)
+        for key, val in self.geomAttrb.iteritems():
+            checked = self.FindWindowById(val['check']).IsChecked()
+            column  = self.FindWindowById(val['column']).GetValue()
+            unitsIdx = self.FindWindowById(val['units']).GetSelection()
+            if item and not tree.GetPyData(item)[0]['vdigit']: 
+                tree.GetPyData(item)[0]['vdigit'] = { 'geomAttr' : dict() }
+            
+            if checked: # enable
+                if key == 'area':
+                    type = key
+                else:
+                    type = 'length'
+                unitsKey = Units.GetUnitsKey(type, unitsIdx)
+                tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] = { 'column' : column,
+                                                                       'units' : unitsKey }
+            else:
+                if item and tree.GetPyData(item)[0]['vdigit'] and \
+                        key in tree.GetPyData(item)[0]['vdigit']['geomAttr']:
+                    del tree.GetPyData(item)[0]['vdigit']['geomAttr'][key]
+        
+        # query tool
+        if self.queryLength.GetValue():
+            UserSettings.Set(group = 'vdigit', key = "query", subkey = 'selection',
+                             value = 0)
+        else:
+            UserSettings.Set(group = 'vdigit', key = "query", subkey = 'type',
+                             value = 1)
+        UserSettings.Set(group = 'vdigit', key = "query", subkey = 'box',
+                         value = self.queryBox.IsChecked())
+        UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'than-selection',
+                         value = self.queryLengthSL.GetSelection())
+        UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'thresh',
+                         value = int(self.queryLengthValue.GetValue()))
+        UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'than-selection',
+                         value = self.queryDangleSL.GetSelection())
+        UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'thresh',
+                         value = int(self.queryDangleValue.GetValue()))
+
+        # select features
+        for feature in ('point', 'line',
+                        'centroid', 'boundary'):
+            UserSettings.Set(group = 'vdigit', key = 'selectType',
+                             subkey = [feature, 'enabled'],
+                             value = self.FindWindowById(self.selectFeature[feature]).IsChecked())
+        UserSettings.Set(group = 'vdigit', key = "selectThresh", subkey = 'value',
+                         value = int(self.selectThreshValue.GetValue()))
+        UserSettings.Set(group = 'vdigit', key = "checkForDupl", subkey = 'enabled',
+                         value = self.checkForDupl.IsChecked())
+        UserSettings.Set(group = 'vdigit', key = "selectInside", subkey = 'enabled',
+                         value = self.selectIn.IsChecked())
+
+        # on-exit
+        UserSettings.Set(group = 'vdigit', key = "saveOnExit", subkey = 'enabled',
+                         value = self.save.IsChecked())
+
+        # break lines
+        UserSettings.Set(group = 'vdigit', key = "breakLines", subkey = 'enabled',
+                         value = self.intersect.IsChecked())
+        
+        self.digit.UpdateSettings()
+        
+        # redraw map if auto-rendering is enabled
+        if self.parent.IsAutoRendered(): 
+            self.parent.OnRender(None)

Added: grass/trunk/gui/wxpython/vdigit/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/toolbars.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/toolbars.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,815 @@
+"""!
+ at package vdigit.toolbars
+
+ at brief wxGUI vector digitizer toolbars
+
+List of classes:
+ - VDigitToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+from grass.script import core as grass
+
+from gui_core.toolbars  import BaseToolbar
+from gui_core.dialogs   import CreateNewVector
+from vdigit.preferences import VDigitSettingsDialog
+from vdigit.main        import VDigit
+from core.debug         import Debug
+from core.settings      import UserSettings
+from core.gcmd          import GError
+
+class VDigitToolbar(BaseToolbar):
+    """!Toolbar for digitization
+    """
+    def __init__(self, parent, MapWindow, tools = [], layerTree = None, log = None):
+        self.MapWindow     = MapWindow
+        self.Map           = MapWindow.GetMap() # Map class instance
+        self.layerTree     = layerTree  # reference to layer tree associated to map display
+        self.log           = log        # log area
+        self.tools         = tools
+        BaseToolbar.__init__(self, parent)
+        self.digit         = None
+        
+        # currently selected map layer for editing (reference to MapLayer instance)
+        self.mapLayer = None
+        # list of vector layers from Layer Manager (only in the current mapset)
+        self.layers   = [] 
+        
+        self.comboid  = self.combo = None
+        self.undo     = -1
+        
+        # only one dialog can be open
+        self.settingsDialog   = None
+        
+        # create toolbars (two rows optionally)
+        self.InitToolbar(self._toolbarData())
+        self.Bind(wx.EVT_TOOL, self.OnTool)
+        
+        # default action (digitize new point, line, etc.)
+        self.action = { 'desc' : '',
+                        'type' : '',
+                        'id'   : -1 }
+        
+        # list of available vector maps
+        self.UpdateListOfLayers(updateTool = True)
+        
+        # realize toolbar
+        self.Realize()
+        # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
+        if self.combo:
+            self.combo.Hide()
+            self.combo.Show()
+        
+        # disable undo/redo
+        if self.undo:
+            self.EnableTool(self.undo, False)
+        
+        # toogle to pointer by default
+        self.OnTool(None)
+        
+        self.FixSize(width = 105)
+        
+    def _toolbarData(self):
+        """!Toolbar data
+        """
+        data = []
+        icons = Icons['vdigit']
+        if not self.tools or 'selector' in self.tools:
+            data.append((None, ))
+        if not self.tools or 'addPoint' in self.tools:
+            data.append(("addPoint", icons["addPoint"],
+                         self.OnAddPoint,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'addLine' in self.tools:
+            data.append(("addLine", icons["addLine"],
+                        self.OnAddLine,
+                        wx.ITEM_CHECK))
+        if not self.tools or 'addBoundary' in self.tools:
+            data.append(("addBoundary", icons["addBoundary"],
+                         self.OnAddBoundary,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'addCentroid' in self.tools:
+            data.append(("addCentroid", icons["addCentroid"],
+                         self.OnAddCentroid,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'addArea' in self.tools:
+            data.append(("addArea", icons["addArea"],
+                         self.OnAddArea,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'moveVertex' in self.tools:            
+            data.append(("moveVertex", icons["moveVertex"],
+                         self.OnMoveVertex,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'addVertex' in self.tools:
+            data.append(("addVertex", icons["addVertex"],
+                         self.OnAddVertex,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'removeVertex' in self.tools:
+            data.append(("removeVertex", icons["removeVertex"],
+                         self.OnRemoveVertex,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'editLine' in self.tools:            
+            data.append(("editLine", icons["editLine"],
+                         self.OnEditLine,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'moveLine' in self.tools:
+            data.append(("moveLine", icons["moveLine"],
+                         self.OnMoveLine,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'deleteLine' in self.tools:
+            data.append(("deleteLine", icons["deleteLine"],
+                         self.OnDeleteLine,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'displayCats' in self.tools:
+            data.append(("displayCats", icons["displayCats"],
+                         self.OnDisplayCats,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'displayAttr' in self.tools:
+            data.append(("displayAttr", icons["displayAttr"],
+                         self.OnDisplayAttr,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'additionalSelf.Tools' in self.tools:
+            data.append(("additionalTools", icons["additionalTools"],
+                         self.OnAdditionalToolMenu,
+                         wx.ITEM_CHECK))
+        if not self.tools or 'undo' in self.tools or \
+                'settings' in self.tools or \
+                'quit' in self.tools:
+            data.append((None, ))
+        if not self.tools or 'undo' in self.tools:
+            data.append(("undo", icons["undo"],
+                         self.OnUndo))
+        if not self.tools or 'settings' in self.tools:
+            data.append(("settings", icons["settings"],
+                         self.OnSettings))
+        if not self.tools or 'quit' in self.tools:
+            data.append(("quit", icons["quit"],
+                         self.OnExit))
+        
+        return self._getToolbarData(data)
+    
+    def OnTool(self, event):
+        """!Tool selected -> disable selected tool in map toolbar"""
+        if self.parent.GetName() == 'IClassWindow':
+            toolbarName = 'iClassMap'
+        else:
+            toolbarName = 'map'
+        aId = self.parent.toolbars[toolbarName].GetAction(type = 'id')
+        self.parent.toolbars[toolbarName].ToggleTool(aId, False)
+                
+        # set cursor
+        cursor = self.parent.cursors["cross"]
+        self.MapWindow.SetCursor(cursor)
+        
+        # pointer
+        self.parent.OnPointer(None)
+                
+        if event:
+            # deselect previously selected tool
+            aId = self.action.get('id', -1)
+            if aId != event.GetId() and \
+                    self.action['id'] != -1:
+                self.ToggleTool(self.action['id'], False)
+            else:
+                self.ToggleTool(self.action['id'], True)
+            
+            self.action['id'] = event.GetId()
+            
+            event.Skip()
+        
+        if self.action['id'] != -1:
+            self.ToggleTool(self.action['id'], True)
+        
+        # clear tmp canvas
+        if self.action['id'] != aId:
+            self.MapWindow.ClearLines(pdc = self.MapWindow.pdcTmp)
+            if self.digit and \
+                    len(self.MapWindow.digit.GetDisplay().GetSelected()) > 0:
+                # cancel action
+                self.MapWindow.OnMiddleDown(None)
+        
+        # set focus
+        self.MapWindow.SetFocus()
+        
+    def OnAddPoint(self, event):
+        """!Add point to the vector map Laier"""
+        Debug.msg (2, "VDigitToolbar.OnAddPoint()")
+        self.action = { 'desc' : "addLine",
+                        'type' : "point",
+                        'id'   : self.addPoint }
+        self.MapWindow.mouse['box'] = 'point'
+        
+    def OnAddLine(self, event):
+        """!Add line to the vector map layer"""
+        Debug.msg (2, "VDigitToolbar.OnAddLine()")
+        self.action = { 'desc' : "addLine",
+                        'type' : "line",
+                        'id'   : self.addLine }
+        self.MapWindow.mouse['box'] = 'line'
+        ### self.MapWindow.polycoords = [] # reset temp line
+                
+    def OnAddBoundary(self, event):
+        """!Add boundary to the vector map layer"""
+        Debug.msg (2, "VDigitToolbar.OnAddBoundary()")
+        if self.action['desc'] != 'addLine' or \
+                self.action['type'] != 'boundary':
+            self.MapWindow.polycoords = [] # reset temp line
+        self.action = { 'desc' : "addLine",
+                        'type' : "boundary",
+                        'id'   : self.addBoundary }
+        self.MapWindow.mouse['box'] = 'line'
+        
+    def OnAddCentroid(self, event):
+        """!Add centroid to the vector map layer"""
+        Debug.msg (2, "VDigitToolbar.OnAddCentroid()")
+        self.action = { 'desc' : "addLine",
+                        'type' : "centroid",
+                        'id'   : self.addCentroid }
+        self.MapWindow.mouse['box'] = 'point'
+
+    def OnAddArea(self, event):
+        """!Add area to the vector map layer"""
+        Debug.msg (2, "VDigitToolbar.OnAddCentroid()")
+        self.action = { 'desc' : "addLine",
+                        'type' : "area",
+                        'id'   : self.addArea }
+        self.MapWindow.mouse['box'] = 'line'
+
+    def OnExit (self, event=None):
+        """!Quit digitization tool"""
+        # stop editing of the currently selected map layer
+        if self.mapLayer:
+            self.StopEditing()
+        
+        # close dialogs if still open
+        if self.settingsDialog:
+            self.settingsDialog.OnCancel(None)
+            
+        # set default mouse settings
+        self.MapWindow.mouse['use'] = "pointer"
+        self.MapWindow.mouse['box'] = "point"
+        self.MapWindow.polycoords = []
+        
+        # disable the toolbar
+        self.parent.RemoveToolbar("vdigit")
+        
+    def OnMoveVertex(self, event):
+        """!Move line vertex"""
+        Debug.msg(2, "Digittoolbar.OnMoveVertex():")
+        self.action = { 'desc' : "moveVertex",
+                        'id'   : self.moveVertex }
+        self.MapWindow.mouse['box'] = 'point'
+
+    def OnAddVertex(self, event):
+        """!Add line vertex"""
+        Debug.msg(2, "Digittoolbar.OnAddVertex():")
+        self.action = { 'desc' : "addVertex",
+                        'id'   : self.addVertex }
+        self.MapWindow.mouse['box'] = 'point'
+        
+    def OnRemoveVertex(self, event):
+        """!Remove line vertex"""
+        Debug.msg(2, "Digittoolbar.OnRemoveVertex():")
+        self.action = { 'desc' : "removeVertex",
+                        'id'   : self.removeVertex }
+        self.MapWindow.mouse['box'] = 'point'
+
+    def OnEditLine(self, event):
+        """!Edit line"""
+        Debug.msg(2, "Digittoolbar.OnEditLine():")
+        self.action = { 'desc' : "editLine",
+                        'id'   : self.editLine }
+        self.MapWindow.mouse['box'] = 'line'
+
+    def OnMoveLine(self, event):
+        """!Move line"""
+        Debug.msg(2, "Digittoolbar.OnMoveLine():")
+        self.action = { 'desc' : "moveLine",
+                        'id'   : self.moveLine }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnDeleteLine(self, event):
+        """!Delete line"""
+        Debug.msg(2, "Digittoolbar.OnDeleteLine():")
+        self.action = { 'desc' : "deleteLine",
+                        'id'   : self.deleteLine }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnDisplayCats(self, event):
+        """!Display/update categories"""
+        Debug.msg(2, "Digittoolbar.OnDisplayCats():")
+        self.action = { 'desc' : "displayCats",
+                        'id'   : self.displayCats }
+        self.MapWindow.mouse['box'] = 'point'
+
+    def OnDisplayAttr(self, event):
+        """!Display/update attributes"""
+        Debug.msg(2, "Digittoolbar.OnDisplayAttr():")
+        self.action = { 'desc' : "displayAttrs",
+                        'id'   : self.displayAttr }
+        self.MapWindow.mouse['box'] = 'point'
+        
+    def OnUndo(self, event):
+        """!Undo previous changes"""
+        self.digit.Undo()
+        
+        event.Skip()
+
+    def EnableUndo(self, enable = True):
+        """!Enable 'Undo' in toolbar
+        
+        @param enable False for disable
+        """
+        if enable:
+            if self.GetToolEnabled(self.undo) is False:
+                self.EnableTool(self.undo, True)
+        else:
+            if self.GetToolEnabled(self.undo) is True:
+                self.EnableTool(self.undo, False)
+        
+    def OnSettings(self, event):
+        """!Show settings dialog"""
+        if self.digit is None:
+            try:
+                self.digit = self.MapWindow.digit = VDigit(mapwindow = self.MapWindow)
+            except SystemExit:
+                self.digit = self.MapWindow.digit = None
+        
+        if not self.settingsDialog:
+            self.settingsDialog = VDigitSettingsDialog(parent = self.parent, title = _("Digitization settings"),
+                                                       style = wx.DEFAULT_DIALOG_STYLE)
+            self.settingsDialog.Show()
+
+    def OnAdditionalToolMenu(self, event):
+        """!Menu for additional tools"""
+        point = wx.GetMousePosition()
+        toolMenu = wx.Menu()
+        
+        for label, itype, handler, desc in (
+            (_('Break selected lines/boundaries at intersection'),
+             wx.ITEM_CHECK, self.OnBreak, "breakLine"),
+            (_('Connect selected lines/boundaries'),
+             wx.ITEM_CHECK, self.OnConnect, "connectLine"),
+            (_('Copy categories'),
+             wx.ITEM_CHECK, self.OnCopyCats, "copyCats"),
+            (_('Copy features from (background) vector map'),
+             wx.ITEM_CHECK, self.OnCopy, "copyLine"),
+            (_('Copy attributes'),
+             wx.ITEM_CHECK, self.OnCopyAttrb, "copyAttrs"),
+            (_('Feature type conversion'),
+             wx.ITEM_CHECK, self.OnTypeConversion, "typeConv"),
+            (_('Flip selected lines/boundaries'),
+             wx.ITEM_CHECK, self.OnFlip, "flipLine"),
+            (_('Merge selected lines/boundaries'),
+             wx.ITEM_CHECK, self.OnMerge, "mergeLine"),
+            (_('Snap selected lines/boundaries (only to nodes)'),
+             wx.ITEM_CHECK, self.OnSnap, "snapLine"),
+            (_('Split line/boundary'),
+             wx.ITEM_CHECK, self.OnSplitLine, "splitLine"),
+            (_('Query features'),
+             wx.ITEM_CHECK, self.OnQuery, "queryLine"),
+            (_('Z bulk-labeling of 3D lines'),
+             wx.ITEM_CHECK, self.OnZBulk, "zbulkLine")):
+            # Add items to the menu
+            item = wx.MenuItem(parentMenu = toolMenu, id = wx.ID_ANY,
+                               text = label,
+                               kind = itype)
+            toolMenu.AppendItem(item)
+            self.MapWindow.Bind(wx.EVT_MENU, handler, item)
+            if self.action['desc'] == desc:
+                item.Check(True)
+        
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.MapWindow.PopupMenu(toolMenu)
+        toolMenu.Destroy()
+        
+        if self.action['desc'] == 'addPoint':
+            self.ToggleTool(self.additionalTools, False)
+        
+    def OnCopy(self, event):
+        """!Copy selected features from (background) vector map"""
+        if self.action['desc'] == 'copyLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnCopy():")
+        self.action = { 'desc' : "copyLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnSplitLine(self, event):
+        """!Split line"""
+        if self.action['desc'] == 'splitLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnSplitLine():")
+        self.action = { 'desc' : "splitLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'point'
+
+
+    def OnCopyCats(self, event):
+        """!Copy categories"""
+        if self.action['desc'] == 'copyCats': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.copyCats, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnCopyCats():")
+        self.action = { 'desc' : "copyCats",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'point'
+
+    def OnCopyAttrb(self, event):
+        """!Copy attributes"""
+        if self.action['desc'] == 'copyAttrs': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.copyCats, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnCopyAttrb():")
+        self.action = { 'desc' : "copyAttrs",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'point'
+        
+
+    def OnFlip(self, event):
+        """!Flip selected lines/boundaries"""
+        if self.action['desc'] == 'flipLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnFlip():")
+        self.action = { 'desc' : "flipLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnMerge(self, event):
+        """!Merge selected lines/boundaries"""
+        if self.action['desc'] == 'mergeLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnMerge():")
+        self.action = { 'desc' : "mergeLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnBreak(self, event):
+        """!Break selected lines/boundaries"""
+        if self.action['desc'] == 'breakLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnBreak():")
+        self.action = { 'desc' : "breakLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnSnap(self, event):
+        """!Snap selected features"""
+        if self.action['desc'] == 'snapLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnSnap():")
+        self.action = { 'desc' : "snapLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnConnect(self, event):
+        """!Connect selected lines/boundaries"""
+        if self.action['desc'] == 'connectLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnConnect():")
+        self.action = { 'desc' : "connectLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnQuery(self, event):
+        """!Query selected lines/boundaries"""
+        if self.action['desc'] == 'queryLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnQuery(): %s" % \
+                      UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection'))
+        self.action = { 'desc' : "queryLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnZBulk(self, event):
+        """!Z bulk-labeling selected lines/boundaries"""
+        if not self.digit.IsVector3D():
+            GError(parent = self.parent,
+                   message = _("Vector map is not 3D. Operation canceled."))
+            return
+        
+        if self.action['desc'] == 'zbulkLine': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnZBulk():")
+        self.action = { 'desc' : "zbulkLine",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'line'
+
+    def OnTypeConversion(self, event):
+        """!Feature type conversion
+
+        Supported conversions:
+         - point <-> centroid
+         - line <-> boundary
+        """
+        if self.action['desc'] == 'typeConv': # select previous action
+            self.ToggleTool(self.addPoint, True)
+            self.ToggleTool(self.additionalTools, False)
+            self.OnAddPoint(event)
+            return
+        
+        Debug.msg(2, "Digittoolbar.OnTypeConversion():")
+        self.action = { 'desc' : "typeConv",
+                        'id'   : self.additionalTools }
+        self.MapWindow.mouse['box'] = 'box'
+
+    def OnSelectMap (self, event):
+        """!Select vector map layer for editing
+
+        If there is a vector map layer already edited, this action is
+        firstly terminated. The map layer is closed. After this the
+        selected map layer activated for editing.
+        """
+        if event.GetSelection() == 0: # create new vector map layer
+            if self.mapLayer:
+                openVectorMap = self.mapLayer.GetName(fullyQualified = False)['name']
+            else:
+                openVectorMap = None
+            dlg = CreateNewVector(self.parent,
+                                  exceptMap = openVectorMap, log = self.log,
+                                  cmd = (('v.edit',
+                                          { 'flags' : 'b', 'tool' : 'create' },
+                                          'map')),
+                                  disableAdd = True)
+            
+            if dlg and dlg.GetName():
+                # add layer to map layer tree
+                if self.layerTree:
+                    mapName = dlg.GetName() + '@' + grass.gisenv()['MAPSET']
+                    self.layerTree.AddLayer(ltype = 'vector',
+                                            lname = mapName,
+                                            lcmd = ['d.vect', 'map=%s' % mapName])
+                    
+                    vectLayers = self.UpdateListOfLayers(updateTool = True)
+                    selection = vectLayers.index(mapName)
+                
+                # create table ?
+                if dlg.IsChecked('table'):
+                    lmgr = self.parent.GetLayerManager()
+                    if lmgr:
+                        lmgr.OnShowAttributeTable(None, selection = 'table')
+                dlg.Destroy()
+            else:
+                self.combo.SetValue(_('Select vector map'))
+                if dlg:
+                    dlg.Destroy()
+                return
+        else:
+            selection = event.GetSelection() - 1 # first option is 'New vector map'
+        
+        # skip currently selected map
+        if self.layers[selection] == self.mapLayer:
+            return
+        
+        if self.mapLayer:
+            # deactive map layer for editing
+            self.StopEditing()
+        
+        # select the given map layer for editing
+        self.StartEditing(self.layers[selection])
+        
+        event.Skip()
+        
+    def StartEditing (self, mapLayer):
+        """!Start editing selected vector map layer.
+
+        @param mapLayer MapLayer to be edited
+        """
+        # deactive layer
+        self.Map.ChangeLayerActive(mapLayer, False)
+        
+        # clean map canvas
+        self.MapWindow.EraseMap()
+        
+        # unset background map if needed
+        if mapLayer:
+            if UserSettings.Get(group = 'vdigit', key = 'bgmap',
+                                subkey = 'value', internal = True) == mapLayer.GetName():
+                UserSettings.Set(group = 'vdigit', key = 'bgmap',
+                                 subkey = 'value', value = '', internal = True)
+            
+            self.parent.SetStatusText(_("Please wait, "
+                                        "opening vector map <%s> for editing...") % mapLayer.GetName(),
+                                        0)
+        
+        self.MapWindow.pdcVector = wx.PseudoDC()
+        self.digit = self.MapWindow.digit = VDigit(mapwindow = self.MapWindow)
+        
+        self.mapLayer = mapLayer
+        # open vector map
+        if self.digit.OpenMap(mapLayer.GetName()) is None:
+            self.mapLayer = None
+            self.StopEditing()
+            return False
+        
+        # check feature type (only for OGR layers)
+        fType = self.digit.GetFeatureType()
+        self.EnableAll()
+        self.EnableUndo(False)
+        
+        if fType == 'Point':
+            for tool in (self.addLine, self.addBoundary, self.addCentroid,
+                         self.addArea, self.moveVertex, self.addVertex,
+                         self.removeVertex, self.editLine):
+                self.EnableTool(tool, False)
+        elif fType == 'Line String':
+            for tool in (self.addPoint, self.addBoundary, self.addCentroid,
+                         self.addArea):
+                self.EnableTool(tool, False)
+        elif fType == 'Polygon':
+            for tool in (self.addPoint, self.addLine, self.addBoundary, self.addCentroid):
+                self.EnableTool(tool, False)
+        elif fType:
+            GError(parent = self,
+                   message = _("Unsupported feature type '%s'. Unable to edit "
+                               "OGR layer <%s>.") % (fType, mapLayer.GetName()))
+            self.digit.CloseMap()
+            self.mapLayer = None
+            self.StopEditing()
+            return False
+        
+        # update toolbar
+        if self.combo:
+            self.combo.SetValue(mapLayer.GetName())
+        if 'map' in self.parent.toolbars:
+            self.parent.toolbars['map'].combo.SetValue (_('Digitize'))
+        
+        if self.parent.GetName() != "IClassWindow":
+            lmgr = self.parent.GetLayerManager()
+            if lmgr:
+                lmgr.toolbars['tools'].Enable('vdigit', enable = False)
+        
+        Debug.msg (4, "VDigitToolbar.StartEditing(): layer=%s" % mapLayer.GetName())
+        
+        # change cursor
+        if self.MapWindow.mouse['use'] == 'pointer':
+            self.MapWindow.SetCursor(self.parent.cursors["cross"])
+        
+        if not self.MapWindow.resize:
+            self.MapWindow.UpdateMap(render = True)
+        
+        # respect opacity
+        opacity = mapLayer.GetOpacity(float = True)
+        
+        if opacity < 1.0:
+            alpha = int(opacity * 255)
+            self.digit.GetDisplay().UpdateSettings(alpha = alpha)
+        
+        return True
+
+    def StopEditing(self):
+        """!Stop editing of selected vector map layer.
+
+        @return True on success
+        @return False on failure
+        """
+        if self.combo:
+            self.combo.SetValue (_('Select vector map'))
+        
+        # save changes
+        if self.mapLayer:
+            Debug.msg (4, "VDigitToolbar.StopEditing(): layer=%s" % self.mapLayer.GetName())
+            if UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled') is False:
+                if self.digit.GetUndoLevel() > -1:
+                    dlg = wx.MessageDialog(parent = self.parent,
+                                           message = _("Do you want to save changes "
+                                                     "in vector map <%s>?") % self.mapLayer.GetName(),
+                                           caption = _("Save changes?"),
+                                           style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+                    if dlg.ShowModal() == wx.ID_NO:
+                        # revert changes
+                        self.digit.Undo(0)
+                    dlg.Destroy()
+            
+            self.parent.SetStatusText(_("Please wait, "
+                                        "closing and rebuilding topology of "
+                                        "vector map <%s>...") % self.mapLayer.GetName(),
+                                      0)
+            self.digit.CloseMap()
+            
+            lmgr = self.parent.GetLayerManager()
+            if lmgr:
+                lmgr.toolbars['tools'].Enable('vdigit', enable = True)
+                lmgr.GetLogWindow().GetProgressBar().SetValue(0)
+                lmgr.GetLogWindow().WriteCmdLog(_("Editing of vector map <%s> successfully finished") % \
+                                                    self.mapLayer.GetName(),
+                                                switchPage = False)
+            # re-active layer 
+            item = self.parent.tree.FindItemByData('maplayer', self.mapLayer)
+            if item and self.parent.tree.IsItemChecked(item):
+                self.Map.ChangeLayerActive(self.mapLayer, True)
+        
+        # change cursor
+        self.MapWindow.SetCursor(self.parent.cursors["default"])
+        self.MapWindow.pdcVector = None
+        
+        # close dialogs
+        for dialog in ('attributes', 'category'):
+            if self.parent.dialogs[dialog]:
+                self.parent.dialogs[dialog].Close()
+                self.parent.dialogs[dialog] = None
+        
+        del self.digit
+        del self.MapWindow.digit
+        
+        self.mapLayer = None
+        
+        self.MapWindow.redrawAll = True
+        
+        return True
+    
+    def UpdateListOfLayers (self, updateTool = False):
+        """!Update list of available vector map layers.
+        This list consists only editable layers (in the current mapset)
+
+        @param updateTool True to update also toolbar
+        """
+        Debug.msg (4, "VDigitToolbar.UpdateListOfLayers(): updateTool=%d" % \
+                   updateTool)
+        
+        layerNameSelected = None
+         # name of currently selected layer
+        if self.mapLayer:
+            layerNameSelected = self.mapLayer.GetName()
+        
+        # select vector map layer in the current mapset
+        layerNameList = []
+        self.layers = self.Map.GetListOfLayers(l_type = "vector",
+                                                      l_mapset = grass.gisenv()['MAPSET'])
+        
+        for layer in self.layers:
+            if not layer.name in layerNameList: # do not duplicate layer
+                layerNameList.append (layer.GetName())
+        
+        if updateTool: # update toolbar
+            if not self.mapLayer:
+                value = _('Select vector map')
+            else:
+                value = layerNameSelected
+            
+            if not self.comboid:
+                if not self.tools or 'selector' in self.tools:
+                    self.combo = wx.ComboBox(self, id = wx.ID_ANY, value = value,
+                                             choices = [_('New vector map'), ] + layerNameList, size = (80, -1),
+                                             style = wx.CB_READONLY)
+                    self.comboid = self.InsertControl(0, self.combo)
+                    self.parent.Bind(wx.EVT_COMBOBOX, self.OnSelectMap, self.comboid)
+            else:
+                self.combo.SetItems([_('New vector map'), ] + layerNameList)
+            
+            self.Realize()
+        
+        return layerNameList
+
+    def GetLayer(self):
+        """!Get selected layer for editing -- MapLayer instance"""
+        return self.mapLayer
+


Property changes on: grass/trunk/gui/wxpython/vdigit/toolbars.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/vdigit/wxdigit.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/wxvdigit.py)
===================================================================
--- grass/trunk/gui/wxpython/vdigit/wxdigit.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/wxdigit.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1760 @@
+"""!
+ at package vdigit.wxdigit
+
+ at brief wxGUI vector digitizer (base class)
+
+Code based on wxVdigit C++ component from GRASS 6.4.0
+(gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
+
+List of classes:
+ - VDigitError
+ - IVDigit
+
+ at todo Read large amounts of data from Vlib into arrays, which could
+then be processed using NumPy and rendered using glDrawArrays or
+glDrawElements, so no per-line/per-vertex processing in Python. Bulk
+data processing with NumPy is much faster than iterating in Python
+(and NumPy would be an excellent candidate for acceleration via
+e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
+
+(C) 2007-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import grass.script.core as grass
+
+from core.cmd         import GError
+from core.debug       import Debug
+from core.settings    import UserSettings
+from vdigit.wxdisplay import DisplayDriver, GetLastError
+
+try:
+    from grass.lib.gis    import *
+    from grass.lib.vector import *
+    from grass.lib.vedit  import *
+    from grass.lib.dbmi   import *
+except ImportError:
+    pass
+
+class VDigitError:
+    def __init__(self, parent):
+        """!Class for managing error messages of vector digitizer
+
+        @param parent parent window for dialogs
+        """
+        self.parent  = parent
+        self.caption = _('Digitization Error')
+    
+    def NoMap(self, name = None):
+        """!No map for editing"""
+        if name:
+            message = _('Unable to open vector map <%s>.') % name
+        else:
+            message =  _('No vector map open for editing.')
+        GError(message + ' ' + _('Operation cancelled.'),
+               parent  = self.parent,
+               caption = self.caption)
+
+    def WriteLine(self):
+        """!Writing line failed
+        """
+        GError(message = _('Writing new feature failed. '
+                           'Operation cancelled.\n\n'
+                           'Reason: %s') % GetLastError(),
+               parent  = self.parent,
+               caption = self.caption)
+
+    def ReadLine(self, line):
+        """!Reading line failed
+        """
+        GError(message = _('Reading feature id %d failed. '
+                           'Operation cancelled.') % line,
+               parent  = self.parent,
+               caption = self.caption)
+
+    def DbLink(self, dblink):
+        """!No dblink available
+        """
+        GError(message = _('Database link %d not available. '
+                           'Operation cancelled.') % dblink,
+               parent  = self.parent,
+               caption = self.caption)
+
+    def Driver(self, driver):
+        """!Staring driver failed
+        """
+        GError(message = _('Unable to start database driver <%s>. '
+                           'Operation cancelled.') % driver,
+               parent  = self.parent,
+               caption = self.caption)
+
+    def Database(self, driver, database):
+        """!Opening database failed
+        """
+        GError(message = _('Unable to open database <%(db)s> by driver <%(driver)s>. '
+                           'Operation cancelled.') % { 'db' : database, 'driver' : driver},
+               parent  = self.parent,
+               caption = self.caption)
+
+    def DbExecute(self, sql):
+        """!Sql query failed
+        """
+        GError(message = _("Unable to execute SQL query '%s'. "
+                           "Operation cancelled.") % sql,
+               parent  = self.parent,
+               caption = self.caption)
+
+    def DeadLine(self, line):
+        """!Dead line
+        """
+        GError(message = _("Feature id %d is marked as dead. "
+                           "Operation cancelled.") % line,
+               parent  = self.parent,
+               caption = self.caption)
+
+    def FeatureType(self, ftype):
+        """!Unknown feature type
+        """
+        GError(message = _("Unsupported feature type %d. "
+                           "Operation cancelled.") % ftype,
+               parent  = self.parent,
+               caption = self.caption)
+        
+class IVDigit:
+    def __init__(self, mapwindow):
+        """!Base class for vector digitizer (ctypes interface)
+        
+        @parem mapwindow reference for map window (BufferedWindow)
+        """
+        self.poMapInfo   = None      # pointer to Map_info
+        self.mapWindow = mapwindow
+
+        # background map
+        self.bgMapInfo   = Map_info()
+        self.poBgMapInfo = self.popoBgMapInfo = None
+        
+        if not mapwindow.parent.IsStandalone():
+            goutput = mapwindow.parent.GetLayerManager().GetLogWindow()
+            log = goutput.GetLog(err = True)
+            progress = goutput.GetProgressBar()
+        else:
+            log = sys.stderr
+            progress = None
+        
+        self.toolbar = mapwindow.parent.toolbars['vdigit']
+        
+        self._error   = VDigitError(parent = self.mapWindow)
+        
+        self._display = DisplayDriver(device    = mapwindow.pdcVector,
+                                      deviceTmp = mapwindow.pdcTmp,
+                                      mapObj    = mapwindow.Map,
+                                      window    = mapwindow,
+                                      glog      = log,
+                                      gprogress = progress)
+        
+        # GRASS lib
+        self.poPoints = Vect_new_line_struct()
+        self.poCats   = Vect_new_cats_struct()
+        
+        # self.SetCategory()
+        
+        # layer / max category
+        self.cats = dict()
+        
+        self._settings = dict()
+        self.UpdateSettings() # -> self._settings
+        
+        # undo/redo
+        self.changesets = dict()
+        self.changesetCurrent = -1 # first changeset to apply
+        self.changesetEnd     = -1 # last changeset to be applied
+        
+        if self.poMapInfo:
+            self.InitCats()
+        
+    def __del__(self):
+        Debug.msg(1, "IVDigit.__del__()")
+        Vect_destroy_line_struct(self.poPoints)
+        self.poPoints = None
+        Vect_destroy_cats_struct(self.poCats)
+        self.poCats = None
+        
+        if self.poBgMapInfo:
+            Vect_close(self.poBgMapInfo)
+            self.poBgMapInfo = self.popoBgMapInfo = None
+            del self.bgMapInfo
+        
+    def CloseBackgroundMap(self):
+        """!Close background vector map"""
+        if not self.poBgMapInfo:
+            return
+        
+        Vect_close(self.poBgMapInfo)
+        self.poBgMapInfo = self.popoBgMapInfo = None
+        
+    def OpenBackgroundMap(self, bgmap):
+        """!Open background vector map
+
+        @todo support more background maps then only one
+        
+        @param bgmap name of vector map to be opened
+
+        @return pointer to map_info
+        @return None on error
+        """
+        name   = create_string_buffer(GNAME_MAX)
+        mapset = create_string_buffer(GMAPSET_MAX)
+        if not G_name_is_fully_qualified(bgmap, name, mapset):
+            name   = str(bgmap)
+            mapset = str(G_find_vector2(bgmap, ''))
+        else:
+            name   = str(name.value)
+            mapset = str(mapset.value)
+        
+        if (name == Vect_get_name(self.poMapInfo) and \
+                mapset == Vect_get_mapset(self.poMapInfo)):
+            self.poBgMapInfo = self.popoBgMapInfo = None
+            self._error.NoMap(bgmap)
+            return
+        
+        self.poBgMapInfo = pointer(self.bgMapInfo)
+        self.popoBgMapInfo = pointer(self.poBgMapInfo)
+	if Vect_open_old(self.poBgMapInfo, name, mapset) == -1:
+            self.poBgMapInfo = self.popoBgMapInfo = None
+            self._error.NoMap(bgmap)
+            return
+        
+    def _getSnapMode(self):
+        """!Get snapping mode
+
+         - snap to vertex
+         - snap to nodes
+         - no snapping
+        
+        @return snap mode
+        """
+        threshold = self._display.GetThreshold()
+        if threshold > 0.0:
+            if UserSettings.Get(group = 'vdigit', key = 'snapToVertex', subkey = 'enabled'):
+                return SNAPVERTEX
+            else:
+                return SNAP
+        else:
+            return NO_SNAP
+    
+    def _breakLineAtIntersection(self, line, pointsLine, changeset):
+        """!Break given line at intersection
+
+        \param line line id
+        \param pointsLine line geometry
+        \param changeset id
+  
+        \return number of modified lines
+        """
+        if not self._checkMap():
+            return -1
+        
+        if not Vect_line_alive(self.poMapInfo, line):
+            return 0
+        
+        if not pointsLine:
+            if Vect_read_line(self.poMapInfo, self.poPoints, None, line) < 0:
+                self._error.ReadLine(line)
+                return -1
+            points = self.poPoints
+        else:
+            points = pointsLine
+        
+        listLine  = Vect_new_boxlist(0)
+        listRef   = Vect_new_list()
+        listBreak = Vect_new_list()
+    
+        pointsCheck = Vect_new_line_struct()
+    
+        lineBox = bound_box()
+        # find all relevant lines
+        Vect_get_line_box(self.poMapInfo, line, byref(lineBox))
+        Vect_select_lines_by_box(self.poMapInfo, byref(lineBox),
+                                 GV_LINES, listLine)
+    
+        # check for intersection
+        Vect_list_append(listBreak, line)
+        Vect_list_append(listRef, line)
+        for i in range(listLine.contents.n_values):
+            lineBreak = listLine.contents.id[i]
+            if lineBreak == line:
+		continue
+            
+            ltype = Vect_read_line(self.poMapInfo, pointsCheck, None, lineBreak)
+            if not (ltype & GV_LINES):
+                continue
+            
+            if Vect_line_check_intersection(self.poPoints, pointsCheck,
+                                            WITHOUT_Z):
+                Vect_list_append(listBreak, lineBreak)
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        for i in range(listBreak.contents.n_values):
+            self._addActionToChangeset(changeset, listBreak.contents.value[i], add = False)
+        
+        ret = Vect_break_lines_list(self.poMapInfo, listBreak, listRef,
+                                    GV_LINES, None)
+        
+        for i in range(listBreak.contents.n_values):
+            if Vect_line_alive(self.poMapInfo, listBreak.contents.value[i]):
+                self._removeActionFromChangeset(changeset, listBreak.contents.value[i],
+                                                add = False)
+        
+        for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo) + 1):
+            self._addActionToChangeset(changeset, line, add = True)
+        
+        Vect_destroy_line_struct(pointsCheck)
+
+        Vect_destroy_boxlist(listLine)
+        Vect_destroy_list(listBreak)
+        Vect_destroy_list(listRef)
+        
+        return ret
+    
+    def _addActionsBefore(self):
+        """!Register action before operation
+  
+        @return changeset id
+        """
+        changeset = len(self.changesets)
+        for line in self._display.selected['ids']:
+            if Vect_line_alive(self.poMapInfo, line):
+                self._addActionToChangeset(changeset, line, add = False)
+        
+        return changeset
+
+    def _applyChangeset(self, changeset, undo):
+        """!Apply changeset (undo/redo changeset)
+        
+        @param changeset changeset id
+        @param undo True for undo otherwise redo
+
+        @return 1 changeset applied
+        @return 0 changeset not applied
+        @return -1 on error
+        """
+        if changeset < 0 or changeset > len(self.changesets.keys()):
+            return -1
+        
+        if self.changesetEnd < 0:
+            self.changesetEnd = changeset
+            
+        ret = 0
+        actions = self.changesets[changeset]
+        for action in actions: 
+            add = action['add']
+            line = action['line']
+            if (undo and add) or \
+                    (not undo and not add):
+                if Vect_line_alive(self.poMapInfo, line):
+                    Debug.msg(3, "IVDigit._applyChangeset(): changeset=%d, action=add, line=%d -> deleted",
+                              changeset, line)
+                    Vect_delete_line(self.poMapInfo, line)
+                    ret = 1
+                else:
+                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
+                              changeset, line)
+            else: # delete
+                offset = action['offset']
+                if not Vect_line_alive(self.poMapInfo, line):
+                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
+                              changeset, line)
+                    if Vect_restore_line(self.poMapInfo, line, offset) < 0:
+                        return -1
+                    ret = 1
+                else:
+                    Debug.msg(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
+                              changeset, line)
+        
+        return ret
+    
+    def _addActionsAfter(self, changeset, nlines):
+        """!Register action after operation
+
+        @param changeset changeset id
+        @param nline number of lines
+        """
+        for line in self._display.selected['ids']:
+            if Vect_line_alive(self.poMapInfo, line):
+                self._removeActionFromChangeset(changeset, line, add = False)
+        
+        for line in range(nlines + 1, Vect_get_num_lines(self.poMapInfo)):
+            if Vect_line_alive(self.poMapInfo, line):
+                self._addActionToChangeset(changeset, line, add = True)
+        
+    def _addActionToChangeset(self, changeset, line, add):
+        """!Add action to changeset
+        
+        @param changeset id of changeset
+        @param line feature id
+        @param add True to add, otherwise delete
+        """
+        if not self._checkMap():
+            return 
+        
+        if not Vect_line_alive(self.poMapInfo, line):
+            return
+        
+        offset = Vect_get_line_offset(self.poMapInfo, line)
+        
+        if changeset not in self.changesets:
+            self.changesets[changeset] = list()
+            self.changesetCurrent = changeset
+        
+        self.changesets[changeset].append({ 'add'    : add,
+                                            'line'   : line,
+                                            'offset' : offset })
+        
+        Debug.msg(3, "IVDigit._addActionToChangeset(): changeset=%d, add=%d, line=%d, offset=%d",
+                  changeset, add, line, offset)
+        
+    def _removeActionFromChangeset(self, changeset, line, add):
+        """!Remove action from changeset
+        
+        @param changeset changeset id
+        @param line line id
+        @param add True for add, False for delete
+        
+        @return number of actions in changeset
+        @return -1 on error
+        """
+        if changeset not in self.changesets.keys():
+            return -1
+        
+        alist = self.changesets[changeset] 
+        for action in alist:
+            if action['add'] == add and action['line'] == line:
+                alist.remove(action)
+        
+        return len(alist)
+
+    def AddFeature(self, ftype, points):
+        """!Add new feature
+        
+        @param ftype feature type (point, line, centroid, boundary)
+        @param points tuple of points ((x, y), (x, y), ...)
+        
+        @return tuple (number of added features, feature ids)
+        """
+        if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') == 2:
+            layer = -1 # -> no category
+            cat   = -1
+        else:
+            layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value')
+            cat   = self.SetCategory()
+        
+        if ftype == 'point':
+            vtype = GV_POINT
+        elif ftype == 'line':
+            vtype = GV_LINE
+        elif ftype == 'centroid':
+            vtype = GV_CENTROID
+        elif ftype == 'boundary':
+            vtype = GV_BOUNDARY
+        elif ftype == 'area':
+            vtype = GV_AREA
+        else:
+            GError(parent = self.mapWindow,
+                   message = _("Unknown feature type '%s'") % ftype)
+            return (-1, None)
+        
+        if vtype & GV_LINES and len(points) < 2:
+            GError(parent = self.mapWindow,
+                   message = _("Not enough points for line"))
+            return (-1, None)
+        
+        self.toolbar.EnableUndo()
+        
+        return self._addFeature(vtype, points, layer, cat,
+                                self._getSnapMode(), self._display.GetThreshold())
+    
+    def DeleteSelectedLines(self):
+        """!Delete selected features
+
+        @return number of deleted features
+        """
+        deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
+        if not self._checkMap():
+            return -1
+        
+        n_dblinks = Vect_get_num_dblinks(self.poMapInfo)
+        Cats_del = None
+        
+        # collect categories for delete if requested
+        if deleteRec:
+            poCats    = Vect_new_cats_struct()
+            poCatsDel = Vect_new_cats_struct()
+            for i in self._display.selected['ids']:
+                if Vect_read_line(self.poMapInfo, None, poCats, i) < 0:
+                    Vect_destroy_cats_struct(poCatsDel)
+                    self._error.ReadLine(i)
+                    return -1
+                
+                cats = poCats.contents
+                for j in range(cats.n_cats):
+                    Vect_cat_set(poCatsDel, cats.field[j], cats.cat[j])
+            
+            Vect_destroy_cats_struct(poCats)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        nlines = Vedit_delete_lines(self.poMapInfo, poList)
+        Vect_destroy_list(poList)
+        self._display.selected['ids'] = list()
+        
+        if nlines > 0 and deleteRec:
+            handle  = dbHandle()
+            poHandle = pointer(handle)
+            stmt    = dbString()
+            poStmt   = pointer(stmt)
+            
+            for dblink in range(n_dblinks):
+                poFi = Vect_get_dblink(self.poMapInfo, dblink)
+                if poFi is None:
+                    self._error.DbLink(dblink)
+                    return -1
+                
+                Fi = poFi.contents
+                poDriver = db_start_driver(Fi.driver)
+                if poDriver is None:
+                    self._error.Driver(Fi.driver)
+                    return -1
+                
+                db_init_handle(poHandle)
+                db_set_handle(poHandle, Fi.database, None)
+                if db_open_database(poDriver, poHandle) != DB_OK:
+                    self._error.Database(Fi.driver, Fi.database)
+                    return -1
+                
+                db_init_string(poStmt)
+                db_set_string(poStmt, "DELETE FROM %s WHERE" % Fi.table)
+                n_cats = 0;
+                catsDel = poCatsDel.contents
+                for c in range(catsDel.n_cats):
+                    if catsDel.field[c] == Fi.number:
+                        if n_cats > 0:
+                            db_append_string(poStmt, " or")
+                    
+		    db_append_string(poStmt, " %s = %d" % (Fi.key, catsDel.cat[c]))
+		    n_cats += 1
+                
+                Vect_cat_del(poCatsDel, Fi.number)
+                
+                if n_cats and \
+                        db_execute_immediate(poDriver, poStmt) != DB_OK:
+                    self._error.DbExecute(db_get_string(poStmt))
+                    return -1
+                
+                db_close_database(poDriver)
+                db_shutdown_driver(poDriver)
+        
+        if poCatsDel:
+            Vect_destroy_cats_struct(poCatsDel)
+        
+        if nlines > 0:
+            self.toolbar.EnableUndo()
+        
+        return nlines
+
+    def MoveSelectedLines(self, move):
+        """!Move selected features
+
+        @param move direction (x, y)
+        """
+        if not self._checkMap():
+            return -1
+        
+        thresh = self._display.GetThreshold()
+        snap   = self._getSnapMode()
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
+                                  poList,
+                                  move[0], move[1], 0,
+                                  snap, thresh)
+        Vect_destroy_list(poList)
+        
+        if nlines > 0:
+            self._addActionsAfter(changeset, nlines)
+        else:
+            del self.changesets[changeset]
+        
+        if nlines > 0 and self._settings['breakLines']:
+            for i in range(1, nlines):
+                self._breakLineAtIntersection(nlines + i, None, changeset)
+        
+        if nlines > 0:
+            self.toolbar.EnableUndo()
+        
+        return nlines
+
+    def MoveSelectedVertex(self, point, move):
+        """!Move selected vertex of the line
+
+        @param point location point
+        @param move  x,y direction
+        
+        @return id of new feature
+        @return 0 vertex not moved (not found, line is not selected)
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        if len(self._display.selected['ids']) != 1:
+            return -1
+        
+        Vect_reset_line(self.poPoints)
+        Vect_append_point(self.poPoints, point[0], point[1], 0.0)
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        
+        # move only first found vertex in bbox 
+        poList = self._display.GetSelectedIList()
+        moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
+                                  poList, self.poPoints,
+                                  self._display.GetThreshold(type = 'selectThresh'),
+                                  self._display.GetThreshold(),
+                                  move[0], move[1], 0.0,
+                                  1, self._getSnapMode())
+        Vect_destroy_list(poList)
+        
+        if moved > 0:
+            self._addActionsAfter(changeset, nlines)
+        else:
+            del self.changesets[changeset]
+        
+        if moved > 0 and self._settings['breakLines']:
+            self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                          None, changeset)
+        
+        if moved > 0:
+            self.toolbar.EnableUndo()
+        
+        return moved
+
+    def AddVertex(self, coords):
+        """!Add new vertex to the selected line/boundary on position 'coords'
+
+        @param coords coordinates to add vertex
+
+        @return id of new feature
+        @return 0 nothing changed
+        @return -1 on failure
+        """
+        added = self._ModifyLineVertex(coords, add = True)
+        
+        if added > 0:
+            self.toolbar.EnableUndo()
+
+        return added
+
+    def RemoveVertex(self, coords):
+        """!Remove vertex from the selected line/boundary on position 'coords'
+
+        @param coords coordinates to remove vertex
+
+        @return id of new feature
+        @return 0 nothing changed
+        @return -1 on failure
+        """
+        deleted = self._ModifyLineVertex(coords, add = False)
+        
+        if deleted > 0:
+            self.toolbar.EnableUndo()
+
+        return deleted
+
+
+    def SplitLine(self, point):
+        """!Split/break selected line/boundary on given position
+
+        @param point point where to split line
+        
+        @return 1 line modified
+        @return 0 nothing changed
+        @return -1 error
+        """
+        thresh = self._display.GetThreshold('selectThresh')
+        if not self._checkMap():
+            return -1
+        
+        poList  = self._display.GetSelectedIList()
+        Vect_reset_line(self.poPoints)
+        Vect_append_point(self.poPoints, point[0], point[1], 0.0)
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        
+        ret = Vedit_split_lines(self.poMapInfo, poList,
+                                self.poPoints, thresh, None)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        return ret
+
+    def EditLine(self, line, coords):
+        """!Edit existing line/boundary
+
+        @param line feature id to be modified
+        @param coords list of coordinates of modified line
+
+        @return feature id of new line
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        if len(coords) < 2:
+            self.DeleteSelectedLines()
+            return 0
+        
+        if not Vect_line_alive(self.poMapInfo, line):
+            self._error.DeadLine(line)
+            return -1
+        
+        # read original feature
+        ltype = Vect_read_line(self.poMapInfo, None, self.poCats, line)
+        if ltype < 0:
+            self._error.ReadLine(line)
+            return -1
+        
+        # build feature geometry
+        Vect_reset_line(self.poPoints)
+        for p in coords:
+            Vect_append_point(self.poPoints, p[0], p[1], 0.0)
+
+        # apply snapping (node or vertex)
+        snap = self._getSnapMode()
+        if snap != NO_SNAP:
+            modeSnap = not (snap == SNAP)
+            Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo,
+                            int(self.poBgMapInfo is not None),
+                           -1, self.poPoints, self._display.GetThreshold(), modeSnap)
+
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
+                                    self.poPoints, self.poCats)
+        if newline > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        if newline > 0 and self._settings['breakLines']:
+            self._breakLineAtIntersection(newline, None, changeset)
+        
+        return newline
+
+    def FlipLine(self):
+        """!Flip selected lines/boundaries
+
+        @return number of modified lines
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vedit_flip_lines(self.poMapInfo, poList)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        return ret
+
+    def MergeLine(self):
+        """!Merge selected lines/boundaries
+
+        @return number of modified lines
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vedit_merge_lines(self.poMapInfo, poList)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+                
+        return ret
+
+    def BreakLine(self):
+        """!Break selected lines/boundaries
+
+        @return number of modified lines
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vect_break_lines_list(self.poMapInfo, poList, None,
+                                    GV_LINES, None)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+                
+        return ret
+
+    def SnapLine(self):
+        """!Snap selected lines/boundaries
+
+        @return on success
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        Vect_snap_lines_list(self.poMapInfo, poList,
+                             self._display.GetThreshold(), None)
+        Vect_destroy_list(poList)
+        
+        if nlines < Vect_get_num_lines(self.poMapInfo):
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+    def ConnectLine(self):
+        """!Connect selected lines/boundaries
+
+        @return 1 lines connected
+        @return 0 lines not connected
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vedit_connect_lines(self.poMapInfo, poList,
+                                  self._display.GetThreshold())
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        return ret
+        
+    def CopyLine(self, ids = []):
+        """!Copy features from (background) vector map
+
+        @param ids list of line ids to be copied
+
+        @return number of copied features
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        poList = self._display.GetSelectedIList(ids)
+        ret = Vedit_copy_lines(self.poMapInfo, self.poBgMapInfo,
+                               poList)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            changeset = len(self.changesets)
+            for line in (range(nlines + 1, Vect_get_num_lines(self.poMapInfo))):
+                self._addActionToChangeset(changeset, line, add = True)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+
+        if ret > 0 and self.poBgMapInfo and self._settings['breakLines']:
+            for i in range(1, ret):
+                self._breakLineAtIntersection(nlines + i, None, changeset)
+        
+        return ret
+
+    def CopyCats(self, fromId, toId, copyAttrb = False):
+        """!Copy given categories to objects with id listed in ids
+
+        @param cats ids of 'from' feature
+        @param ids  ids of 'to' feature(s)
+
+        @return number of modified features
+        @return -1 on error
+        """
+        if len(fromId) < 1 or len(toId) < 1:
+            return 0
+        
+        poCatsFrom = self.poCats
+        poCatsTo = Vect_new_cats_struct();
+        
+        nlines = 0
+        
+        for fline in fromId:
+            if not Vect_line_alive(self.poMapInfo, fline):
+                continue
+            
+            if Vect_read_line(self.poMapInfo, None, poCatsFrom, fline) < 0:
+                self._error.ReadLine(fline)
+                return -1
+            
+            for tline in toId:
+                if not Vect_line_alive(self.poMapInfo, tline):
+                    continue
+                
+                ltype = Vect_read_line(self.poMapInfo, self.poPoints, poCatsTo, tline)
+                if ltype < 0:
+                    self._error.ReadLine(fline)
+                    return -1
+                
+                catsFrom = poCatsFrom.contents
+                for i in range(catsFrom.n_cats):
+                    if not copyAttrb:
+                        # duplicate category
+                        cat = catsFrom.cat[i]
+                    else:
+                        # duplicate attributes
+                        cat = self.cats[catsFrom.field[i]] + 1
+                        self.cats[catsFrom.field[i]] = cat
+                        poFi = Vect_get_field(self.poMapInfo, catsFrom.field[i])
+                        if not poFi:
+                            self._error.DbLink(i)
+                            return -1
+                        
+                        fi = poFi.contents
+                        driver = db_start_driver(fi.driver)
+                        if not driver:
+                            self._error.Driver(fi.driver)
+                            return -1
+                        
+                        handle = dbHandle()
+                        db_init_handle(byref(handle))
+                        db_set_handle(byref(handle), fi.database, None)
+                        if db_open_database(driver, byref(handle)) != DB_OK:
+                            db_shutdown_driver(driver)
+                            self._error.Database(fi.driver, fi.database)
+                            return -1
+                        
+                        stmt = dbString()
+                        db_init_string(byref(stmt))
+                        db_set_string(byref(stmt),
+                                      "SELECT * FROM %s WHERE %s=%d" % (fi.table, fi.key,
+                                                                        catsFrom.cat[i]))
+                        
+                        cursor = dbCursor()
+                        if db_open_select_cursor(driver, byref(stmt), byref(cursor),
+                                                 DB_SEQUENTIAL) != DB_OK:
+                                db_close_database_shutdown_driver(driver)
+                                return -1
+                        
+                        table = db_get_cursor_table(byref(cursor))
+                        ncols = db_get_table_number_of_columns(table)
+                        
+                        sql = "INSERT INTO %s VALUES (" % fi.table
+                        # fetch the data
+                        more = c_int()
+                        while True:
+                            if db_fetch(byref(cursor), DB_NEXT, byref(more)) != DB_OK:
+                                db_close_database_shutdown_driver(driver)
+                                return -1
+                            if not more.value:
+                                break
+                            
+                            value_string = dbString()
+                            for col in range(ncols):
+                                if col > 0:
+                                    sql += ","
+                                    
+                                column = db_get_table_column(table, col)
+                                if db_get_column_name(column) == fi.key:
+                                    sql += "%d" % cat
+                                    continue
+                                
+                                value = db_get_column_value(column)
+                                db_convert_column_value_to_string(column, byref(value_string))
+                                if db_test_value_isnull(value):
+                                    sql += "NULL"
+                                else:
+                                    ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column))
+                                    if ctype != DB_C_TYPE_STRING:
+                                        sql += db_get_string(byref(value_string))
+                                    else:
+                                        sql += "'%s'" % db_get_string(byref(value_string))
+                        
+                        sql += ")"
+                        db_set_string(byref(stmt), sql)
+                        if db_execute_immediate(driver, byref(stmt)) != DB_OK:
+                            db_close_database_shutdown_driver(driver)
+                            return -1
+                        
+                        db_close_database_shutdown_driver(driver)
+                        G_free(poFi)
+                
+                if Vect_cat_set(poCatsTo, catsFrom.field[i], cat) < 1:
+                    continue
+                
+                if Vect_rewrite_line(self.poMapInfo, tline, ltype, self.poPoints, poCatsTo) < 0:
+                    self._error.WriteLine()
+                    return -1
+                
+                nlines +=1
+        
+        Vect_destroy_cats_struct(poCatsTo)
+        
+        if nlines > 0:
+            self.toolbar.EnableUndo()
+        
+        return nlines
+
+    def _selectLinesByQueryThresh(self):
+        """!Generic method used for SelectLinesByQuery() -- to get
+        threshold value"""
+        thresh = 0.0
+        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
+            thresh = UserSettings.Get(group = 'vdigit', key = 'queryLength', subkey = 'thresh')
+            if UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection') == 0:
+                thresh = -1 * thresh
+        else:
+            thresh = UserSettings.Get(group = 'vdigit', key = 'queryDangle', subkey = 'thresh')
+            if UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection') == 0:
+                thresh = -1 * thresh
+        
+        return thresh
+
+    def SelectLinesByQuery(self, bbox):
+        """!Select features by query
+        
+        @todo layer / 3D
+        
+        @param bbox bounding box definition
+        """
+        if not self._checkMap():
+            return -1
+        
+        thresh = self._selectLinesByQueryThresh()
+        
+        query = QUERY_UNKNOWN
+        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'selection') == 0:
+            query = QUERY_LENGTH
+        else:
+            query = QUERY_DANGLE
+        
+        ftype = GV_POINTS | GV_LINES # TODO: 3D
+        layer = 1 # TODO
+        
+        ids = list()
+        poList = Vect_new_list()
+        coList = poList.contents
+        if UserSettings.Get(group = 'vdigit', key = 'query', subkey = 'box'):
+            Vect_reset_line(self.poPoints)
+            x1, y1 = bbox[0]
+            x2, y2 = bbox[1]
+            z1 = z2 = 0.0
+            
+            Vect_append_point(self.poPoints, x1, y1, z1)
+            Vect_append_point(self.poPoints, x2, y1, z2)
+            Vect_append_point(self.poPoints, x2, y2, z1)
+            Vect_append_point(self.poPoints, x1, y2, z2)
+            Vect_append_point(self.poPoints, x1, y1, z1)
+	
+            Vect_select_lines_by_polygon(self.poMapInfo, self.poPoints, 0, None,
+                                         ftype, poList)
+            
+            if coList.n_values == 0:
+                return ids
+        
+        Vedit_select_by_query(self.poMapInfo,
+                              ftype, layer, thresh, query,
+                              poList)
+        
+        for i in range(coList.n_values):
+            ids.append(int(coList.value[i]))
+            
+        Debug.msg(3, "IVDigit.SelectLinesByQuery(): lines=%d", coList.n_values)    
+        Vect_destroy_list(poList)
+        
+        return ids
+
+    def IsVector3D(self):
+        """!Check if open vector map is 3D
+        """
+        if not self._checkMap():
+            return False
+        
+        return Vect_is_3d(self.poMapInfo)
+    
+    def GetLineLength(self, line):
+        """!Get line length
+
+        @param line feature id
+
+        @return line length
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        if not Vect_line_alive(self.poMapInfo, line):
+            return -1
+    
+        ltype = Vect_read_line(self.poMapInfo, self.poPoints, None, line)
+        if ltype < 0:
+            self._error.ReadLine(line)
+            return ret
+        
+        length = -1
+        if ltype & GV_LINES: # lines & boundaries
+            length = Vect_line_length(self.poPoints)
+        
+        return length
+
+    def GetAreaSize(self, centroid):
+        """!Get area size
+
+        @param centroid centroid id
+
+        @return area size
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
+        if ltype < 0:
+            self._error.ReadLine(line)
+            return ret
+        
+        if ltype != GV_CENTROID:
+            return -1
+        
+        area = Vect_get_centroid_area(self.poMapInfo, centroid)
+        size = -1
+        if area > 0:
+            if not Vect_area_alive(self.poMapInfo, area):
+                return size
+            
+            size = Vect_get_area_area(self.poMapInfo, area)
+        
+        return size
+        
+    def GetAreaPerimeter(self, centroid):
+        """!Get area perimeter
+        
+        @param centroid centroid id
+        
+        @return area size
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        ltype = Vect_read_line(self.poMapInfo, None, None, centroid)
+        if ltype < 0:
+            self._error.ReadLine(line)
+            return ret
+        
+        if ltype != GV_CENTROID:
+            return -1
+        
+        area = Vect_get_centroid_area(self.poMapInfo, centroid)
+        perimeter = -1
+        if area > 0:
+            if not Vect_area_alive(self.poMapInfo, area):
+                return -1
+            
+            Vect_get_area_points(self.poMapInfo, area, self.poPoints)
+            perimeter = Vect_area_perimeter(self.poPoints)
+        
+        return perimeter
+    
+    def SetLineCats(self, line, layer, cats, add = True):
+        """!Set categories for given line and layer
+
+        @param line feature id
+        @param layer layer number (-1 for first selected line)
+        @param cats list of categories
+        @param add if True to add, otherwise do delete categories
+
+        @return new feature id (feature need to be rewritten)
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        if line < 1 and len(self._display.selected['ids']) < 1:
+            return -1
+        
+        update = False
+        if line == -1:
+            update = True
+            line = self._display.selected['ids'][0]
+	
+        if not Vect_line_alive(self.poMapInfo, line):
+            return -1
+        
+        ltype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
+        if ltype < 0:
+            self._error.ReadLine(line)
+            return -1
+        
+        for c in cats:
+            if add:
+                Vect_cat_set(self.poCats, layer, c)
+            else:
+                Vect_field_cat_del(self.poCats, layer, c)
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        changeset = self._addActionsBefore()
+        newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
+                                    self.poPoints, self.poCats)
+        
+        if newline > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        
+        if update:
+            # update line id since the line was rewritten
+            self._display.selected['ids'][0] =  newline
+        
+        return newline
+
+    def TypeConvForSelectedLines(self):
+        """!Feature type conversion for selected objects.
+
+        Supported conversions:
+         - point <-> centroid
+         - line <-> boundary
+
+        @return number of modified features
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vedit_chtype_lines(self.poMapInfo, poList)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        return ret
+
+    def Undo(self, level = -1):
+        """!Undo action
+
+        @param level levels to undo (0 to revert all)
+
+        @return id of current changeset
+        """
+        changesetLast = len(self.changesets.keys()) - 1
+
+        if changesetLast < 0:
+            return changesetLast
+        
+        if self.changesetCurrent == -2: # value uninitialized 
+            self.changesetCurrent = changesetLast
+            
+        if level > 0 and self.changesetCurrent < 0:
+            self.changesetCurrent = 0
+        
+        if level == 0:
+            # 0 -> undo all
+            level = -1 * changesetLast + 1
+
+        Debug.msg(2, "Digit.Undo(): changeset_last=%d, changeset_current=%d, level=%d",
+                  changesetLast, self.changesetCurrent, level)
+    
+        if level < 0: # undo
+            if self.changesetCurrent + level < -1:
+                return changesetCurrent;
+            for changeset in range(self.changesetCurrent, self.changesetCurrent + level, -1):
+                self._applyChangeset(changeset, undo = True)
+        elif level > 0: # redo 
+            if self.changesetCurrent + level > len(self.changesets.keys()):
+                return self.changesetCurrent
+            for changeset in range(self.changesetCurrent, self.changesetCurrent + level):
+                self._applyChangeset(changeset, undo = False)
+        
+        self.changesetCurrent += level
+
+        Debug.msg(2, "Digit.Undo(): changeset_current=%d, changeset_last=%d, changeset_end=%d",
+                  self.changesetCurrent, changesetLast, self.changesetEnd)
+        
+        if self.changesetCurrent == self.changesetEnd:
+            self.changesetEnd = changesetLast
+            return -1
+        
+        self.mapWindow.UpdateMap(render = False)
+        
+        if self.changesetCurrent < 0: # disable undo tool
+            self.toolbar.EnableUndo(False)
+
+    def ZBulkLines(self, pos1, pos2, start, step):
+        """!Z-bulk labeling
+
+        @param pos1 reference line (start point)
+        @param pos1 reference line (end point)
+        @param start starting value
+        @param step step value
+
+        @return number of modified lines
+        @return -1 on error
+        """
+        if not self._checkMap():
+            return -1
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        
+        # register changeset
+        changeset = self._addActionsBefore()
+        
+        poList = self._display.GetSelectedIList()
+        ret = Vedit_bulk_labeling(self.poMapInfo, poList,
+                                  pos1[0], pos1[1], pos2[0], pos2[1],
+                                  start, step)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+            self.toolbar.EnableUndo()
+        else:
+            del self.changesets[changeset]
+        
+        return ret
+    
+    def GetDisplay(self):
+        """!Get display driver instance"""
+        return self._display
+    
+    def OpenMap(self, name):
+        """!Open vector map for editing
+        
+        @param map name of vector map to be set up
+        """
+        Debug.msg (3, "AbstractDigit.SetMapName map=%s" % name)
+
+        if '@' in name:
+            name, mapset = name.split('@')
+        else:
+            mapset = grass.gisenv()['MAPSET']
+        
+        self.poMapInfo = self._display.OpenMap(str(name), str(mapset), True)
+        
+        if self.poMapInfo:
+            self.InitCats()
+        
+        return self.poMapInfo
+    
+    def CloseMap(self):
+        """!Close currently open vector map
+        """
+        if not self._checkMap():
+            return
+        
+        self._display.CloseMap()
+
+    def InitCats(self):
+        """!Initialize categories information
+        
+        @return 0 on success
+        @return -1 on error
+        """
+        self.cats.clear()
+        if not self._checkMap():
+            return -1
+        
+        ndblinks = Vect_get_num_dblinks(self.poMapInfo)
+        for i in range(ndblinks):
+            fi = Vect_get_dblink(self.poMapInfo, i).contents
+            if fi:
+                self.cats[fi.number] = None
+        
+        # find max category
+        nfields = Vect_cidx_get_num_fields(self.poMapInfo)
+        Debug.msg(2, "wxDigit.InitCats(): nfields=%d", nfields)
+        
+        for i in range(nfields):
+            field = Vect_cidx_get_field_number(self.poMapInfo, i)
+            ncats = Vect_cidx_get_num_cats_by_index(self.poMapInfo, i)
+            if field <= 0:
+                continue
+            for j in range(ncats):
+                cat = c_int()
+                type = c_int()
+                id = c_int()
+                Vect_cidx_get_cat_by_index(self.poMapInfo, i, j,
+                                           byref(cat), byref(type), byref(id))
+                if field in self.cats:
+                    if cat > self.cats[field]:
+                        self.cats[field] = cat.value
+                else:
+                    self.cats[field] = cat.value
+            Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
+            
+        # set default values
+        for field, cat in self.cats.iteritems():
+            if cat == None:
+                self.cats[field] = 0 # first category 1
+	    Debug.msg(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, self.cats[field])
+        
+    def _checkMap(self):
+        """!Check if map is open
+        """
+        if not self.poMapInfo:
+            self._error.NoMap()
+            return False
+        
+        return True
+
+    def _addFeature(self, ftype, coords, layer, cat, snap, threshold):
+        """!Add new feature(s) to the vector map
+
+        @param ftype feature type (GV_POINT, GV_LINE, GV_BOUNDARY, ...)
+        @coords tuple of coordinates ((x, y), (x, y), ...)
+        @param layer layer number (-1 for no cat)
+        @param cat category number
+        @param snap snap to node/vertex
+        @param threshold threshold for snapping
+        
+        @return tuple (number of added features, list of fids)
+        @return number of features -1 on error
+        """
+        fids = list()
+        if not self._checkMap():
+            return (-1, None)
+        
+        is3D = bool(Vect_is_3d(self.poMapInfo))
+        
+        Debug.msg(2, "IVDigit._addFeature(): npoints=%d, layer=%d, cat=%d, snap=%d",
+                  len(coords), layer, cat, snap)
+        
+        if not (ftype & (GV_POINTS | GV_LINES | GV_AREA)): # TODO: 3D
+            self._error.FeatureType(ftype)
+            return (-1, None)
+        
+        # set category
+        Vect_reset_cats(self.poCats)
+        if layer > 0 and ftype != GV_AREA:
+            Vect_cat_set(self.poCats, layer, cat)
+            self.cats[layer] = max(cat, self.cats.get(layer, 1))
+        
+        # append points
+        Vect_reset_line(self.poPoints)
+        for c in coords:
+            Vect_append_point(self.poPoints, c[0], c[1], 0.0)
+        
+        if ftype & (GV_BOUNDARY | GV_AREA):
+            # close boundary
+            points = self.poPoints.contents
+            last = points.n_points - 1
+            if Vect_points_distance(points.x[0], points.x[0], points.z[0],
+                                    points.x[last], points.x[last], points.z[last],
+                                    is3D) <= threshold:
+                points.x[last] = points.x[0]
+                points.y[last] = points.y[0]
+                points.z[last] = points.z[0]
+        
+        if snap != NO_SNAP:
+            # apply snapping (node or vertex)
+            modeSnap = not (snap == SNAP)
+            Vedit_snap_line(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
+                            -1, self.poPoints, threshold, modeSnap)
+        
+        if ftype == GV_AREA:
+            ltype = GV_BOUNDARY
+        else:
+            ltype = ftype
+        newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats)
+        if newline < 0:
+            self._error.WriteLine()
+            return (-1, None)
+        else:
+            fids.append(newline)
+        
+        left = right = -1
+        if ftype & GV_AREA:
+            # add centroids for left/right area
+            bpoints = Vect_new_line_struct()
+            cleft = c_int()
+            cright = c_int()
+            
+            Vect_get_line_areas(self.poMapInfo, newline,
+                                byref(cleft), byref(cright))
+            left = cleft.value
+            right = cright.value
+            
+            # check if area exists and has no centroid inside
+            if layer > 0 and (left > 0 or right > 0):
+                Vect_cat_set(self.poCats, layer, cat)
+                self.cats[layer] = max(cat, self.cats.get(layer, 0))
+            
+            x = c_double()
+            y = c_double()
+            if left > 0 and \
+                    Vect_get_area_centroid(self.poMapInfo, left) == 0:
+                # if Vect_get_area_points(self.poMapInfo, left, bpoints) > 0 and
+                # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
+                if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
+                    Vect_reset_line(bpoints)
+                    Vect_append_point(bpoints, x.value, y.value, 0.0)
+                    newline = Vect_write_line(self.poMapInfo, GV_CENTROID,
+                                              bpoints, self.poCats)
+                    if newline < 0:
+                        self._error.WriteLine()
+                        return (len(fids), fids)
+                    else:
+                        fids.append(newline)
+                    
+            if right > 0 and \
+                    Vect_get_area_centroid(self.poMapInfo, right) == 0:
+                # if Vect_get_area_points(byref(self.poMapInfo), right, bpoints) > 0 and 
+                # Vect_find_poly_centroid(bpoints, byref(x), byref(y)) == 0:
+                if Vect_get_point_in_area(self.poMapInfo, left, byref(x), byref(y)) == 0:
+                    Vect_reset_line(bpoints)
+                    Vect_append_point(bpoints, x.value, y.value, 0.0)
+                    newline =  Vect_write_line(self.poMapInfo, GV_CENTROID,
+                                               bpoints, self.poCats)
+                    if newline < 0:
+                        self._error.WriteLine()
+                        return (len(fids, fids))
+                    else:
+                        fids.append(newline)
+                    
+            Vect_destroy_line_struct(bpoints)
+        
+        # register changeset
+        changeset = len(self.changesets)
+        self._addActionToChangeset(changeset, newline, add = True)
+        
+        # break at intersection
+        if self._settings['breakLines']:
+            self._breakLineAtIntersection(newline, self.poPoints, changeset)
+        
+        return (len(fids), fids)
+    
+    def _ModifyLineVertex(self, coords, add = True):
+        """!Add or remove vertex
+        
+        Shape of line/boundary is not changed when adding new vertex.
+        
+        @param coords coordinates of point
+        @param add True to add, False to remove
+        
+        @return id id of the new feature
+        @return 0 nothing changed
+        @return -1 error
+        """
+        if not self._checkMap():
+            return -1
+        
+        selected = self._display.selected
+        if len(selected['ids']) != 1:
+            return 0
+        
+        poList  = self._display.GetSelectedIList()
+        Vect_reset_line(self.poPoints)
+        Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
+        
+        nlines = Vect_get_num_lines(self.poMapInfo)
+        thresh = self._display.GetThreshold(type = 'selectThresh')
+        
+        changeset = self._addActionsBefore()
+        
+        if add:
+            ret = Vedit_add_vertex(self.poMapInfo, poList,
+                                   self.poPoints, thresh)
+        else:
+            ret = Vedit_remove_vertex(self.poMapInfo, poList,
+                                      self.poPoints, thresh)
+        Vect_destroy_list(poList)
+        
+        if ret > 0:
+            self._addActionsAfter(changeset, nlines)
+        else:
+            del self.changesets[changeset]
+        
+        if not add and ret > 0 and self._settings['breakLines']:
+            self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                          None, changeset)
+                
+        return nlines + 1 # feature is write at the end of the file
+    
+    def GetLineCats(self, line):
+        """!Get list of layer/category(ies) for selected feature.
+
+        @param line feature id (-1 for first selected feature)
+
+        @return list of layer/cats
+        """
+        ret = dict()
+        if not self._checkMap():
+            return ret
+        
+        if line == -1 and len(self._display.selected['ids']) < 1:
+            return ret
+        
+        if line == -1:
+            line = self._display.selected['ids'][0]
+            
+        if not Vect_line_alive(self.poMapInfo, line):
+            self._error.DeadLine(line)
+            return ret
+        
+        if Vect_read_line(self.poMapInfo, None, self.poCats, line) < 0:
+            self._error.ReadLine(line)
+            return ret
+        
+        cats = self.poCats.contents
+        for i in range(cats.n_cats):
+            field = cats.field[i]
+            if field not in ret:
+                ret[field] = list()
+            ret[field].append(cats.cat[i])
+        
+        return ret
+
+    def GetLayers(self):
+        """!Get list of layers
+        
+        Requires self.InitCats() to be called.
+
+        @return list of layers
+        """
+        return self.cats.keys()
+    
+    def UpdateSettings(self):
+        """!Update digit (and display) settings
+        """
+        self._display.UpdateSettings()
+        
+        self._settings['breakLines']  = bool(UserSettings.Get(group = 'vdigit', key = "breakLines",
+                                                              subkey = 'enabled'))
+        
+    def SetCategory(self):
+        """!Update self.cats based on settings"""
+        sel = UserSettings.Get(group = 'vdigit', key = 'categoryMode', subkey = 'selection')
+        cat = None
+        if sel == 0: # next to usep
+            cat = self._setCategoryNextToUse()
+        elif sel == 1:
+            cat = UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')
+        
+        if cat:
+            layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
+            self.cats[layer] = cat
+        
+        return cat
+    
+    def _setCategoryNextToUse(self):
+        """!Find maximum category number for the given layer and
+        update the settings
+
+        @return category to be used
+        """
+        # get max category number for given layer and update the settings
+        layer = UserSettings.Get(group = 'vdigit', key = 'layer', subkey = 'value')
+        cat = self.cats.get(layer, 0) + 1
+        UserSettings.Set(group = 'vdigit', key = 'category', subkey = 'value',
+                         value = cat)
+        Debug.msg(1, "IVDigit._setCategoryNextToUse(): cat=%d", cat)
+        
+        return cat
+
+    def SelectLinesFromBackgroundMap(self, bbox):
+        """!Select features from background map
+
+        @param bbox bounding box definition
+        
+        @return list of selected feature ids
+        """
+        # try select features by box first
+        if self._display.SelectLinesByBox(bbox, poMapInfo = self.poBgMapInfo) < 1:
+            self._display.SelectLineByPoint(bbox[0], poMapInfo = self.poBgMapInfo)['line']
+            
+        return self._display.selected['ids']
+        
+    def GetUndoLevel(self):
+        """!Get undo level (number of active changesets)
+        
+        Note: Changesets starts wiht 0
+        """
+        return self.changesetCurrent
+    
+    def GetFeatureType(self):
+        """!Get feature type for OGR layers
+
+        @return feature type as string (Point, Line String, Polygon)
+        @return None for native format
+        """
+        return Vect_get_ogr_geometry_type(self.poMapInfo)
+        

Copied: grass/trunk/gui/wxpython/vdigit/wxdisplay.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/wxvdriver.py)
===================================================================
--- grass/trunk/gui/wxpython/vdigit/wxdisplay.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/wxdisplay.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1013 @@
+"""!
+ at package vdigit.wxdisplay
+
+ at brief wxGUI vector digitizer (display driver)
+
+Code based on wxVdigit C++ component from GRASS 6.4.0
+(gui/wxpython/vdigit). Converted to Python in 2010/12-2011/01.
+
+List of classes:
+ - DisplayDriver
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import locale
+
+import wx
+
+from core.debug    import Debug
+from core.settings import UserSettings
+
+try:
+    from grass.lib.gis    import *
+    from grass.lib.vector import *
+    from grass.lib.vedit  import *
+except ImportError:
+    pass
+
+log       = None
+progress  = None
+last_error = ''
+
+def print_error(msg, type):
+    """!Redirect stderr"""
+    global log
+    if log:
+        log.write(msg)
+    else:
+        print msg
+    global last_error
+    last_error += ' ' + msg
+
+    return 0
+
+def print_progress(value):
+    """!Redirect progress info"""
+    global progress
+    if progress:
+        progress.SetValue(value)
+    else:
+        print value
+    
+    return 0
+
+def GetLastError():
+    global last_error
+    ret = last_error
+    if ret[-1] != '.':
+        ret += '.'
+    
+    last_error = '' # reset
+    
+    return ret
+
+errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
+errfunc = errtype(print_error)
+pertype = CFUNCTYPE(UNCHECKED(c_int), c_int)
+perfunc = pertype(print_progress)
+
+class DisplayDriver:
+    def __init__(self, device, deviceTmp, mapObj, window, glog, gprogress):
+        """!Display driver used by vector digitizer
+        
+        @param device    wx.PseudoDC device where to draw vector objects
+        @param deviceTmp wx.PseudoDC device where to draw temporary vector objects
+        @param mapOng    Map Object (render.Map)
+        @param windiow   parent window for dialogs
+        @param glog      logging device (None to discard messages)
+        @param gprogress progress bar device (None to discard message)
+        """
+        global errfunc, perfunc, log, progress
+        log = glog
+        progress = gprogress
+        
+        G_gisinit('wxvdigit')
+        locale.setlocale(locale.LC_NUMERIC, 'C')
+        G_set_error_routine(errfunc) 
+        G_set_percent_routine(perfunc)
+        # G_set_fatal_error(FATAL_RETURN)
+        
+        self.mapInfo   = None     # open vector map (Map_Info structure)
+        self.poMapInfo = None     # pointer to self.mapInfo
+        self.is3D      = False    # is open vector map 3D
+        
+        self.dc      = device     # PseudoDC devices
+        self.dcTmp   = deviceTmp
+        self.mapObj  = mapObj
+        self.region  = mapObj.GetCurrentRegion()
+        self.window  = window
+        self.log     = log        # log device
+
+        self.firstNode = True     # track PseudoDC Id of selected features
+        self.lastNodeId = -1
+        
+        # GRASS lib
+        self.poPoints = Vect_new_line_struct()
+        self.poCats   = Vect_new_cats_struct()
+        
+        # selected objects
+        self.selected = {
+            'field'   : -1,      # field number
+            'cats'    : list(),  # list of cats
+            'ids'     : list(),  # list of ids
+            'idsDupl' : list(),  # list of duplicated features
+            }
+        
+        # digitizer settings
+        self.settings = {
+            'highlight'     : None,
+            'highlightDupl' : { 'enabled' : False,
+                                'color'   : None },
+            'point'         : { 'enabled' : False,
+                                'color'   : None },
+            'line'          : { 'enabled' : False,
+                                'color'   : None },
+            'boundaryNo'    : { 'enabled' : False,
+                                'color'   : None },
+            'boundaryOne'   : { 'enabled' : False,
+                                'color'   : None },
+            'boundaryTwo'   : { 'enabled' : False,
+                                'color'   : None },
+            'centroidIn'    : { 'enabled' : False,
+                                'color'   : None },
+            'centroidOut'   : { 'enabled' : False,
+                                'color'   : None },
+            'centroidDup'   : { 'enabled' : False,
+                                'color'   : None },
+            'nodeOne'       : { 'enabled' : False,
+                                'color'   : None },
+            'nodeTwo'       : { 'enabled' : False,
+                                'color'   : None },
+            'vertex'        : { 'enabled' : False,
+                                'color'   : None },
+            'area'          : { 'enabled' : False,
+                                'color'   : None },
+            'direction'     : { 'enabled' : False,
+                                'color'   : None },
+            'lineWidth'     : -1,    # screen units 
+            }
+        
+        # topology
+        self._resetTopology()
+        
+        self._drawSelected = False
+        self._drawSegments = False
+        
+        self.UpdateSettings()
+        
+    def __del__(self):
+        """!Close currently open vector map"""
+        G_unset_error_routine()
+        G_unset_percent_routine()
+        
+        if self.poMapInfo:
+            self.CloseMap()
+        
+        Vect_destroy_line_struct(self.poPoints)
+        Vect_destroy_cats_struct(self.poCats)
+
+    def _resetTopology(self):
+        """!Reset topology dict
+        """
+        self.topology = {
+            'highlight'   : 0,
+            'point'       : 0,
+            'line'        : 0,
+            'boundaryNo'  : 0,
+            'boundaryOne' : 0,
+            'boundaryTwo' : 0,
+            'centroidIn'  : 0,
+            'centroidOut' : 0,
+            'centroidDup' : 0,
+            'nodeOne'     : 0,
+            'nodeTwo'     : 0,
+            'vertex'      : 0,
+            }
+        
+    def _cell2Pixel(self, east, north, elev):
+        """!Conversion from geographic coordinates (east, north)
+        to screen (x, y)
+  
+        @todo 3D stuff...
+
+        @param east, north, elev geographical coordinates
+
+        @return x, y screen coordinates (integer)
+        """
+        map_res = max(self.region['ewres'], self.region['nsres'])
+        w = self.region['center_easting']  - (self.mapObj.width  / 2) * map_res
+        n = self.region['center_northing'] + (self.mapObj.height / 2) * map_res
+        
+        return int((east - w) / map_res), int((n - north) / map_res)
+    
+    def _drawCross(self, pdc, point, size = 5):
+        """!Draw cross symbol of given size to device content
+   
+        Used for points, nodes, vertices
+
+        @param[in,out] PseudoDC where to draw
+        @param point coordinates of center
+        @param size size of the cross symbol
+   
+        @return 0 on success
+        @return -1 on failure
+        """
+        if not pdc or not point:
+            return -1
+        
+        pdc.DrawLine(point.x - size, point.y, point.x + size, point.y)
+        pdc.DrawLine(point.x, point.y - size, point.x, point.y + size)
+        
+        return 0
+    
+    def _drawObject(self, robj):
+        """!Draw given object to the device
+        
+        The object is defined as robject() from vedit.h.
+        
+        @param robj object to be rendered
+        
+        @return  1 on success
+        @return -1 on failure (vector feature marked as dead, etc.)
+        """
+        if not self.dc or not self.dcTmp:
+            return -1
+        
+        Debug.msg(3, "_drawObject(): type=%d npoints=%d", robj.type, robj.npoints)
+        brush = None
+        if self._isSelected(robj.fid):
+            pdc = self.dcTmp
+            if self.settings['highlightDupl']['enabled'] and self._isDuplicated(robj.fid):
+                pen = wx.Pen(self.settings['highlightDupl']['color'], self.settings['lineWidth'], wx.SOLID)
+            else:            
+                pen = wx.Pen(self.settings['highlight'], self.settings['lineWidth'], wx.SOLID)
+            
+            dcId = 1
+            self.topology['highlight'] += 1
+            if not self._drawSelected:
+                return
+        else:
+            pdc = self.dc
+            pen, brush = self._definePen(robj.type)
+            dcId = 0
+        
+        pdc.SetPen(pen)        
+        if brush:
+            pdc.SetBrush(brush)
+        
+        if robj.type & (TYPE_POINT | TYPE_CENTROIDIN | TYPE_CENTROIDOUT | TYPE_CENTROIDDUP |
+                        TYPE_NODEONE | TYPE_NODETWO | TYPE_VERTEX): # -> point
+            if dcId > 0:
+                if robj.type == TYPE_VERTEX:
+                    dcId = 3 # first vertex
+                elif robj.type & (TYPE_NODEONE | TYPE_NODETWO):
+                    if self.firstNode:
+                        dcId = 1
+                        self.firstNode = False
+                    else:
+                        dcId = self.lastNodeId
+            
+            for i in range(robj.npoints):
+                p = robj.point[i]
+                if dcId > 0:
+                    pdc.SetId(dcId)
+                    dcId += 2
+                self._drawCross(pdc, p)
+        else:
+            if dcId > 0 and self._drawSegments:
+                self.fisrtNode = True
+                self.lastNodeId = robj.npoints * 2 - 1
+                dcId = 2 # first segment
+                i = 0
+                while i < robj.npoints - 1:
+                    point_beg = wx.Point(robj.point[i].x, robj.point[i].y)
+                    point_end = wx.Point(robj.point[i+1].x, robj.point[i+1].y)
+                    pdc.SetId(dcId) # set unique id & set bbox for each segment
+                    pdc.SetPen(pen)
+                    pdc.SetIdBounds(dcId - 1, wx.Rect(point_beg.x, point_beg.y, 0, 0))
+                    pdc.SetIdBounds(dcId, wx.RectPP(point_beg, point_end))
+                    pdc.DrawLine(point_beg.x, point_beg.y,
+                                 point_end.x, point_end.y)
+                    i    += 1
+                    dcId += 2
+                pdc.SetIdBounds(dcId - 1, wx.Rect(robj.point[robj.npoints - 1].x,
+                                                  robj.point[robj.npoints - 1].y,
+                                                  0, 0))
+            else:
+                points = list()
+                for i in range(robj.npoints):
+                    p = robj.point[i]
+                    points.append(wx.Point(p.x, p.y))
+                    
+                if robj.type == TYPE_AREA:
+                    pdc.DrawPolygon(points)
+                else:
+                    pdc.DrawLines(points)
+        
+    def _definePen(self, rtype):
+        """!Define pen/brush based on rendered object)
+        
+        Updates also self.topology dict
+
+        @return pen, brush
+        """
+        if rtype == TYPE_POINT:
+            key = 'point'
+        elif rtype == TYPE_LINE:
+            key = 'line'
+        elif rtype == TYPE_BOUNDARYNO:
+            key = 'boundaryNo'
+        elif rtype == TYPE_BOUNDARYTWO:
+            key = 'boundaryTwo'
+        elif rtype == TYPE_BOUNDARYONE:
+            key = 'boundaryOne'
+        elif rtype == TYPE_CENTROIDIN:
+            key = 'centroidIn'
+        elif rtype == TYPE_CENTROIDOUT:
+            key = 'centroidOut'
+        elif rtype == TYPE_CENTROIDDUP:
+            key = 'centroidDup'
+        elif rtype == TYPE_NODEONE:
+            key = 'nodeOne'
+        elif rtype == TYPE_NODETWO:
+            key = 'nodeTwo'
+        elif rtype == TYPE_VERTEX:
+            key = 'vertex'
+        elif rtype == TYPE_AREA:
+            key = 'area' 
+        elif rtype == TYPE_ISLE:
+            key = 'isle'
+        elif rtype == TYPE_DIRECTION:
+            key = 'direction'
+        
+        if key not in ('direction', 'area', 'isle'):
+            self.topology[key] += 1
+        
+        if key in ('area', 'isle'):
+            pen = wx.TRANSPARENT_PEN
+            if key == 'area':
+                brush = wx.Brush(self.settings[key]['color'], wx.SOLID)
+            else:
+                brush = wx.TRANSPARENT_BRUSH
+        else:
+            pen = wx.Pen(self.settings[key]['color'], self.settings['lineWidth'], wx.SOLID)
+            brush = None
+        
+        return pen, brush
+        
+    def _getDrawFlag(self):
+        """!Get draw flag from the settings
+        
+        See vedit.h for list of draw flags.
+        
+        @return draw flag (int)
+        """
+        ret = 0
+        if self.settings['point']['enabled']:
+            ret |= DRAW_POINT
+        if self.settings['line']['enabled']:
+            ret |= DRAW_LINE
+        if self.settings['boundaryNo']['enabled']:
+            ret |= DRAW_BOUNDARYNO
+        if self.settings['boundaryTwo']['enabled']:
+            ret |= DRAW_BOUNDARYTWO
+        if self.settings['boundaryOne']['enabled']:
+            ret |= DRAW_BOUNDARYONE
+        if self.settings['centroidIn']['enabled']:
+            ret |= DRAW_CENTROIDIN
+        if self.settings['centroidOut']['enabled']:
+            ret |= DRAW_CENTROIDOUT
+        if self.settings['centroidDup']['enabled']:
+            ret |= DRAW_CENTROIDDUP
+        if self.settings['nodeOne']['enabled']:
+            ret |= DRAW_NODEONE
+        if self.settings['nodeTwo']['enabled']:
+            ret |= DRAW_NODETWO
+        if self.settings['vertex']['enabled']:
+            ret |= DRAW_VERTEX
+        if self.settings['area']['enabled']:
+            ret |= DRAW_AREA
+        if self.settings['direction']['enabled']:
+            ret |= DRAW_DIRECTION
+        
+        return ret
+        
+    def _isSelected(self, line, force = False):
+        """!Check if vector object selected?
+   
+        @param line feature id
+
+        @return True if vector object is selected
+        @return False if vector object is not selected
+        """
+        if len(self.selected['cats']) < 1 or force:
+            # select by id
+            if line in self.selected['ids']:
+                return True
+        else: 
+            # select by cat
+            cats = self.poCats.contents
+            for i in range(cats.n_cats):
+                if cats.field[i] == self.selected['field'] and \
+                        cats.cat[i] in self.selected['cats']:
+                    # remember id
+                    # -> after drawing all features selected.cats is reseted */
+                    self.selected['ids'].append(line)
+                    return True
+        
+        return False
+
+    def _isDuplicated(self, line):
+        """!Check for already marked duplicates
+        
+        @param line feature id
+
+        @return True line already marked as duplicated
+        @return False not duplicated
+        """
+        return line in self.selected['idsDupl']
+    
+    def _getRegionBox(self):
+        """!Get bound_box() from current region
+
+        @return bound_box
+        """
+        box = bound_box()
+        
+        box.N = self.region['n']
+        box.S = self.region['s']
+        box.E = self.region['e']
+        box.W = self.region['w']
+        box.T = PORT_DOUBLE_MAX
+        box.B = -PORT_DOUBLE_MAX
+        
+        return box
+
+    def DrawMap(self, force = False):
+        """!Draw content of the vector map to the device
+        
+        @param force force drawing
+        @return number of drawn features
+        @return -1 on error
+        """
+        Debug.msg(1, "DisplayDriver.DrawMap(): force=%d", force)
+        
+        if not self.poMapInfo or not self.dc or not self.dcTmp:
+            return -1
+        
+        try:
+            rlist = Vedit_render_map(self.poMapInfo, byref(self._getRegionBox()), self._getDrawFlag(),
+                                     self.region['center_easting'], self.region['center_northing'],
+                                     self.mapObj.width, self.mapObj.height,
+                                     max(self.region['nsres'], self.region['ewres'])).contents
+        except SystemExit:
+            pass
+        
+        self._resetTopology()
+        
+        self.dc.BeginDrawing()
+        self.dcTmp.BeginDrawing()
+        
+        # draw objects
+        for i in range(rlist.nitems):
+            robj = rlist.item[i].contents
+            self._drawObject(robj)
+        
+        self.dc.EndDrawing()
+        self.dcTmp.EndDrawing()
+        
+        # reset list of selected features by cat 
+        # list of ids - see IsSelected()
+        self.selected['field'] = -1
+        self.selected['cats'] = list()
+        
+    def _getSelectType(self):
+        """!Get type(s) to be selected
+
+        Used by SelectLinesByBox() and SelectLineByPoint()
+        """
+        ftype = 0
+        for feature in (('point',    GV_POINT),
+                        ('line',     GV_LINE),
+                        ('centroid', GV_CENTROID),
+                        ('boundary', GV_BOUNDARY)):
+            if UserSettings.Get(group = 'vdigit', key = 'selectType',
+                                subkey = [feature[0], 'enabled']):
+                ftype |= feature[1]
+        
+        return ftype
+
+    def _validLine(self, line):
+        """!Check if feature id is valid
+
+        @param line feature id
+
+        @return True valid feature id
+        @return False invalid
+        """
+        if line > 0 and line <= Vect_get_num_lines(self.poMapInfo):
+            return True
+        
+        return False
+    
+    def SelectLinesByBox(self, bbox, drawSeg = False, poMapInfo = None):
+        """!Select vector objects by given bounding box
+        
+        If line id is already in the list of selected lines, then it will
+        be excluded from this list.
+        
+        @param bbox bounding box definition
+        @param drawSeg True to draw segments of line
+        @param poMapInfo use external Map_info, None for self.poMapInfo
+
+        @return number of selected features
+        @return None on error
+        """
+        thisMapInfo = poMapInfo is None
+        if not poMapInfo:
+            poMapInfo = self.poMapInfo
+        
+        if not poMapInfo:
+            return None
+        
+        if thisMapInfo:
+            self._drawSegments = drawSeg
+            self._drawSelected = True
+        
+            # select by ids
+            self.selected['cats'] = list()
+        
+        poList = Vect_new_list()
+        x1, y1 = bbox[0]
+        x2, y2 = bbox[1]
+        poBbox = Vect_new_line_struct()
+        Vect_append_point(poBbox, x1, y1, 0.0)
+        Vect_append_point(poBbox, x2, y1, 0.0)
+        Vect_append_point(poBbox, x2, y2, 0.0)
+        Vect_append_point(poBbox, x1, y2, 0.0)
+        Vect_append_point(poBbox, x1, y1, 0.0)
+        
+        Vect_select_lines_by_polygon(poMapInfo, poBbox,
+                                     0, None, # isles
+                                     self._getSelectType(), poList)
+        
+        flist = poList.contents
+        nlines = flist.n_values
+        Debug.msg(1, "DisplayDriver.SelectLinesByBox() num = %d", nlines)
+        for i in range(nlines):
+            line = flist.value[i]
+            if UserSettings.Get(group = 'vdigit', key = 'selectInside',
+                                subkey = 'enabled'):
+                inside = True
+                if not self._validLine(line):
+                    return None
+                Vect_read_line(poMapInfo, self.poPoints, None, line)
+                points = self.poPoints.contents
+                for p in range(points.n_points):
+                    if not Vect_point_in_poly(points.x[p], points.y[p],
+                                              poBbox):
+                        inside = False
+                        break
+                    
+                if not inside:
+                    continue # skip lines just overlapping bbox
+            
+            if not self._isSelected(line):
+                self.selected['ids'].append(line)
+            else:
+                self.selected['ids'].remove(line)
+        
+        Vect_destroy_line_struct(poBbox)
+        Vect_destroy_list(poList)
+        
+        return nlines
+
+    def SelectLineByPoint(self, point, poMapInfo = None):
+        """!Select vector feature by given point in given
+        threshold
+   
+        Only one vector object can be selected. Bounding boxes of
+        all segments are stores.
+        
+        @param point points coordinates (x, y)
+        @param poMapInfo use external Map_info, None for self.poMapInfo
+
+        @return dict {'line' : feature id, 'point' : point on line}
+        """
+        thisMapInfo = poMapInfo is None
+        if not poMapInfo:
+            poMapInfo = self.poMapInfo
+        
+        if not poMapInfo:
+            return { 'line' : -1, 'point': None }
+        
+        if thisMapInfo:
+            self._drawSelected = True
+            # select by ids 
+            self.selected['cats'] = list()
+        
+        poFound = Vect_new_list()
+        
+        lineNearest = Vect_find_line_list(poMapInfo, point[0], point[1], 0,
+                                           self._getSelectType(), self.GetThreshold(), self.is3D,
+                                           None, poFound)
+        Debug.msg(1, "DisplayDriver.SelectLineByPoint() found = %d", lineNearest)
+        
+        if lineNearest > 0:
+            if not self._isSelected(lineNearest):
+                self.selected['ids'].append(lineNearest)
+            else:
+                self.selected['ids'].remove(lineNearest)
+        
+        px = c_double()
+        py = c_double()
+        pz = c_double()
+        if not self._validLine(lineNearest):
+            return { 'line' : -1, 'point': None }
+	ftype = Vect_read_line(poMapInfo, self.poPoints, self.poCats, lineNearest)
+	Vect_line_distance (self.poPoints, point[0], point[1], 0.0, self.is3D,
+			    byref(px), byref(py), byref(pz),
+			    None, None, None)
+        
+	# check for duplicates 
+	if self.settings['highlightDupl']['enabled']:
+            found = poFound.contents
+	    for i in range(found.n_values):
+		line = found.value[i]
+		if line != lineNearest:
+                    self.selected['ids'].append(line)
+	    
+            self.GetDuplicates()
+	    
+	    for i in range(found.n_values):
+		line = found.value[i]
+		if line != lineNearest and not self._isDuplicated(line):
+                    self.selected['ids'].remove(line)
+        
+        Vect_destroy_list(poFound)
+        
+        if thisMapInfo:
+            # drawing segments can be very expensive
+            # only one features selected
+            self._drawSegments = True
+        
+        return { 'line'  : lineNearest,
+                 'point' : (px.value, py.value, pz.value) }
+    
+    def _listToIList(self, plist):
+        """!Generate from list struct_ilist
+        """
+        ilist = Vect_new_list()
+        for val in plist:
+            Vect_list_append(ilist, val)
+        
+        return ilist
+        
+    def GetSelectedIList(self, ilist = None):
+        """!Get list of selected objects as struct_ilist
+
+        Returned IList must be freed by Vect_destroy_list().
+        
+        @return struct_ilist
+        """
+        if ilist:
+            return self._listToIList(ilist)
+        
+        return self._listToIList(self.selected['ids'])
+        
+    def GetSelected(self, grassId = True):
+        """!Get ids of selected objects
+        
+        @param grassId True for feature id, False for PseudoDC id
+        
+        @return list of ids of selected vector objects
+        """
+        if grassId:
+            return self.selected['ids']
+        
+        dc_ids = list()
+        
+        if not self._drawSegments:
+            dc_ids.append(1)
+        elif len(self.selected['ids']) > 0:
+            # only first selected feature
+            Vect_read_line(self.poMapInfo, self.poPoints, None,
+                           self.selected['ids'][0])
+            points = self.poPoints.contents
+            # node - segment - vertex - segment - node
+            for i in range(1, 2 * points.n_points):
+                dc_ids.append(i)
+        
+        return dc_ids
+        
+    def SetSelected(self, ids, layer = -1):
+        """!Set selected vector objects
+
+        @param list of ids (None to unselect features)
+        @param layer layer number for features selected based on category number
+        """
+        if ids:
+            self._drawSelected = True
+        else:
+            self._drawSelected = False
+        
+        if layer > 0:
+            selected.field = layer
+            self.selected['cats'] = ids
+        else:
+            field = -1
+            self.selected['ids'] = ids
+        
+    def GetSelectedVertex(self, pos):
+        """!Get PseudoDC vertex id of selected line
+
+        Set bounding box for vertices of line.
+        
+        @param pos position
+        
+        @return id of center, left and right vertex
+        @return 0 no line found
+        @return -1 on error
+        """
+        returnId = list()
+        # only one object can be selected
+        if len(self.selected['ids']) != 1 or not self._drawSegments:
+            return returnId
+        
+        startId = 1
+        line = self.selected['ids'][0]
+        
+        if not self._validLine(line):
+            return -1
+        ftype = Vect_read_line(self.poMapInfo, self.poPoints, self.poCats, line)
+        
+        minDist = 0.0
+        Gid = -1
+        # find the closest vertex (x, y)
+        DCid = 1
+        points = self.poPoints.contents
+        for idx in range(points.n_points):
+            dist = Vect_points_distance(pos[0], pos[1], 0.0,
+                                        points.x[idx], points.y[idx], points.z[idx], 0)
+            
+            if idx == 0:
+                minDist = dist
+                Gid     = idx
+            else:
+                if minDist > dist:
+                    minDist = dist
+                    Gid = idx
+            
+            vx, vy = self._cell2Pixel(points.x[idx], points.y[idx], points.z[idx])
+            rect = wx.Rect(vx, vy, 0, 0)
+            self.dc.SetIdBounds(DCid, rect)
+            DCid += 2
+        
+        if minDist > self.GetThreshold():
+            return returnId
+        
+        # translate id
+        DCid = Gid * 2 + 1
+        
+        # add selected vertex
+        returnId.append(DCid)
+        # left vertex
+        if DCid == startId:
+            returnId.append(-1)
+        else:
+            returnId.append(DCid - 2)
+        # right vertex
+        if DCid == (points.n_points - 1) * 2 + startId:
+            returnId.append(-1)
+        else:
+            returnId.append(DCid + 2)
+        
+        return returnId
+
+    def DrawSelected(self, flag):
+        """!Draw selected features
+        
+        @param flag True to draw selected features
+        """
+        self._drawSelected = bool(flag)
+        
+    def CloseMap(self):
+        """!Close vector map
+        
+        @return 0 on success
+        @return non-zero on error
+        """
+        ret = 0
+        if self.poMapInfo:
+            # rebuild topology
+            Vect_build_partial(self.poMapInfo, GV_BUILD_NONE)
+            Vect_build(self.poMapInfo)
+
+            # close map and store topo/cidx
+            ret = Vect_close(self.poMapInfo)
+            del self.mapInfo
+            self.poMapInfo = self.mapInfo = None
+        
+        return ret
+    
+    def OpenMap(self, name, mapset, update = True):
+        """!Open vector map by the driver
+        
+        @param name name of vector map to be open
+        @param mapset name of mapset where the vector map lives
+   
+        @return map_info
+        @return None on error
+        """
+        Debug.msg("DisplayDriver.OpenMap(): name=%s mapset=%s updated=%d",
+                  name, mapset, update)
+        if not self.mapInfo:
+            self.mapInfo = Map_info()
+            self.poMapInfo = pointer(self.mapInfo)
+        
+        # open existing map
+        if update:
+            ret = Vect_open_update(self.poMapInfo, name, mapset)
+        else:
+            ret = Vect_open_old(self.poMapInfo, name, mapset)
+        self.is3D = Vect_is_3d(self.poMapInfo)
+        
+        if ret == -1: # error
+            del self.mapInfo
+            self.poMapInfo = self.mapInfo = None
+        elif ret < 2:
+            dlg = wx.MessageDialog(parent = self.window,
+                                   message = _("Topology for vector map <%s> is not available. "
+                                               "Topology is required by digitizer. Do you want to "
+                                               "rebuild topology (takes some time) and open the vector map "
+                                               "for editing?") % name,
+                                   caption=_("Topology missing"),
+                                   style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
+            ret = dlg.ShowModal()
+            if ret != wx.ID_YES:
+                del self.mapInfo
+                self.poMapInfo = self.mapInfo = None
+            else:
+                Vect_build(self.poMapInfo)
+        
+        return self.poMapInfo
+    
+    def GetMapBoundingBox(self):
+        """!Get bounding box of (opened) vector map layer
+
+        @return (w,s,b,e,n,t)
+        """
+        if not self.poMapInfo:
+            return None
+        
+        bbox = bound_box()
+        Vect_get_map_box(self.poMapInfo, byref(bbox))
+
+        return bbox.W, bbox.S, bbox.B, \
+            bbox.E, bbox.N, bbox.T
+    
+    def UpdateSettings(self, alpha = 255):
+        """!Update display driver settings
+
+        @todo map units
+        
+        @alpha color value for aplha channel
+        """
+        color = dict()
+        for key in self.settings.keys():
+            if key == 'lineWidth':
+                self.settings[key] = int(UserSettings.Get(group = 'vdigit', key = 'lineWidth',
+                                                          subkey = 'value'))
+                continue
+            
+            color = wx.Color(UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                              subkey = [key, 'color'])[0],
+                             UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                              subkey = [key, 'color'])[1],
+                             UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                              subkey = [key, 'color'])[2],
+                             alpha)
+            
+            if key == 'highlight':
+                self.settings[key] = color
+                continue
+            
+            if key == 'highlightDupl':
+                self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'checkForDupl',
+                                                                      subkey = 'enabled'))
+            else:
+                self.settings[key]['enabled'] = bool(UserSettings.Get(group = 'vdigit', key = 'symbol',
+                                                                      subkey = [key, 'enabled']))
+            
+            self.settings[key]['color'] = color
+        
+    def UpdateRegion(self):
+        """!Update geographical region used by display driver
+        """
+        self.region = self.mapObj.GetCurrentRegion()
+        
+    def GetThreshold(self, type = 'snapping', value = None, units = None):
+        """!Return threshold value in map units
+        
+        @param type snapping mode (node, vertex)
+        @param value threshold to be set up
+        @param units units (map, screen)
+
+        @return threshold value
+        """
+        if value is None:
+            value = UserSettings.Get(group = 'vdigit', key = type, subkey = 'value')
+        
+        if units is None:
+            units = UserSettings.Get(group = 'vdigit', key = type, subkey = 'units')
+        
+        if value < 0:
+            value = (self.region['nsres'] + self.region['ewres']) / 2.0
+        
+        if units == "screen pixels":
+            # pixel -> cell
+            res = max(self.region['nsres'], self.region['ewres'])
+            return value * res
+        
+        return value
+    
+    def GetDuplicates(self):
+        """!Return ids of (selected) duplicated vector features
+        """
+        if not self.poMapInfo:
+            return
+        
+        ids = dict()
+        APoints = Vect_new_line_struct()
+        BPoints = Vect_new_line_struct()
+        
+        self.selected['idsDupl'] = list()
+        
+        for i in range(len(self.selected['ids'])):
+            line1 = self.selected['ids'][i]
+            if self._isDuplicated(line1):
+                continue
+            
+            Vect_read_line(self.poMapInfo, APoints, None, line1)
+            
+            for line2 in self.selected['ids']:
+                if line1 == line2 or self._isDuplicated(line2):
+                    continue
+                
+                Vect_read_line(self.poMapInfo, BPoints, None, line2)
+	    
+                if Vect_line_check_duplicate(APoints, BPoints, WITHOUT_Z):
+                    if i not in ids:
+                        ids[i] = list()
+                        ids[i].append((line1, self._getCatString(line1)))
+                        self.selected['idsDupl'].append(line1)
+                    
+                    ids[i].append((line2, self._getCatString(line2)))
+                    self.selected['idsDupl'].append(line2)
+        
+        Vect_destroy_line_struct(APoints)
+        Vect_destroy_line_struct(BPoints)
+
+        return ids
+    
+    def _getCatString(self, line):
+        Vect_read_line(self.poMapInfo, None, self.poCats, line)
+        
+        cats = self.poCats.contents
+        catsDict = dict()
+        for i in range(cats.n_cats):
+            layer = cats.field[i]
+            if layer not in catsDict:
+                catsDict[layer] = list()
+            catsDict[layer].append(cats.cat[i])
+        
+        catsStr = ''
+        for l, c in catsDict.iteritems():
+            catsStr = '%d: (%s)' % (l, ','.join(map(str, c)))
+        
+        return catsStr
+
+    def UnSelect(self, lines):
+        """!Unselect vector features
+
+        @param lines list of feature id(s)
+        """
+        checkForDupl = False
+
+        for line in lines:
+            if self._isSelected(line):
+                self.selected['ids'].remove(line)
+            if self.settings['highlightDupl']['enabled'] and self._isDuplicated(line):
+                checkForDupl = True
+
+        if checkForDupl:
+            self.GetDuplicates()
+        
+        return len(self.selected['ids'])
+    
+

Modified: grass/trunk/gui/wxpython/wxgui.py
===================================================================
--- grass/trunk/gui/wxpython/wxgui.py	2011-11-24 09:13:37 UTC (rev 49346)
+++ grass/trunk/gui/wxpython/wxgui.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -1,18 +1,19 @@
 """!
- at package wxgui.py
+ at package wxgui
 
- at brief Main Python app for GRASS wxPython GUI. Main menu, layer management
-toolbar, notebook control for display management and access to
-command console.
+ at brief Main Python application for GRASS wxPython GUI
 
+Layer Manager - main menu, layer management toolbar, notebook control
+for display management and access to command console.
+
 Classes:
  - GMFrame
  - GMApp
+ - Usage
 
 (C) 2006-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
 
 @author Michael Barton (Arizona State University)
 @author Jachym Cepicky (Mendel University of Agriculture)
@@ -22,68 +23,57 @@
 
 import sys
 import os
-import time
-import string
 import getopt
-import platform
-import signal
 import tempfile
 try:
     import xml.etree.ElementTree as etree
 except ImportError:
     import elementtree.ElementTree as etree # Python <= 2.4
 
-from gui_modules import globalvar
+from core import globalvar
 import wx
 import wx.aui
-import wx.combo
-import wx.html
-import wx.stc
 try:
-    import wx.lib.agw.customtreectrl as CT
     import wx.lib.agw.flatnotebook   as FN
 except ImportError:
-    import wx.lib.customtreectrl as CT
     import wx.lib.flatnotebook   as FN
-
 try:
     import wx.lib.agw.advancedsplash as SC
 except ImportError:
     SC = None
 
 sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
-from grass.script import core as grass
+from grass.script          import core as grass
 
-from gui_modules import utils
-from gui_modules import preferences
-from gui_modules import layertree
-from gui_modules import mapdisp
-from gui_modules import menudata
-from gui_modules import menuform
-from gui_modules import histogram
-from gui_modules import mcalc_builder as mapcalculator
-from gui_modules import gcmd
-from gui_modules import dbm
-from gui_modules import workspace
-from gui_modules import goutput
-from gui_modules import gdialogs
-from gui_modules import colorrules
-from gui_modules import ogc_services
-from gui_modules import prompt
-from gui_modules import menu
-from gui_modules import gmodeler
-from gui_modules import vclean
-from gui_modules import nviz_tools
-from gui_modules import psmap
-from gui_modules.debug    import Debug
-from gui_modules.ghelp    import MenuTreeWindow, AboutWindow, InstallExtensionWindow
-from gui_modules.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar,\
-                                 LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
-from gui_modules.gpyshell import PyShellWindow
-from icons.icon           import Icons
+from core                  import utils
+from core.gcmd             import RunCommand, GError, GMessage
+from core.settings         import UserSettings
+from icons.icon            import Icons
+from gui_core.preferences  import MapsetAccess, PreferencesDialog, EVT_SETTINGS_CHANGED
+from lmgr.layertree        import LayerTree
+from lmgr.menudata         import ManagerData
+from gui_core.widgets      import GNotebook
+from modules.histogram     import HistFrame
+from modules.mcalc_builder import MapCalcFrame
+from dbm.manager           import AttributeManager
+from core.workspace        import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
+from gui_core.goutput      import GMConsole
+from gui_core.dialogs      import GdalOutputDialog, DxfImportDialog, GdalImportDialog, MapLayersDialog
+from gui_core.dialogs      import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog
+from modules.ogc_services  import WMSDialog
+from modules.colorrules    import RasterColorTable, VectorColorTable
+from gui_core.menu         import Menu
+from gmodeler.model        import Model
+from gmodeler.frame        import ModelFrame
+from modules.vclean        import VectorCleaningFrame
+from nviz.tools            import NvizToolWindow
+from psmap.frame           import PsMapFrame
+from core.debug            import Debug
+from gui_core.ghelp        import MenuTreeWindow, AboutWindow, InstallExtensionWindow
+from lmgr.toolbars         import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
+from lmgr.toolbars         import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
+from lmgr.pyshell          import PyShellWindow
 
-UserSettings = preferences.globalSettings
-
 class GMFrame(wx.Frame):
     """!Layer Manager frame with notebook widget for controlling GRASS
     GIS. Includes command console page for typing GRASS (and other)
@@ -229,7 +219,7 @@
         
     def _createMenuBar(self):
         """!Creates menu bar"""
-        self.menubar = menu.Menu(parent = self, data = menudata.ManagerData())
+        self.menubar = Menu(parent = self, data = ManagerData())
         self.SetMenuBar(self.menubar)
         self.menucmd = self.menubar.GetCmd()
         
@@ -245,7 +235,7 @@
     
     def _createNoteBook(self):
         """!Creates notebook widgets"""
-        self.notebook = menuform.GNotebook(parent = self, style = globalvar.FNPageDStyle)
+        self.notebook = GNotebook(parent = self, style = globalvar.FNPageDStyle)
         # create displays notebook widget and add it to main notebook page
         cbStyle = globalvar.FNPageStyle
         if globalvar.hasAgw:
@@ -256,7 +246,7 @@
         self.notebook.AddPage(page = self.gm_cb, text = _("Map layers"), name = 'layers')
         
         # create 'command output' text area
-        self.goutput = goutput.GMConsole(self)
+        self.goutput = GMConsole(self)
         self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
         self._setCopyingOfSelectedText()
         
@@ -292,8 +282,8 @@
         self._auimgr.Update()
         
         # create nviz tools tab
-        self.nviz = nviz_tools.NvizToolWindow(parent = self,
-                                              display = self.curr_page.maptree.GetMapDisplay())
+        self.nviz = NvizToolWindow(parent = self,
+                                   display = self.curr_page.maptree.GetMapDisplay())
         idx = self.notebook.GetPageIndexByName('layers')
         self.notebook.InsertPage(indx = idx + 1, page = self.nviz, text = _("3D view"), name = 'nviz')
         self.notebook.SetSelectionByName('nviz')
@@ -338,10 +328,10 @@
             
             ret = dlg.ShowModal()
             if ret == wx.ID_YES:
-                gcmd.RunCommand("g.gisenv",
-                                set = "LOCATION_NAME=%s" % gWizard.location)
-                gcmd.RunCommand("g.gisenv",
-                                set = "MAPSET=PERMANENT")
+                RunCommand("g.gisenv",
+                           set = "LOCATION_NAME=%s" % gWizard.location)
+                RunCommand("g.gisenv",
+                           set = "MAPSET=PERMANENT")
             
             dlg.Destroy()
             
@@ -368,7 +358,7 @@
     def OnPsMap(self, event):
         """!Launch Cartographic Composer
         """
-        win = psmap.PsMapFrame(parent = self)
+        win = PsMapFrame(parent = self)
         win.CentreOnScreen()
         
         win.Show()
@@ -379,9 +369,9 @@
         try:
             from gui_modules import rstream
         except:
-            gcmd.GError(parent = self.parent,
-                        message = _("RStream Utility is not available. You can install it by %s") % \
-                            'g.extension -s extension=wx.stream')
+            GError(parent = self.parent,
+                   message = _("RStream Utility is not available. You can install it by %s") % \
+                       'g.extension -s extension=wx.stream')
             return
         
         win = rstream.RStreamFrame(parent = self)
@@ -418,14 +408,14 @@
     def OnMapsets(self, event):
         """!Launch mapset access dialog
         """
-        dlg = preferences.MapsetAccess(parent = self, id = wx.ID_ANY)
+        dlg = MapsetAccess(parent = self, id = wx.ID_ANY)
         dlg.CenterOnScreen()
         
         if dlg.ShowModal() == wx.ID_OK:
             ms = dlg.GetMapsets()
-            gcmd.RunCommand('g.mapsets',
-                            parent = self,
-                            mapset = '%s' % ','.join(ms))
+            RunCommand('g.mapsets',
+                       parent = self,
+                       mapset = '%s' % ','.join(ms))
         
     def OnCBPageChanged(self, event):
         """!Page in notebook (display) changed"""
@@ -575,14 +565,14 @@
             mapLayer = None
         
         if not mapLayer or mapLayer.GetType() != 'vector':
-            gcmd.GMessage(parent = self,
-                          message = _("Selected map layer is not vector."))
+            GMessage(parent = self,
+                     message = _("Selected map layer is not vector."))
             return
         
         if mapLayer.GetMapset() != grass.gisenv()['MAPSET']:
-            gcmd.GMessage(parent = self,
-                          message = _("Editing is allowed only for vector maps from the "
-                                      "current mapset."))
+            GMessage(parent = self,
+                     message = _("Editing is allowed only for vector maps from the "
+                                 "current mapset."))
             return
         
         if not tree.GetPyData(layer)[0]:
@@ -608,9 +598,9 @@
             return False
 
         if not os.path.exists(filename):
-            gcmd.GError(parent = self,
-                        message = _("Script file '%s' doesn't exist. "
-                                    "Operation cancelled.") % filename)
+            GError(parent = self,
+                   message = _("Script file '%s' doesn't exist. "
+                               "Operation cancelled.") % filename)
             return
         
         self.goutput.WriteCmdLog(_("Launching script '%s'...") % filename)
@@ -618,14 +608,14 @@
         
     def OnChangeLocation(self, event):
         """Change current location"""
-        dlg = gdialogs.LocationDialog(parent = self)
+        dlg = LocationDialog(parent = self)
         if dlg.ShowModal() == wx.ID_OK:
             location, mapset = dlg.GetValues()
             if location and mapset:
-                ret = gcmd.RunCommand("g.gisenv",
-                                      set = "LOCATION_NAME=%s" % location)
-                ret += gcmd.RunCommand("g.gisenv",
-                                       set = "MAPSET=%s" % mapset)
+                ret = RunCommand("g.gisenv",
+                                 set = "LOCATION_NAME=%s" % location)
+                ret += RunCommand("g.gisenv",
+                                  set = "MAPSET=%s" % mapset)
                 if ret > 0:
                     wx.MessageBox(parent = self,
                                   message = _("Unable to switch to location <%(loc)s> mapset <%(mapset)s>.") % \
@@ -650,43 +640,43 @@
         if dlg.ShowModal() ==  wx.ID_OK:
             mapset = dlg.GetValue()
             if not mapset:
-                gcmd.GError(parent = self,
-                            message = _("No mapset provided. Operation canceled."))
+                GError(parent = self,
+                       message = _("No mapset provided. Operation canceled."))
                 return
             
-            ret = gcmd.RunCommand('g.mapset',
-                                  parent = self,
-                                  flags = 'c',
-                                  mapset = mapset)
+            ret = RunCommand('g.mapset',
+                             parent = self,
+                             flags = 'c',
+                             mapset = mapset)
             if ret == 0:
-                gcmd.GMessage(parent = self,
-                              message = _("Current mapset is <%s>.") % mapset)
-            
+                GMessage(parent = self,
+                         message = _("Current mapset is <%s>.") % mapset)
+                
     def OnChangeMapset(self, event):
         """Change current mapset"""
-        dlg = gdialogs.MapsetDialog(parent = self)
+        dlg = MapsetDialog(parent = self)
         
         if dlg.ShowModal() == wx.ID_OK:
             mapset = dlg.GetMapset()
             if not mapset:
-                gcmd.GError(parent = self,
-                            message = _("No mapset provided. Operation canceled."))
+                GError(parent = self,
+                       message = _("No mapset provided. Operation canceled."))
                 return
             
-            ret = gcmd.RunCommand('g.mapset',
-                                  parent = self,
-                                  mapset = mapset)
+            ret = RunCommand('g.mapset',
+                             parent = self,
+                             mapset = mapset)
             
             if ret == 0:
-                gcmd.GMessage(parent = self,
-                              message = _("Current mapset is <%s>.") % mapset)
+                GMessage(parent = self,
+                         message = _("Current mapset is <%s>.") % mapset)
         
     def OnNewVector(self, event):
         """!Create new vector map layer"""
-        dlg = gdialogs.CreateNewVector(self, log = self.goutput,
-                                       cmd = (('v.edit',
-                                               { 'tool' : 'create' },
-                                               'map')))
+        dlg = CreateNewVector(self, log = self.goutput,
+                              cmd = (('v.edit',
+                                      { 'tool' : 'create' },
+                                      'map')))
         
         if not dlg:
             return
@@ -814,11 +804,11 @@
         
         # parse workspace file
         try:
-            gxwXml = workspace.ProcessWorkspaceFile(etree.parse(filename))
+            gxwXml = ProcessWorkspaceFile(etree.parse(filename))
         except Exception, e:
-            gcmd.GError(parent = self,
-                        message = _("Reading workspace file <%s> failed.\n"
-                                    "Invalid file, unable to parse XML document.") % filename)
+            GError(parent = self,
+                   message = _("Reading workspace file <%s> failed.\n"
+                               "Invalid file, unable to parse XML document.") % filename)
             return
         
         busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
@@ -958,7 +948,7 @@
         wx.Yield()
 
         maptree = None
-        for layer in workspace.ProcessGrcFile(filename).read(self):
+        for layer in ProcessGrcFile(filename).read(self):
             maptree = self.gm_cb.GetPage(layer['display']).maptree
             newItem = maptree.AddLayer(ltype = layer['type'],
                                        lname = layer['name'],
@@ -1027,11 +1017,11 @@
         """
         tmpfile = tempfile.TemporaryFile(mode = 'w+b')
         try:
-            workspace.WriteWorkspaceFile(lmgr = self, file = tmpfile)
+            WriteWorkspaceFile(lmgr = self, file = tmpfile)
         except StandardError, e:
-            gcmd.GError(parent = self,
-                        message = _("Writing current settings to workspace file "
-                                    "failed."))
+            GError(parent = self,
+                   message = _("Writing current settings to workspace file "
+                               "failed."))
             return False
         
         try:
@@ -1040,8 +1030,8 @@
             for line in tmpfile.readlines():
                 mfile.write(line)
         except IOError:
-            gcmd.GError(parent = self,
-                        message = _("Unable to open file <%s> for writing.") % filename)
+            GError(parent = self,
+                   message = _("Unable to open file <%s> for writing.") % filename)
             return False
         
         mfile.close()
@@ -1094,7 +1084,7 @@
     def OnEditImageryGroups(self, event, cmd = None):
         """!Show dialog for creating and editing groups.
         """
-        dlg = gdialogs.GroupDialog(self)
+        dlg = GroupDialog(self)
         dlg.CentreOnScreen()
         dlg.Show()
         
@@ -1108,11 +1098,11 @@
         """!General GUI preferences/settings
         """
         if not self.dialogs['preferences']:
-            dlg = preferences.PreferencesDialog(parent = self)
+            dlg = PreferencesDialog(parent = self)
             self.dialogs['preferences'] = dlg
             self.dialogs['preferences'].CenterOnScreen()
             
-            dlg.Bind(preferences.EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
+            dlg.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
         
         self.dialogs['preferences'].ShowModal()
         
@@ -1125,9 +1115,8 @@
         """
         Init histogram display canvas and tools
         """
-        self.histogram = histogram.HistFrame(self,
-                                             id = wx.ID_ANY, pos = wx.DefaultPosition, size = (400,300),
-                                             style = wx.DEFAULT_FRAME_STYLE)
+        self.histogram = HistFrame(self, id = wx.ID_ANY, pos = wx.DefaultPosition, size = (400,300),
+                                   style = wx.DEFAULT_FRAME_STYLE)
 
         #show new display
         self.histogram.Show()
@@ -1154,8 +1143,8 @@
             except KeyError:
                 cmd = ['r.mapcalc']
         
-        win = mapcalculator.MapCalcFrame(parent = self,
-                                         cmd = cmd[0])
+        win = MapCalcFrame(parent = self,
+                           cmd = cmd[0])
         win.CentreOnScreen()
         win.Show()
     
@@ -1166,7 +1155,7 @@
         if event:
             cmd = self.GetMenuCmd(event)
 
-        win = vclean.VectorCleaningFrame(parent = self, cmd = cmd[0])
+        win = VectorCleaningFrame(parent = self, cmd = cmd[0])
         win.CentreOnScreen()
         win.Show()
 
@@ -1176,43 +1165,43 @@
 
     def OnVectorOutputFormat(self, event):
         """!Set vector output format handler"""
-        dlg = gdialogs.GdalOutputDialog(parent = self, ogr = True)
+        dlg = GdalOutputDialog(parent = self, ogr = True)
         dlg.CentreOnScreen()
         dlg.Show()
     
     def OnImportDxfFile(self, event, cmd = None):
         """!Convert multiple DXF layers to GRASS vector map layers"""
-        dlg = gdialogs.DxfImportDialog(parent = self)
+        dlg = DxfImportDialog(parent = self)
         dlg.CentreOnScreen()
         dlg.Show()
 
     def OnImportGdalLayers(self, event, cmd = None):
         """!Convert multiple GDAL layers to GRASS raster map layers"""
-        dlg = gdialogs.GdalImportDialog(parent = self)
+        dlg = GdalImportDialog(parent = self)
         dlg.CentreOnScreen()
         dlg.Show()
 
     def OnLinkGdalLayers(self, event, cmd = None):
         """!Link multiple GDAL layers to GRASS raster map layers"""
-        dlg = gdialogs.GdalImportDialog(parent = self, link = True)
+        dlg = GdalImportDialog(parent = self, link = True)
         dlg.CentreOnScreen()
         dlg.Show()
         
     def OnImportOgrLayers(self, event, cmd = None):
         """!Convert multiple OGR layers to GRASS vector map layers"""
-        dlg = gdialogs.GdalImportDialog(parent = self, ogr = True)
+        dlg = GdalImportDialog(parent = self, ogr = True)
         dlg.CentreOnScreen()
         dlg.Show()
         
     def OnLinkOgrLayers(self, event, cmd = None):
         """!Links multiple OGR layers to GRASS vector map layers"""
-        dlg = gdialogs.GdalImportDialog(parent = self, ogr = True, link = True)
+        dlg = GdalImportDialog(parent = self, ogr = True, link = True)
         dlg.CentreOnScreen()
         dlg.Show()
         
     def OnImportWMS(self, event):
         """!Import data from OGC WMS server"""
-        dlg = ogc_services.WMSDialog(parent = self, service = 'wms')
+        dlg = WMSDialog(parent = self, service = 'wms')
         dlg.CenterOnScreen()
         
         if dlg.ShowModal() == wx.ID_OK: # -> import layers
@@ -1262,8 +1251,8 @@
             maptype = None
         
         if not maptype or maptype != 'vector':
-            gcmd.GMessage(parent = self,
-                          message = _("Selected map layer is not vector."))
+            GMessage(parent = self,
+                     message = _("Selected map layer is not vector."))
             return
         
         if not tree.GetPyData(layer)[0]:
@@ -1276,10 +1265,10 @@
                            parent = self)
         wx.Yield()
         
-        dbmanager = dbm.AttributeManager(parent = self, id = wx.ID_ANY,
-                                         size = wx.Size(500, 300),
-                                         item = layer, log = self.goutput,
-                                         selection = selection)
+        dbmanager = AttributeManager(parent = self, id = wx.ID_ANY,
+                                     size = wx.Size(500, 300),
+                                     item = layer, log = self.goutput,
+                                     selection = selection)
         
         busy.Destroy()
         
@@ -1309,12 +1298,12 @@
         self.curr_page = self.gm_cb.GetCurrentPage()
         
         # create layer tree (tree control for managing GIS layers)  and put on new notebook page
-        self.curr_page.maptree = layertree.LayerTree(self.curr_page, id = wx.ID_ANY, pos = wx.DefaultPosition,
-                                                     size = wx.DefaultSize, style = wx.TR_HAS_BUTTONS |
-                                                     wx.TR_LINES_AT_ROOT| wx.TR_HIDE_ROOT |
-                                                     wx.TR_DEFAULT_STYLE| wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE,
-                                                     idx = self.disp_idx, lmgr = self, notebook = self.gm_cb,
-                                                     auimgr = self._auimgr, showMapDisplay = show)
+        self.curr_page.maptree = LayerTree(self.curr_page, id = wx.ID_ANY, pos = wx.DefaultPosition,
+                                           size = wx.DefaultSize, style = wx.TR_HAS_BUTTONS |
+                                           wx.TR_LINES_AT_ROOT| wx.TR_HIDE_ROOT |
+                                           wx.TR_DEFAULT_STYLE| wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE,
+                                           idx = self.disp_idx, lmgr = self, notebook = self.gm_cb,
+                                           auimgr = self._auimgr, showMapDisplay = show)
         
         # layout for controls
         cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
@@ -1342,7 +1331,7 @@
     
     def OnAddMaps(self, event = None):
         """!Add selected map layers into layer tree"""
-        dialog = gdialogs.MapLayersDialog(parent = self, title = _("Add selected map layers into layer tree"))
+        dialog = MapLayersDialog(parent = self, title = _("Add selected map layers into layer tree"))
         
         if dialog.ShowModal() != wx.ID_OK:
             dialog.Destroy()
@@ -1366,8 +1355,8 @@
                 cmd = ['d.vect', 'map=%s' % layerName]
                 wxType = 'vector'
             else:
-                gcmd.GError(parent = self,
-                            message = _("Unsupported map layer type <%s>.") % ltype)
+                GError(parent = self,
+                       message = _("Unsupported map layer type <%s>.") % ltype)
                 return
             
             newItem = maptree.AddLayer(ltype = wxType,
@@ -1739,7 +1728,7 @@
     print >> sys.stderr, " python wxgui.py [options]"
     print >> sys.stderr, "%sOptions:" % os.linesep
     print >> sys.stderr, " -w\t--workspace file\tWorkspace file to load"
-    sys.exit(0)
+    sys.exit(1)
 
 def process_opt(opts, args):
     """!Process command-line arguments"""

Copied: grass/trunk/gui/wxpython/wxplot/base.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/wxplot.py)
===================================================================
--- grass/trunk/gui/wxpython/wxplot/base.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/wxplot/base.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,529 @@
+"""!
+ at package wxplot.base
+
+ at brief Base classes for iinteractive plotting using PyPlot
+
+Classes:
+ - BasePlotFrame
+
+(C) 2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import os
+import sys
+
+import wx
+import wx.lib.plot as plot
+
+from core.globalvar import ETCICONDIR
+from core.settings  import UserSettings
+from wxplot.dialogs import TextDialog, OptDialog
+
+import grass.script as grass
+
+class BasePlotFrame(wx.Frame):
+    """!Abstract PyPlot display frame class"""
+    def __init__(self, parent = None, id = wx.ID_ANY, size = (700, 300),
+                 style = wx.DEFAULT_FRAME_STYLE, rasterList = [],  **kwargs):
+
+        wx.Frame.__init__(self, parent, id, size = size, style = style, **kwargs)
+        
+        self.parent = parent            # MapFrame
+        self.mapwin = self.parent.MapWindow
+        self.Map    = Map()             # instance of render.Map to be associated with display
+        self.rasterList = rasterList    #list of rasters to plot
+        self.raster = {}    # dictionary of raster maps and their plotting parameters
+        self.plottype = ''
+        
+        self.linestyledict = { 'solid' : wx.SOLID,
+                            'dot' : wx.DOT,
+                            'long-dash' : wx.LONG_DASH,
+                            'short-dash' : wx.SHORT_DASH,
+                            'dot-dash' : wx.DOT_DASH }
+
+        self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
+                            'solid' : wx.SOLID }
+
+        #
+        # Icon
+        #
+        self.SetIcon(wx.Icon(os.path.join(ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+                
+        #
+        # Add statusbar
+        #
+        self.statusbar = self.CreateStatusBar(number = 2, style = 0)
+        self.statusbar.SetStatusWidths([-2, -1])
+
+        #
+        # Define canvas and settings
+        #
+        # 
+        self.client = plot.PlotCanvas(self)
+
+        #define the function for drawing pointLabels
+        self.client.SetPointLabelFunc(self.DrawPointLabel)
+
+        # Create mouse event for showing cursor coords in status bar
+        self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
+
+        # Show closest point when enabled
+        self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
+
+        self.plotlist = []      # list of things to plot
+        self.plot = None        # plot draw object
+        self.ptitle = ""        # title of window
+        self.xlabel = ""        # default X-axis label
+        self.ylabel = ""        # default Y-axis label
+
+        #
+        # Bind various events
+        #
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+        
+        self.CentreOnScreen()
+        
+        self._createColorDict()
+
+
+    def _createColorDict(self):
+        """!Create color dictionary to return wx.Color tuples
+        for assigning colors to images in imagery groups"""
+                
+        self.colorDict = {}
+        for clr in grass.named_colors.iterkeys():
+            if clr == 'white' or clr == 'black': continue
+            r = grass.named_colors[clr][0] * 255
+            g = grass.named_colors[clr][1] * 255
+            b = grass.named_colors[clr][2] * 255
+            self.colorDict[clr] = (r,g,b,255)
+
+    def InitPlotOpts(self, plottype):
+        """!Initialize options for entire plot
+        """
+        
+        self.plottype = plottype                # histogram, profile, or scatter
+
+        self.properties = {}                    # plot properties
+        self.properties['font'] = {}
+        self.properties['font']['prop'] = UserSettings.Get(group = self.plottype, key = 'font')
+        self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
+                                                    wx.FONTSTYLE_NORMAL,
+                                                    wx.FONTWEIGHT_NORMAL)
+        
+        if self.plottype == 'profile':
+            self.properties['marker'] = UserSettings.Get(group = self.plottype, key = 'marker')
+            # changing color string to tuple for markers/points
+            colstr = str(self.properties['marker']['color'])
+            self.properties['marker']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
+
+        self.properties['grid'] = UserSettings.Get(group = self.plottype, key = 'grid')        
+        colstr = str(self.properties['grid']['color']) # changing color string to tuple        
+        self.properties['grid']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
+                
+        self.properties['x-axis'] = {}
+        self.properties['x-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'x-axis')
+        self.properties['x-axis']['axis'] = None
+
+        self.properties['y-axis'] = {}
+        self.properties['y-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'y-axis')
+        self.properties['y-axis']['axis'] = None
+        
+        self.properties['legend'] = UserSettings.Get(group = self.plottype, key = 'legend')
+
+        self.zoom = False  # zooming disabled
+        self.drag = False  # draging disabled
+        self.client.SetShowScrollbars(True) # vertical and horizontal scrollbars
+
+        # x and y axis set to normal (non-log)
+        self.client.setLogScale((False, False))
+        if self.properties['x-axis']['prop']['type']:
+            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
+        else:
+            self.client.SetXSpec('auto')
+        
+        if self.properties['y-axis']['prop']['type']:
+            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
+        else:
+            self.client.SetYSpec('auto')
+        
+    def InitRasterOpts(self, rasterList, plottype):
+        """!Initialize or update raster dictionary for plotting
+        """
+
+        rdict = {} # initialize a dictionary
+
+        for r in rasterList:
+            idx = rasterList.index(r)
+            
+            try:
+                ret = grass.raster_info(r)
+            except:
+                continue
+                # if r.info cannot parse map, skip it
+                
+            self.raster[r] = UserSettings.Get(group = plottype, key = 'raster') # some default settings
+            rdict[r] = {} # initialize sub-dictionaries for each raster in the list
+
+            if ret['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
+                rdict[r]['units'] = ''
+            else:
+                self.raster[r]['units'] = ret['units']
+
+            rdict[r]['plegend'] = r.split('@')[0]
+            rdict[r]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
+            rdict[r]['pline'] = None
+            rdict[r]['datatype'] = ret['datatype']
+            rdict[r]['pwidth'] = 1
+            rdict[r]['pstyle'] = 'solid'
+            
+            if idx <= len(self.colorList):
+                rdict[r]['pcolor'] = self.colorDict[self.colorList[idx]]
+            else:
+                r = randint(0, 255)
+                b = randint(0, 255)
+                g = randint(0, 255)
+                rdict[r]['pcolor'] = ((r,g,b,255))
+ 
+            
+        return rdict
+            
+    def InitRasterPairs(self, rasterList, plottype):
+        """!Initialize or update raster dictionary with raster pairs for
+            bivariate scatterplots
+        """
+        
+        if len(rasterList) == 0: return
+
+        rdict = {} # initialize a dictionary
+        for rpair in rasterList:
+            idx = rasterList.index(rpair)
+            
+            try:
+                ret0 = grass.raster_info(rpair[0])
+                ret1 = grass.raster_info(rpair[1])
+
+            except:
+                continue
+                # if r.info cannot parse map, skip it
+
+            self.raster[rpair] = UserSettings.Get(group = plottype, key = 'rasters') # some default settings
+            rdict[rpair] = {} # initialize sub-dictionaries for each raster in the list
+            rdict[rpair][0] = {}
+            rdict[rpair][1] = {}
+
+            if ret0['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
+                rdict[rpair][0]['units'] = ''
+            else:
+                self.raster[rpair][0]['units'] = ret0['units']
+
+            if ret1['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
+                rdict[rpair][1]['units'] = ''
+            else:
+                self.raster[rpair][1]['units'] = ret1['units']
+
+            rdict[rpair]['plegend'] = rpair[0].split('@')[0] + ' vs ' + rpair[1].split('@')[0]
+            rdict[rpair]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
+            rdict[rpair]['ptype'] = 'dot'
+            rdict[rpair][0]['datatype'] = ret0['datatype']
+            rdict[rpair][1]['datatype'] = ret1['datatype']
+            rdict[rpair]['psize'] = 1
+            rdict[rpair]['pfill'] = 'solid'
+            
+            if idx <= len(self.colorList):
+                rdict[rpair]['pcolor'] = self.colorDict[self.colorList[idx]]
+            else:
+                r = randint(0, 255)
+                b = randint(0, 255)
+                g = randint(0, 255)
+                rdict[rpair]['pcolor'] = ((r,g,b,255))
+            
+        return rdict
+
+    def SetGraphStyle(self):
+        """!Set plot and text options
+        """
+        self.client.SetFont(self.properties['font']['wxfont'])
+        self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
+        self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
+
+        self.client.SetEnableZoom(self.zoom)
+        self.client.SetEnableDrag(self.drag)
+        
+        #
+        # axis settings
+        #
+        if self.properties['x-axis']['prop']['type'] == 'custom':
+            self.client.SetXSpec('min')
+        else:
+            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
+
+        if self.properties['y-axis']['prop']['type'] == 'custom':
+            self.client.SetYSpec('min')
+        else:
+            self.client.SetYSpec(self.properties['y-axis']['prop'])
+
+        if self.properties['x-axis']['prop']['type'] == 'custom' and \
+               self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
+            self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
+                                                 self.properties['x-axis']['prop']['max'])
+        else:
+            self.properties['x-axis']['axis'] = None
+
+        if self.properties['y-axis']['prop']['type'] == 'custom' and \
+                self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
+            self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
+                                                 self.properties['y-axis']['prop']['max'])
+        else:
+            self.properties['y-axis']['axis'] = None
+
+        self.client.SetEnableGrid(self.properties['grid']['enabled'])
+        
+        self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
+                                           self.properties['grid']['color'][1],
+                                           self.properties['grid']['color'][2],
+                                           255))
+
+        self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
+        self.client.SetEnableLegend(self.properties['legend']['enabled'])
+
+        if self.properties['x-axis']['prop']['log'] == True:
+            self.properties['x-axis']['axis'] = None
+            self.client.SetXSpec('min')
+        if self.properties['y-axis']['prop']['log'] == True:
+            self.properties['y-axis']['axis'] = None
+            self.client.SetYSpec('min')
+            
+        self.client.setLogScale((self.properties['x-axis']['prop']['log'],
+                                 self.properties['y-axis']['prop']['log']))
+
+    def DrawPlot(self, plotlist):
+        """!Draw line and point plot from list plot elements.
+        """
+        self.plot = plot.PlotGraphics(plotlist,
+                                         self.ptitle,
+                                         self.xlabel,
+                                         self.ylabel)
+
+        if self.properties['x-axis']['prop']['type'] == 'custom':
+            self.client.SetXSpec('min')
+        else:
+            self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
+
+        if self.properties['y-axis']['prop']['type'] == 'custom':
+            self.client.SetYSpec('min')
+        else:
+            self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
+
+        self.client.Draw(self.plot, self.properties['x-axis']['axis'],
+                         self.properties['y-axis']['axis'])
+                
+    def DrawPointLabel(self, dc, mDataDict):
+        """!This is the fuction that defines how the pointLabels are
+            plotted dc - DC that will be passed mDataDict - Dictionary
+            of data that you want to use for the pointLabel
+
+            As an example I have decided I want a box at the curve
+            point with some text information about the curve plotted
+            below.  Any wxDC method can be used.
+        """
+        dc.SetPen(wx.Pen(wx.BLACK))
+        dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
+
+        sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
+        dc.DrawRectangle( sx-5,sy-5, 10, 10)  #10by10 square centered on point
+        px,py = mDataDict["pointXY"]
+        cNum = mDataDict["curveNum"]
+        pntIn = mDataDict["pIndex"]
+        legend = mDataDict["legend"]
+        #make a string to display
+        s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
+        dc.DrawText(s, sx , sy+1)
+
+    def OnZoom(self, event):
+        """!Enable zooming and disable dragging
+        """
+        self.zoom = True
+        self.drag = False
+        self.client.SetEnableZoom(self.zoom)
+        self.client.SetEnableDrag(self.drag)
+
+    def OnDrag(self, event):
+        """!Enable dragging and disable zooming
+        """
+        self.zoom = False
+        self.drag = True
+        self.client.SetEnableDrag(self.drag)
+        self.client.SetEnableZoom(self.zoom)
+
+    def OnRedraw(self, event):
+        """!Redraw the plot window. Unzoom to original size
+        """
+        self.client.Reset()
+        self.client.Redraw()
+       
+    def OnErase(self, event):
+        """!Erase the plot window
+        """
+        self.client.Clear()
+        self.mapwin.ClearLines(self.mapwin.pdc)
+        self.mapwin.ClearLines(self.mapwin.pdcTmp)
+        self.mapwin.polycoords = []
+        self.mapwin.Refresh()
+
+    def SaveToFile(self, event):
+        """!Save plot to graphics file
+        """
+        self.client.SaveFile()
+
+    def OnMouseLeftDown(self,event):
+        self.SetStatusText(_("Left Mouse Down at Point: (%.4f, %.4f)") % \
+                               self.client._getXY(event))
+        event.Skip() # allows plotCanvas OnMouseLeftDown to be called
+
+    def OnMotion(self, event):
+        """!Indicate when mouse is outside the plot area
+        """
+        if self.client.OnLeave(event): print 'out of area'
+        #show closest point (when enbled)
+        if self.client.GetEnablePointLabel() == True:
+            #make up dict with info for the pointLabel
+            #I've decided to mark the closest point on the closest curve
+            dlst =  self.client.GetClosetPoint( self.client._getXY(event), pointScaled =  True)
+            if dlst != []:      #returns [] if none
+                curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
+                #make up dictionary to pass to my user function (see DrawPointLabel)
+                mDataDict =  {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
+                    "pointXY":pointXY, "scaledXY":scaledXY}
+                #pass dict to update the pointLabel
+                self.client.UpdatePointLabel(mDataDict)
+        event.Skip()           #go to next handler        
+ 
+ 
+    def PlotOptionsMenu(self, event):
+        """!Popup menu for plot and text options
+        """
+        point = wx.GetMousePosition()
+        popt = wx.Menu()
+        # Add items to the menu
+        settext = wx.MenuItem(popt, wx.ID_ANY, _('Text settings'))
+        popt.AppendItem(settext)
+        self.Bind(wx.EVT_MENU, self.PlotText, settext)
+
+        setgrid = wx.MenuItem(popt, wx.ID_ANY, _('Plot settings'))
+        popt.AppendItem(setgrid)
+        self.Bind(wx.EVT_MENU, self.PlotOptions, setgrid)
+
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(popt)
+        popt.Destroy()
+
+    def NotFunctional(self):
+        """!Creates a 'not functional' message dialog
+        """
+        dlg = wx.MessageDialog(parent = self,
+                               message = _('This feature is not yet functional'),
+                               caption = _('Under Construction'),
+                               style = wx.OK | wx.ICON_INFORMATION)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    def OnPlotText(self, dlg):
+        """!Custom text settings for histogram plot.
+        """
+        self.ptitle = dlg.ptitle
+        self.xlabel = dlg.xlabel
+        self.ylabel = dlg.ylabel
+        dlg.UpdateSettings()
+
+        self.client.SetFont(self.properties['font']['wxfont'])
+        self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
+        self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
+
+        if self.plot:
+            self.plot.setTitle(dlg.ptitle)
+            self.plot.setXLabel(dlg.xlabel)
+            self.plot.setYLabel(dlg.ylabel)
+        
+        self.OnRedraw(event = None)
+    
+    def PlotText(self, event):
+        """!Set custom text values for profile title and axis labels.
+        """
+        dlg = TextDialog(parent = self, id = wx.ID_ANY, 
+                                 plottype = self.plottype, 
+                                 title = _('Histogram text settings'))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            self.OnPlotText(dlg)
+
+        dlg.Destroy()
+
+    def PlotOptions(self, event):
+        """!Set various profile options, including: line width, color,
+        style; marker size, color, fill, and style; grid and legend
+        options.  Calls OptDialog class.
+        """
+        dlg = OptDialog(parent = self, id = wx.ID_ANY, 
+                        plottype = self.plottype, 
+                        title = _('Plot settings'))
+        btnval = dlg.ShowModal()
+
+        if btnval == wx.ID_SAVE:
+            dlg.UpdateSettings()            
+            self.SetGraphStyle()            
+            dlg.Destroy()            
+        elif btnval == wx.ID_CANCEL:
+            dlg.Destroy()
+
+    def PrintMenu(self, event):
+        """!Print options and output menu
+        """
+        point = wx.GetMousePosition()
+        printmenu = wx.Menu()
+        for title, handler in ((_("Page setup"), self.OnPageSetup),
+                               (_("Print preview"), self.OnPrintPreview),
+                               (_("Print display"), self.OnDoPrint)):
+            item = wx.MenuItem(printmenu, wx.ID_ANY, title)
+            printmenu.AppendItem(item)
+            self.Bind(wx.EVT_MENU, handler, item)
+        
+        # Popup the menu.  If an item is selected then its handler
+        # will be called before PopupMenu returns.
+        self.PopupMenu(printmenu)
+        printmenu.Destroy()
+
+    def OnPageSetup(self, event):
+        self.client.PageSetup()
+
+    def OnPrintPreview(self, event):
+        self.client.PrintPreview()
+
+    def OnDoPrint(self, event):
+        self.client.Printout()
+
+    def OnQuit(self, event):
+        self.Close(True)
+
+    def OnCloseWindow(self, event):
+        """!Close plot window and clean up
+        """
+        try:
+            self.mapwin.ClearLines()
+            self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
+            self.mapwin.mouse['use'] = 'pointer'
+            self.mapwin.mouse['box'] = 'point'
+            self.mapwin.polycoords = []
+            self.mapwin.UpdateMap(render = False, renderVector = False)
+        except:
+            pass
+        
+        self.mapwin.SetCursor(self.Parent.cursors["default"])
+        self.Destroy()
+        


Property changes on: grass/trunk/gui/wxpython/wxplot/base.py
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Copied: grass/trunk/gui/wxpython/wxplot/dialogs.py (from rev 49324, grass/trunk/gui/wxpython/gui_modules/wxplot_dialogs.py)
===================================================================
--- grass/trunk/gui/wxpython/wxplot/dialogs.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/wxplot/dialogs.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,1233 @@
+"""!
+ at package wxplot.dialogs
+
+ at brief Dialogs for different plotting routines
+
+Classes:
+ - ProfileRasterDialog
+ - ScatterRasterDialog
+ - PlotStatsFrame
+ - HistRasterDialog
+ - TextDialog
+ - OptDialog
+
+(C) 2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import wx
+import wx.lib.colourselect  as csel
+import wx.lib.scrolledpanel as scrolled
+
+from core          import globalvar
+from core.settings import UserSettings
+
+from grass.script import core  as grass
+
+class ProfileRasterDialog(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, 
+                 title = _("Select raster maps to profile"),
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+        """!Dialog to select raster maps to profile.
+        """
+
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+
+
+        self.parent = parent
+        self.colorList = ["blue", "red", "green", "yellow", "magenta", "cyan", \
+                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
+                    "indigo"]
+
+        self.rasterList = self.parent.rasterList
+        
+        self._do_layout()
+        
+    def _do_layout(self):
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.GridBagSizer (hgap = 3, vgap = 3)
+        
+        rastText = ''
+        for r in self.rasterList:
+            rastText += '%s,' % r
+            
+        rastText = rastText.rstrip(',')
+        
+        txt = _("Select raster map(s) to profile:")
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = txt)
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        
+        selection = Select(self, id = wx.ID_ANY,
+                           size = globalvar.DIALOG_GSELECT_SIZE,
+                           type = 'cell', multiple=True)
+        selection.SetValue(rastText)
+        selection.Bind(wx.EVT_TEXT, self.OnSelection)
+        
+        box.Add(item = selection, pos = (0, 1))
+            
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.ALL, border = 10)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(self, wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(self, wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnSelection(self, event):
+        """!Choose maps to profile. Convert these into a list
+        """
+        self.rasterList = []
+        self.rasterList = event.GetString().split(',')
+
+class ScatterRasterDialog(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, 
+                 title = _("Select pairs of raster maps for scatterplots"),
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+        """!Dialog to select raster maps to profile.
+        """
+
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+
+        self.parent = parent
+        self.rasterList = self.parent.rasterList
+        self.bins = self.parent.bins
+        self.scattertype = self.parent.scattertype
+        self.maptype = self.parent.maptype
+        self.spinbins = ''        
+        self.colorList = ["blue", "red", "green", "yellow", "magenta", "cyan", \
+                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
+                    "indigo"]
+        
+        self._do_layout()
+        
+    def _do_layout(self):
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.GridBagSizer (hgap = 3, vgap = 3)
+        
+        # parse raster pair tuples 
+        rastText = ''
+        if len(self.rasterList) > 0:
+            for r in self.rasterList:
+                if isinstance(r, tuple):
+                    rastText += '%s,%s,' % r
+                else:
+                    rastText += '%s,' % r
+            rastText = rastText.rstrip(',')
+        
+        # select rasters
+        txt = _("Select pairs of raster maps for bivariate scatterplots:")
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = txt)
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        
+        selection = Select(self, id = wx.ID_ANY,
+                           size = globalvar.DIALOG_GSELECT_SIZE,
+                           type = 'cell', multiple=True)
+        selection.SetValue(rastText)
+        selection.Bind(wx.EVT_TEXT, self.OnSelection)
+        
+        box.Add(item = selection, pos = (0, 1))
+            
+        # Nsteps for FP maps 
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+                              label = _("Number of bins (for FP maps)"))
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+        self.spinbins = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
+                                      size = (100,-1), style = wx.SP_ARROW_KEYS)
+        self.spinbins.SetRange(1,1000)
+        self.spinbins.SetValue(self.bins)
+        box.Add(item = self.spinbins,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 1))
+
+#### TODO possibly make bubble plots with marker size proportional to cell counts
+#        # scatterplot type 
+#        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+#                              label = _("Scatterplot type"))
+#        box.Add(item = label,
+#                flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+#        types = ['normal', 'bubble']
+#        scattertype = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
+#                                choices = types, style = wx.CB_DROPDOWN)
+#        scattertype.SetStringSelection(self.scattertype)
+#        box.Add(item = scattertype,
+#                flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 1))
+          
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.ALL, border = 10)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(self, wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(self, wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
+        self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
+#        scattertype.Bind(wx.EVT_TEXT, self.OnSetScattertypes)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnSelection(self, event):
+        """!Select raster maps for scatterplot. Must select maps in pairs.
+        """
+        self.rasterList = []
+        self.rasterList = event.GetString().split(',')
+            
+    def OnSetBins(self, event):
+        """!Bins for histogramming FP maps (=nsteps in r.stats)
+        """
+        self.bins = self.spinbins.GetValue()
+        
+    def OnSetScattertypes(self, event):
+        self.scattertype = event.GetString()
+        
+class PlotStatsFrame(wx.Frame):
+    def __init__(self, parent, id, message = '', title = '',
+                 style = wx.DEFAULT_FRAME_STYLE, **kwargs):
+        """!Dialog to display and save statistics for plots
+        """
+        wx.Frame.__init__(self, parent, id, style = style, **kwargs)
+        self.SetLabel(_("Statistics"))
+        
+        sp = scrolled.ScrolledPanel(self, -1, size=(400, 400),
+                                    style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="Statistics" )
+                
+
+        #
+        # initialize variables
+        #
+        self.parent = parent
+        self.message = message 
+        self.title = title   
+        self.CenterOnParent()  
+        
+        #
+        # Display statistics
+        #
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        txtSizer = wx.BoxSizer(wx.VERTICAL)
+
+        statstitle = wx.StaticText(parent = self, id = wx.ID_ANY, label = self.title)
+        sizer.Add(item = statstitle, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
+        for stats in self.message:
+            statstxt = wx.StaticText(parent = sp, id = wx.ID_ANY, label = stats)
+            statstxt.SetBackgroundColour("WHITE")
+            txtSizer.Add(item = statstxt, proportion = 1, 
+                         flag = wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
+            line = wx.StaticLine(parent = sp, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL) 
+            txtSizer.Add(item = line, proportion = 0,
+                         flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)      
+
+        sp.SetSizer(txtSizer)
+        sp.SetAutoLayout(1)
+        sp.SetupScrolling() 
+
+        sizer.Add(item = sp, proportion = 1, 
+                  flag = wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 3)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW |wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
+
+        #
+        # buttons
+        #
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        btn_clipboard = wx.Button(self, id = wx.ID_COPY, label = _('C&opy'))
+        btn_clipboard.SetToolTipString(_("Copy regression statistics the clipboard (Ctrl+C)"))
+        btnSizer.Add(item = btn_clipboard, proportion = 0, flag = wx.ALIGN_LEFT | wx.ALL, border = 5)
+        
+        btnCancel = wx.Button(self, wx.ID_CLOSE)
+        btnCancel.SetDefault()
+        btnSizer.Add(item = btnCancel, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)        
+
+        sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        # bindings
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnClose)
+        btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
+        
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnCopy(self, event):
+        """!Copy the regression stats to the clipboard
+        """
+        str = self.title + '\n'
+        for item in self.message:
+            str += item
+            
+        rdata = wx.TextDataObject()
+        rdata.SetText(str)
+        
+        if wx.TheClipboard.Open():
+            wx.TheClipboard.SetData(rdata)
+            wx.TheClipboard.Close()
+            wx.MessageBox(_("Regression statistics copied to clipboard"))
+        
+    def OnClose(self, event):
+        """!Button 'Close' pressed
+        """
+        self.Close(True)
+
+class HistRasterDialog(wx.Dialog):
+    def __init__(self, parent, id = wx.ID_ANY, 
+                 title = _("Select raster map or imagery group to histogram"),
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+        """!Dialog to select raster maps to histogram.
+        """
+
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+
+        self.parent = parent
+        self.rasterList = self.parent.rasterList
+        self.group = self.parent.group
+        self.bins = self.parent.bins
+        self.histtype = self.parent.histtype
+        self.maptype = self.parent.maptype
+        self.spinbins = ''
+        
+        self._do_layout()
+        
+    def _do_layout(self):
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.GridBagSizer (hgap = 3, vgap = 3)
+        
+        #
+        # select single raster or image group to histogram radio buttons
+        #
+        self.rasterRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram single raster"), style = wx.RB_GROUP)
+        self.groupRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram imagery group"))
+        if self.maptype == 'raster': 
+            self.rasterRadio.SetValue(True)
+        elif self.maptype == 'group': 
+            self.groupRadio.SetValue(True)
+        box.Add(item = self.rasterRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        box.Add(item = self.groupRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
+        
+        #
+        # Select a raster to histogram
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+                              label = _("Select raster map:"))
+        box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+        self.rselection = Select(self, id = wx.ID_ANY,
+                                 size = globalvar.DIALOG_GSELECT_SIZE,
+                                 type = 'cell')
+        if self.groupRadio.GetValue() == True: 
+            self.rselection.Disable()
+        else:
+            if len(self.rasterList) > 0: self.rselection.SetValue(self.rasterList[0])
+        box.Add(item = self.rselection, pos = (1, 1))       
+
+        #
+        # Select an image group to histogram
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+                              label = _("Select image group:"))
+        box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+        self.gselection = Select(self, id = wx.ID_ANY,
+                                 size = globalvar.DIALOG_GSELECT_SIZE,
+                                 type = 'group')
+        if self.rasterRadio.GetValue() == True: 
+            self.gselection.Disable()
+        else:
+            if self.group != None: self.gselection.SetValue(self.group)
+        box.Add(item = self.gselection, pos = (2, 1))
+            
+        #
+        # Nsteps for FP maps and histogram type selection
+        #
+
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+                              label = _("Number of bins (for FP maps)"))
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
+        self.spinbins = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
+                                      size = (100,-1), style = wx.SP_ARROW_KEYS)
+        self.spinbins.SetRange(1,1000)
+        self.spinbins.SetValue(self.bins)
+        box.Add(item = self.spinbins,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 1))
+
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, 
+                              label = _("Histogram type"))
+        box.Add(item = label,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
+        types = ['count', 'percent', 'area']
+        histtype = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
+                                choices = types, style = wx.CB_DROPDOWN)
+        histtype.SetStringSelection(self.histtype)
+        box.Add(item = histtype,
+                flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 1))
+          
+        sizer.Add(item = box, proportion = 0,
+                  flag = wx.ALL, border = 10)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
+
+        btnsizer = wx.StdDialogButtonSizer()
+
+        btn = wx.Button(self, wx.ID_OK)
+        btn.SetDefault()
+        btnsizer.AddButton(btn)
+
+        btn = wx.Button(self, wx.ID_CANCEL)
+        btnsizer.AddButton(btn)
+        btnsizer.Realize()
+
+        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.rasterRadio)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.groupRadio)
+        self.rselection.Bind(wx.EVT_TEXT, self.OnRasterSelection)
+        self.gselection.Bind(wx.EVT_TEXT, self.OnGroupSelection)
+        self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
+        self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
+        histtype.Bind(wx.EVT_TEXT, self.OnSetHisttypes)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnHistMap(self, event):
+        """!Hander for radio buttons to choose between histogramming a
+            single raster and an imagery group
+        """
+        if self.rasterRadio.GetValue() == True:
+            self.maptype = 'raster'
+            self.rselection.Enable()
+            self.gselection.Disable()
+            self.gselection.SetValue('')
+        elif self.groupRadio.GetValue() == True:
+            self.maptype = 'group'
+            self.gselection.Enable()
+            self.rselection.Disable()
+            self.rselection.SetValue('')
+        else:
+            pass
+        
+    def OnRasterSelection(self, event):
+        """!Handler for selecting a single raster map
+        """
+        self.rasterList = []
+        self.rasterList.append(event.GetString())
+
+    def OnGroupSelection(self, event):
+        """!Handler for selecting imagery group
+        """
+        self.rasterList = []
+        self.group = event.GetString()
+        ret = grass.read_command('i.group', 
+                                  group = '%s' % self.group, 
+                                  quiet = True,
+                                  flags = 'g').strip().split('\n')
+        if ret != None and ret != '':
+            self.rasterList = ret
+                                                                                            
+    def OnSetBins(self, event):
+        """!Bins for histogramming FP maps (=nsteps in r.stats)
+        """
+        self.bins = self.spinbins.GetValue()
+        
+    def OnSetHisttypes(self, event):
+        self.histtype = event.GetString()
+        
+
+class TextDialog(wx.Dialog):
+    def __init__(self, parent, id, title, plottype = '',
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+        """!Dialog to set histogram text options: font, title
+        and font size, axis labels and font size
+        """
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+        #
+        # initialize variables
+        #
+        # combo box entry lists
+        self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
+                             'decorative' : wx.FONTFAMILY_DECORATIVE,
+                             'roman' : wx.FONTFAMILY_ROMAN,
+                             'script' : wx.FONTFAMILY_SCRIPT,
+                             'swiss' : wx.FONTFAMILY_SWISS,
+                             'modern' : wx.FONTFAMILY_MODERN,
+                             'teletype' : wx.FONTFAMILY_TELETYPE }
+
+        self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
+                            'slant' : wx.FONTSTYLE_SLANT,
+                            'italic' : wx.FONTSTYLE_ITALIC }
+
+        self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
+                         'light' : wx.FONTWEIGHT_LIGHT,
+                         'bold' : wx.FONTWEIGHT_BOLD }
+
+        self.parent = parent
+
+        self.ptitle = self.parent.ptitle
+        self.xlabel = self.parent.xlabel
+        self.ylabel = self.parent.ylabel
+
+        self.properties = self.parent.properties # read-only
+        
+        # font size
+        self.fontfamily = self.properties['font']['wxfont'].GetFamily()
+        self.fontstyle = self.properties['font']['wxfont'].GetStyle()
+        self.fontweight = self.properties['font']['wxfont'].GetWeight()
+
+        self._do_layout()
+                
+    def _do_layout(self):
+        """!Do layout"""
+        # dialog layout
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Text settings"))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+
+        #
+        # profile title
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Profile title:"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        self.ptitleentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
+        # self.ptitleentry.SetFont(self.font)
+        self.ptitleentry.SetValue(self.ptitle)
+        gridSizer.Add(item = self.ptitleentry, pos = (0, 1))
+
+        #
+        # title font
+        #
+        tlabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Title font size (pts):"))
+        gridSizer.Add(item = tlabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+        self.ptitlesize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
+                                      size = (50,-1), style = wx.SP_ARROW_KEYS)
+        self.ptitlesize.SetRange(5,100)
+        self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
+        gridSizer.Add(item = self.ptitlesize, pos = (1, 1))
+
+        #
+        # x-axis label
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("X-axis label:"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+        self.xlabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
+        # self.xlabelentry.SetFont(self.font)
+        self.xlabelentry.SetValue(self.xlabel)
+        gridSizer.Add(item = self.xlabelentry, pos = (2, 1))
+
+        #
+        # y-axis label
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Y-axis label:"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
+        self.ylabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
+        # self.ylabelentry.SetFont(self.font)
+        self.ylabelentry.SetValue(self.ylabel)
+        gridSizer.Add(item = self.ylabelentry, pos = (3, 1))
+
+        #
+        # font size
+        #
+        llabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Label font size (pts):"))
+        gridSizer.Add(item = llabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
+        self.axislabelsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
+                                         size = (50, -1), style = wx.SP_ARROW_KEYS)
+        self.axislabelsize.SetRange(5, 100) 
+        self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
+        gridSizer.Add(item = self.axislabelsize, pos = (4,1))
+
+        boxSizer.Add(item = gridSizer)
+        sizer.Add(item = boxSizer, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        #
+        # font settings
+        #
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Font settings"))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        gridSizer.AddGrowableCol(1)
+
+        #
+        # font family
+        #
+        label1 = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Font family:"))
+        gridSizer.Add(item = label1, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+        self.ffamilycb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
+                                choices = self.ffamilydict.keys(), style = wx.CB_DROPDOWN)
+        self.ffamilycb.SetStringSelection('swiss')
+        for item in self.ffamilydict.items():
+            if self.fontfamily == item[1]:
+                self.ffamilycb.SetStringSelection(item[0])
+                break
+        gridSizer.Add(item = self.ffamilycb, pos = (0, 1), flag = wx.ALIGN_RIGHT)
+
+        #
+        # font style
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style:"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+        self.fstylecb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
+                                    choices = self.fstyledict.keys(), style = wx.CB_DROPDOWN)
+        self.fstylecb.SetStringSelection('normal')
+        for item in self.fstyledict.items():
+            if self.fontstyle == item[1]:
+                self.fstylecb.SetStringSelection(item[0])
+                break
+        gridSizer.Add(item = self.fstylecb, pos = (1, 1), flag = wx.ALIGN_RIGHT)
+
+        #
+        # font weight
+        #
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Weight:"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+        self.fwtcb = wx.ComboBox(parent = self, size = (250, -1),
+                                 choices = self.fwtdict.keys(), style = wx.CB_DROPDOWN)
+        self.fwtcb.SetStringSelection('normal')
+        for item in self.fwtdict.items():
+            if self.fontweight == item[1]:
+                self.fwtcb.SetStringSelection(item[0])
+                break
+
+        gridSizer.Add(item = self.fwtcb, pos = (2, 1), flag = wx.ALIGN_RIGHT)
+                      
+        boxSizer.Add(item = gridSizer, flag = wx.EXPAND)
+        sizer.Add(item = boxSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
+
+        #
+        # buttons
+        #
+        btnSave = wx.Button(self, wx.ID_SAVE)
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnOk = wx.Button(self, wx.ID_OK)
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnOk.SetDefault()
+
+        # bindings
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnApply.SetToolTipString(_("Apply changes for the current session"))
+        btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
+        btnOk.SetToolTipString(_("Apply changes for the current session and close dialog"))
+        btnOk.SetDefault()
+        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+
+        # sizers
+        btnStdSizer = wx.StdDialogButtonSizer()
+        btnStdSizer.AddButton(btnOk)
+        btnStdSizer.AddButton(btnApply)
+        btnStdSizer.AddButton(btnCancel)
+        btnStdSizer.Realize()
+        
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(item = btnSave, proportion = 0, flag = wx.ALIGN_LEFT | wx.ALL, border = 5)
+        btnSizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+        sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        #
+        # bindings
+        #
+        self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
+        self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
+        self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnTitle(self, event):
+        self.ptitle = event.GetString()
+
+    def OnXLabel(self, event):
+        self.xlabel = event.GetString()
+
+    def OnYLabel(self, event):
+        self.ylabel = event.GetString()
+
+    def UpdateSettings(self):
+        self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
+        self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()
+
+        family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
+        self.properties['font']['wxfont'].SetFamily(family)
+        style = self.fstyledict[self.fstylecb.GetStringSelection()]
+        self.properties['font']['wxfont'].SetStyle(style)
+        weight = self.fwtdict[self.fwtcb.GetStringSelection()]
+        self.properties['font']['wxfont'].SetWeight(weight)
+
+    def OnSave(self, event):
+        """!Button 'Save' pressed"""
+        self.UpdateSettings()
+        fileSettings = {}
+        UserSettings.ReadSettingsFile(settings=fileSettings)
+        fileSettings['plot'] = UserSettings.Get(group = 'plot')
+        file = UserSettings.SaveToFile(fileSettings)
+        self.parent.parent.GetLayerManager().goutput.WriteLog(_('Plot text settings saved to file \'%s\'.') % file)
+        self.EndModal(wx.ID_OK)
+
+    def OnApply(self, event):
+        """!Button 'Apply' pressed"""
+        self.UpdateSettings()
+        self.parent.OnPlotText(self)
+        
+    def OnOk(self, event):
+        """!Button 'OK' pressed"""
+        self.UpdateSettings()
+        self.EndModal(wx.ID_OK)
+
+    def OnCancel(self, event):
+        """!Button 'Cancel' pressed"""
+        self.EndModal(wx.ID_CANCEL)
+        
+class OptDialog(wx.Dialog):
+    def __init__(self, parent, id, title, plottype = '',
+                 style = wx.DEFAULT_DIALOG_STYLE, **kwargs): 
+        """!Dialog to set various options for data plotted, including: line
+        width, color, style; marker size, color, fill, and style; grid
+        and legend options.
+        """
+        wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+        # init variables
+        self.parent = parent
+        self.linestyledict = parent.linestyledict
+        self.ptfilldict = parent.ptfilldict
+        self.plottype = plottype
+        
+        self.pttypelist = ['circle',
+                           'dot',
+                           'square',
+                           'triangle',
+                           'triangle_down',
+                           'cross',
+                           'plus']
+        
+        self.axislist = ['min',
+                         'auto',
+                         'custom']
+
+        # widgets ids
+        self.wxId = {}
+        
+        self.parent = parent
+
+        # read-only
+        self.raster = self.parent.raster
+        self.rasterList = self.parent.rasterList
+        self.properties = self.parent.properties
+        self.map = ''
+        
+        if len(self.rasterList) == 0:
+            wx.MessageBox(parent = self,
+                              message = _("No map or image group selected to plot."),
+                              caption = _("Warning"), style = wx.OK | wx.ICON_ERROR)
+            
+        self._do_layout()
+        
+    def ConvertTuples(self, tlist):
+        """!Converts tuples to strings when rasterList contains raster pairs
+            for scatterplot
+        """
+        list = []
+        for i in tlist:
+            i = str(i).strip('()')
+            list.append(i)
+            
+        return list
+
+    def _do_layout(self):
+        """!Do layout"""
+        # dialog layout
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Plot settings")) 
+        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+        self.wxId['pcolor']  = 0
+        self.wxId['pwidth']  = 0
+        self.wxId['pstyle']  = 0
+        self.wxId['psize'] = 0
+        self.wxId['ptype'] = 0
+        self.wxId['pfill'] = 0
+        self.wxId['plegend'] = 0
+        self.wxId['marker'] = {}
+        self.wxId['x-axis'] = {}
+        self.wxId['y-axis'] = {}
+        
+        #
+        # plot line settings and point settings
+        #
+        if len(self.rasterList) == 0: return
+        
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = _("Map/image plotted"))
+        boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+        
+        row = 0
+        choicelist = []
+        for i in self.rasterList:
+            choicelist.append(str(i))
+
+        self.mapchoice = wx.Choice(parent = self, id = wx.ID_ANY, size = (300, -1),
+                                   choices = choicelist)
+        if not self.map:
+            self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
+        else:
+            self.mapchoice.SetStringSelection(str(self.map))
+            
+                
+        gridSizer.Add(item = self.mapchoice, flag = wx.ALIGN_CENTER_VERTICAL, 
+                      pos = (row, 0), span = (1, 2))
+        
+        #
+        # options for line plots (profiles and histograms)
+        #
+        if self.plottype != 'scatter':
+            row +=1            
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line color"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            color = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.raster[self.map]['pcolor'])
+            self.wxId['pcolor'] = color.GetId()
+            gridSizer.Add(item = color, pos = (row, 1))
+
+            row += 1
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line width"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            width = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
+                                 size = (50,-1), style = wx.SP_ARROW_KEYS)
+            width.SetRange(1, 10)
+            width.SetValue(self.raster[self.map]['pwidth'])
+            self.wxId['pwidth'] = width.GetId()
+            gridSizer.Add(item = width, pos = (row, 1))
+
+            row +=1
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line style"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            style = wx.Choice(parent = self, id = wx.ID_ANY, 
+                                 size = (120, -1), choices = self.linestyledict.keys(), style = wx.CB_DROPDOWN)
+            style.SetStringSelection(self.raster[self.map]['pstyle'])
+            self.wxId['pstyle'] = style.GetId()
+            gridSizer.Add(item = style, pos = (row, 1))
+
+        row += 1
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+        legend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
+        legend.SetValue(self.raster[self.map]['plegend'])
+        gridSizer.Add(item = legend, pos = (row, 1))
+        self.wxId['plegend'] = legend.GetId()
+        
+        boxSizer.Add(item = gridSizer)
+        boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
+
+        #
+        # segment marker settings for profiles only
+        #       
+        if self.plottype == 'profile':
+            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                               label = " %s " % _("Transect segment marker settings"))
+            
+            boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+            
+            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Color"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+            ptcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.properties['marker']['color'])
+            self.wxId['marker']['color'] = ptcolor.GetId()
+            gridSizer.Add(item = ptcolor, pos = (0, 1))
+
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Size"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+            ptsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
+                                 size = (50, -1), style = wx.SP_ARROW_KEYS)
+            ptsize.SetRange(1, 10)
+            ptsize.SetValue(self.properties['marker']['size'])
+            self.wxId['marker']['size'] = ptsize.GetId()
+            gridSizer.Add(item = ptsize, pos = (1, 1))
+            
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+            ptfill = wx.ComboBox(parent = self, id = wx.ID_ANY,
+                                 size = (120, -1), choices = self.ptfilldict.keys(), style = wx.CB_DROPDOWN)
+            ptfill.SetStringSelection(self.properties['marker']['fill'])
+            self.wxId['marker']['fill'] = ptfill.GetId()
+            gridSizer.Add(item = ptfill, pos = (2, 1))
+            
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
+            ptlegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
+            ptlegend.SetValue(self.properties['marker']['legend'])
+            self.wxId['marker']['legend'] = ptlegend.GetId()
+            gridSizer.Add(item = ptlegend, pos = (3, 1))
+                    
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Type"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
+            pttype = wx.ComboBox(parent = self, 
+                                 size = (200, -1), choices = self.pttypelist, style = wx.CB_DROPDOWN)
+            pttype.SetStringSelection(self.properties['marker']['type'])
+            self.wxId['marker']['type'] = pttype.GetId()
+            gridSizer.Add(item = pttype, pos = (4, 1))
+
+            boxSizer.Add(item = gridSizer)
+            boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
+            
+        #
+        # point options for scatterplots
+        #
+        elif self.plottype == 'scatter':
+            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                               label = " %s " % _("Scatterplot points"))
+            
+            boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+            
+            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Color"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+            ptcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.raster[self.map]['pcolor'])
+            self.wxId['pcolor'] = ptcolor.GetId()
+            gridSizer.Add(item = ptcolor, pos = (0, 1))
+
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Size"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
+            ptsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
+                                 size = (50, -1), style = wx.SP_ARROW_KEYS)
+            ptsize.SetRange(1, 10)
+            ptsize.SetValue(self.raster[self.map]['psize'])
+            self.wxId['psize'] = ptsize.GetId()
+            gridSizer.Add(item = ptsize, pos = (1, 1))
+            
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
+            ptfill = wx.ComboBox(parent = self, id = wx.ID_ANY,
+                                 size = (120, -1), choices = self.ptfilldict.keys(), style = wx.CB_DROPDOWN)
+            ptfill.SetStringSelection(self.raster[self.map]['pfill'])
+            self.wxId['pfill'] = ptfill.GetId()
+            gridSizer.Add(item = ptfill, pos = (2, 1))
+            
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
+            ptlegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
+            ptlegend.SetValue(self.raster[self.map]['plegend'])
+            self.wxId['plegend'] = ptlegend.GetId()
+            gridSizer.Add(item = ptlegend, pos = (3, 1))
+                    
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Type"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
+            pttype = wx.ComboBox(parent = self, 
+                                 size = (200, -1), choices = self.pttypelist, style = wx.CB_DROPDOWN)
+            pttype.SetStringSelection(self.raster[self.map]['ptype'])
+            self.wxId['ptype'] = pttype.GetId()
+            gridSizer.Add(item = pttype, pos = (4, 1))
+
+            boxSizer.Add(item = gridSizer)
+            boxMainSizer.Add(item = boxSizer, flag = wx.ALL, border = 3)
+            
+        sizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        #
+        # axis options for all plots
+        #
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Axis settings"))
+        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+        middleSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        idx = 0
+        for axis, atype in [(_("X-Axis"), 'x-axis'),
+                     (_("Y-Axis"), 'y-axis')]:
+            box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                               label = " %s " % axis)
+            boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+            gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+
+            prop = self.properties[atype]['prop']
+            
+            row = 0
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            type = wx.Choice(parent = self, id = wx.ID_ANY,
+                               size = (100, -1), choices = self.axislist, style = wx.CB_DROPDOWN)
+            type.SetStringSelection(prop['type']) 
+            self.wxId[atype]['type'] = type.GetId()
+            gridSizer.Add(item = type, pos = (row, 1))
+                        
+            row += 1
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom min"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            min = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
+            min.SetValue(str(prop['min']))
+            self.wxId[atype]['min'] = min.GetId()
+            gridSizer.Add(item = min, pos = (row, 1))
+
+            row += 1
+            label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom max"))
+            gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+            max = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
+            max.SetValue(str(prop['max']))
+            self.wxId[atype]['max'] = max.GetId()
+            gridSizer.Add(item = max, pos = (row, 1))
+            
+            row += 1
+            log = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Log scale"))
+            log.SetValue(prop['log'])
+            self.wxId[atype]['log'] = log.GetId()
+            gridSizer.Add(item = log, pos = (row, 0), span = (1, 2))
+
+            if idx == 0:
+                flag = wx.ALL | wx.EXPAND
+            else:
+                flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
+
+            boxSizer.Add(item = gridSizer, flag = wx.ALL, border = 3)
+            boxMainSizer.Add(item = boxSizer, flag = flag, border = 3)
+
+            idx += 1
+            
+        middleSizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
+
+        #
+        # grid & legend options for all plots
+        #
+        self.wxId['grid'] = {}
+        self.wxId['legend'] = {}
+        self.wxId['font'] = {}
+        box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+                           label = " %s " % _("Grid and Legend settings"))
+        boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+        gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
+
+        row = 0
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Grid color"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+        gridcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.properties['grid']['color'])
+        self.wxId['grid']['color'] = gridcolor.GetId()
+        gridSizer.Add(item = gridcolor, pos = (row, 1))
+
+        row +=1
+        gridshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show grid"))
+        gridshow.SetValue(self.properties['grid']['enabled'])
+        self.wxId['grid']['enabled'] = gridshow.GetId()
+        gridSizer.Add(item = gridshow, pos = (row, 0), span = (1, 2))
+
+        row +=1
+        label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend font size"))
+        gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
+        legendfontsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", 
+                                     size = (50, -1), style = wx.SP_ARROW_KEYS)
+        legendfontsize.SetRange(5,100)
+        legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
+        self.wxId['font']['legendSize'] = legendfontsize.GetId()
+        gridSizer.Add(item = legendfontsize, pos = (row, 1))
+
+        row += 1
+        legendshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show legend"))
+        legendshow.SetValue(self.properties['legend']['enabled'])
+        self.wxId['legend']['enabled'] = legendshow.GetId()
+        gridSizer.Add(item = legendshow, pos = (row, 0), span = (1, 2))
+
+        boxMainSizer.Add(item = gridSizer, flag = flag, border = 3)
+
+        middleSizer.Add(item = boxMainSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+        sizer.Add(item = middleSizer, flag = wx.ALL, border = 0)
+        
+        #
+        # line & buttons
+        #
+        line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
+        sizer.Add(item = line, proportion = 0,
+                  flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
+
+        #
+        # buttons
+        #
+        btnSave = wx.Button(self, wx.ID_SAVE)
+        btnApply = wx.Button(self, wx.ID_APPLY)
+        btnCancel = wx.Button(self, wx.ID_CANCEL)
+        btnSave.SetDefault()
+
+        # tooltips for buttons
+        btnApply.SetToolTipString(_("Apply changes for the current session"))
+        btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
+        btnSave.SetDefault()
+        btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+
+        # sizers
+        btnStdSizer = wx.StdDialogButtonSizer()
+        btnStdSizer.AddButton(btnCancel)
+        btnStdSizer.AddButton(btnSave)
+        btnStdSizer.AddButton(btnApply)
+        btnStdSizer.Realize()
+        
+        sizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+        #
+        # bindings for buttons and map plot settings controls
+        #
+        self.mapchoice.Bind(wx.EVT_CHOICE, self.OnSetMap)
+        
+        if self.plottype != 'scatter':
+            color.Bind(csel.EVT_COLOURSELECT, self.OnSetOpt)
+            width.Bind(wx.EVT_SPINCTRL, self.OnSetOpt)
+            style.Bind(wx.EVT_CHOICE, self.OnSetOpt)
+            legend.Bind(wx.EVT_TEXT, self.OnSetOpt)
+            
+        if self.plottype != 'histogram':
+            ptcolor.Bind(csel.EVT_COLOURSELECT, self.OnSetOpt)
+            ptsize.Bind(wx.EVT_SPINCTRL, self.OnSetOpt)
+            ptfill.Bind(wx.EVT_CHOICE, self.OnSetOpt)
+            ptlegend.Bind(wx.EVT_TEXT, self.OnSetOpt)
+            pttype.Bind(wx.EVT_CHOICE, self.OnSetOpt)
+            
+        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+        btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
+        btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+
+    def OnSetMap(self, event):
+        """!Handler for changing map selection"""
+        idx = event.GetSelection()
+        self.map = self.rasterList[idx]
+        
+        # update settings controls for all plots
+        self.FindWindowById(self.wxId['pcolor']).SetColour(self.raster[self.map]['pcolor'])
+        self.FindWindowById(self.wxId['plegend']).SetValue(self.raster[self.map]['plegend'])
+
+        # update settings controls for histograms and profiles
+        if self.plottype != 'scatter':
+            self.FindWindowById(self.wxId['pwidth']).SetValue(self.raster[self.map]['pwidth'])
+            self.FindWindowById(self.wxId['pstyle']).SetStringSelection(self.raster[self.map]['pstyle'])
+
+        # update settings controls for scatterplots
+        elif self.plottype == 'scatter':
+            self.FindWindowById(self.wxId['psize']).SetValue(self.raster[self.map]['psize'])
+            self.FindWindowById(self.wxId['ptype']).SetStringSelection(self.raster[self.map]['ptype'])
+            self.FindWindowById(self.wxId['pfill']).SetStringSelection(self.raster[self.map]['pfill'])
+            
+        self.Refresh()
+        
+    def OnSetOpt(self, event):
+        """!Handler for changing any other option"""
+        self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
+        self.UpdateSettings()
+        self.parent.SetGraphStyle()
+        if self.parent.plot:
+            p = self.parent.CreatePlotList()
+            self.parent.DrawPlot(p)
+
+    def UpdateSettings(self):
+        """!Apply settings to each map and to entire plot"""
+        
+        # update plot settings for selected map
+        self.raster[self.map]['pcolor'] = self.FindWindowById(self.wxId['pcolor']).GetColour()
+        self.raster[self.map]['plegend'] = self.FindWindowById(self.wxId['plegend']).GetValue()
+        
+        if self.plottype != 'scatter':
+            self.raster[self.map]['pwidth'] = int(self.FindWindowById(self.wxId['pwidth']).GetValue())
+            self.raster[self.map]['pstyle'] = self.FindWindowById(self.wxId['pstyle']).GetStringSelection()
+            
+        elif self.plottype == 'scatter':
+            self.raster[self.map]['psize'] = self.FindWindowById(self.wxId['psize']).GetValue()
+            self.raster[self.map]['ptype'] = self.FindWindowById(self.wxId['ptype']).GetValue()
+            self.raster[self.map]['pfill'] = self.FindWindowById(self.wxId['pfill']).GetValue()
+
+        # update settings for entire plot
+        for axis in ('x-axis', 'y-axis'):
+            self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetStringSelection()
+            self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
+            self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
+            self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()
+
+        if self.plottype == 'profile':
+            self.properties['marker']['color'] = self.FindWindowById(self.wxId['marker']['color']).GetColour()
+            self.properties['marker']['fill'] = self.FindWindowById(self.wxId['marker']['fill']).GetStringSelection()
+            self.properties['marker']['size'] = self.FindWindowById(self.wxId['marker']['size']).GetValue()
+            self.properties['marker']['type'] = self.FindWindowById(self.wxId['marker']['type']).GetValue()
+            self.properties['marker']['legend'] = self.FindWindowById(self.wxId['marker']['legend']).GetValue()
+
+        self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
+        self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()
+
+        self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
+        self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()
+
+    def OnSave(self, event):
+        """!Button 'Save' pressed"""
+        self.OnApply(None)
+        fileSettings = {}
+        UserSettings.ReadSettingsFile(settings = fileSettings)
+        fileSettings[self.plottype] = UserSettings.Get(group = self.plottype)
+        file = UserSettings.SaveToFile(fileSettings)
+        self.parent.parent.GetLayerManager().goutput.WriteLog(_('Plot settings saved to file \'%s\'.') % file)
+        self.Close()
+
+    def OnApply(self, event):
+        """!Button 'Apply' pressed. Does not close dialog"""
+        self.UpdateSettings()
+        self.parent.SetGraphStyle()
+        if self.parent.plot:
+            p = self.parent.CreatePlotList()
+            self.parent.DrawPlot(p)
+        
+    def OnCancel(self, event):
+        """!Button 'Cancel' pressed"""
+        self.Close()
+     


Property changes on: grass/trunk/gui/wxpython/wxplot/dialogs.py
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/wxplot/histogram.py
===================================================================
--- grass/trunk/gui/wxpython/wxplot/histogram.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/wxplot/histogram.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,260 @@
+"""!
+ at package wxplot.histogram
+
+ at brief Histogramming using PyPlot
+
+Classes:
+ - Histogram2Frame
+ - Histogram2Toolbar
+
+(C) 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import sys
+
+import wx
+import wx.lib.plot as plot
+
+import grass.script as grass
+
+from gui_core.toolbars import BaseToolbar
+from wxplot.base       import BasePlotFrame
+
+class Histogram2Frame(BasePlotFrame):
+    def __init__(self, parent, id, pos, style, size, rasterList = []):
+        """!Mainframe for displaying histogram of raster map. Uses wx.lib.plot.
+        """
+        BasePlotFrame.__init__(self, parent)
+        
+        self.toolbar = Histogram2Toolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+        self.SetLabel(_("GRASS Histogramming Tool"))
+
+        #
+        # Init variables
+        #
+        self.rasterList = rasterList
+        self.plottype = 'histogram'
+        self.group = '' 
+        self.ptitle = _('Histogram of')         # title of window
+        self.xlabel = _("Raster cell values")   # default X-axis label
+        self.ylabel = _("Cell counts")          # default Y-axis label
+        self.maptype = 'raster'                 # default type of histogram to plot
+        self.histtype = 'count' 
+        self.bins = 255
+        self.colorList = ["blue", "green", "red", "yellow", "magenta", "cyan", \
+                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
+                    "indigo"]
+        
+        if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
+            self.InitRasterOpts(self.rasterList, self.plottype)
+
+        self._initOpts()
+
+    def _initOpts(self):
+        """!Initialize plot options
+        """
+        self.InitPlotOpts('histogram')            
+
+    def OnCreateHist(self, event):
+        """!Main routine for creating a histogram. Uses r.stats to
+        create a list of cell value and count/percent/area pairs. This is passed to
+        plot to create a line graph of the histogram.
+        """
+        self.SetCursor(self.parent.cursors["default"])
+        self.SetGraphStyle()
+        self.SetupHistogram()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+
+    def OnSelectRaster(self, event):
+        """!Select raster map(s) to profile
+        """
+        dlg = dialogs.HistRasterDialog(parent = self)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            self.rasterList = dlg.rasterList
+            self.group = dlg.group
+            self.bins = dlg.bins
+            self.histtype = dlg.histtype
+            self.maptype = dlg.maptype
+            self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
+
+            # plot histogram
+            if len(self.rasterList) > 0:
+                self.OnCreateHist(event = None)
+
+        dlg.Destroy()
+
+    def SetupHistogram(self):
+        """!Build data list for ploting each raster
+        """
+
+        #
+        # populate raster dictionary
+        #
+        if len(self.rasterList) == 0: return  # nothing selected
+        
+        for r in self.rasterList:
+            self.raster[r]['datalist'] = self.CreateDatalist(r)
+            
+        #
+        # update title
+        #
+        if self.maptype == 'group':
+            self.ptitle = _('Histogram of %s') % self.group.split('@')[0] 
+        else: 
+            self.ptitle = _('Histogram of %s') % self.rasterList[0].split('@')[0] 
+
+        
+        #
+        # set xlabel based on first raster map in list to be histogrammed
+        #
+        units = self.raster[self.rasterList[0]]['units']
+        if units != '' and units != '(none)' and units != None:
+            self.xlabel = _('Raster cell values %s') % units
+        else:
+            self.xlabel = _('Raster cell values') 
+
+        #
+        # set ylabel from self.histtype
+        #
+        if self.histtype == 'count': self.ylabel = _('Cell counts')
+        if self.histtype == 'percent': self.ylabel = _('Percent of total cells')
+        if self.histtype == 'area': self.ylabel = _('Area')
+
+    def CreateDatalist(self, raster):
+        """!Build a list of cell value, frequency pairs for histogram
+            frequency can be in cell counts, percents, or area
+        """
+        datalist = []
+        
+        if self.histtype == 'count': freqflag = 'cn'
+        if self.histtype == 'percent': freqflag = 'pn'
+        if self.histtype == 'area': freqflag = 'an'
+                
+        try:
+            ret = gcmd.RunCommand("r.stats",
+                                  parent = self,
+                                  input = raster,
+                                  flags = freqflag,
+                                  nsteps = self.bins,
+                                  fs = ',',
+                                  quiet = True,
+                                  read = True)
+            
+            if not ret:
+                return datalist
+            
+            for line in ret.splitlines():
+                cellval, histval = line.strip().split(',')
+                histval = histval.strip()
+                if self.raster[raster]['datatype'] != 'CELL':
+                    cellval = cellval.split('-')[0]
+                if self.histtype == 'percent':
+                    histval = histval.rstrip('%')
+                    
+                datalist.append((cellval,histval))
+
+            return datalist
+        except gcmd.GException, e:
+            gcmd.GError(parent = self,
+                        message = e.value)
+            return None
+        
+    def CreatePlotList(self):
+        """!Make list of elements to plot
+        """
+        
+        # graph the cell value, frequency pairs for the histogram
+        self.plotlist = []
+
+        for r in self.rasterList:
+            if len(self.raster[r]['datalist']) > 0:
+                col = wx.Color(self.raster[r]['pcolor'][0],
+                               self.raster[r]['pcolor'][1],
+                               self.raster[r]['pcolor'][2],
+                               255)
+                self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
+                                                        colour = col,
+                                                        width = self.raster[r]['pwidth'],
+                                                        style = self.linestyledict[self.raster[r]['pstyle']],
+                                                        legend = self.raster[r]['plegend'])
+
+                self.plotlist.append(self.raster[r]['pline'])
+          
+        if len(self.plotlist) > 0:        
+            return self.plotlist
+        else:
+            return None
+
+    def Update(self):
+        """!Update histogram after changing options
+        """
+        self.SetGraphStyle()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+ 
+    def OnStats(self, event):
+        """!Displays regression information in messagebox
+        """
+        message = []
+        title = _('Statistics for Map(s) Histogrammed')
+
+        for r in self.rasterList:
+            rast = r.split('@')[0] 
+            ret = grass.read_command('r.univar', map = r, flags = 'e', quiet = True)
+            stats = _('Statistics for %s\n\n%s\n') % (rast, ret)
+            message.append(stats)
+            
+        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
+                                      title = title)
+
+        if stats.Show() == wx.ID_CLOSE:
+            stats.Destroy()       
+
+class Histogram2Toolbar(BaseToolbar):
+    """!Toolbar for histogramming raster map
+    """ 
+    def __init__(self, parent):
+        AbstractToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['plot']
+        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
+                                      self.parent.OnSelectRaster),
+                                     (None, ),
+                                     ('draw', icons["draw"],
+                                      self.parent.OnCreateHist),
+                                     ('erase', Icons['displayWindow']["erase"],
+                                      self.parent.OnErase),
+                                     ('drag', Icons['displayWindow']['pan'],
+                                      self.parent.OnDrag),
+                                     ('zoom', Icons['displayWindow']['zoomIn'],
+                                      self.parent.OnZoom),
+                                     ('unzoom', Icons['displayWindow']['zoomBack'],
+                                      self.parent.OnRedraw),
+                                     (None, ),
+                                     ('statistics', icons['statistics'],
+                                      self.parent.OnStats),
+                                     ('image', Icons['displayWindow']["saveFile"],
+                                      self.parent.SaveToFile),
+                                     ('print', Icons['displayWindow']["print"],
+                                      self.parent.PrintMenu),
+                                     (None, ),
+                                     ('settings', icons["options"],
+                                      self.parent.PlotOptionsMenu),
+                                     ('quit', icons["quit"],
+                                      self.parent.OnQuit),
+                                     )
+)


Property changes on: grass/trunk/gui/wxpython/wxplot/histogram.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/wxplot/profile.py
===================================================================
--- grass/trunk/gui/wxpython/wxplot/profile.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/wxplot/profile.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,427 @@
+"""!
+ at package wxplot.profile
+
+ at brief Profiling using PyPlot
+
+Classes:
+ - ProfileFrame
+ - ProfileToolbar
+
+(C) 2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import os
+import sys
+import math
+
+import wx
+import wx.lib.plot as plot
+
+import grass.script as grass
+
+try:
+    import numpy
+except ImportError:
+    msg = _("This module requires the NumPy module, which could not be "
+            "imported. It probably is not installed (it's not part of the "
+            "standard Python distribution). See the Numeric Python site "
+            "(http://numpy.scipy.org) for information on downloading source or "
+            "binaries.")
+    print >> sys.stderr, "wxplot.py: " + msg
+
+from wxplot.base       import BasePlotFrame
+from gui_core.toolbars import BaseToolbar
+
+class ProfileFrame(BasePlotFrame):
+    """!Mainframe for displaying profile of one or more raster maps. Uses wx.lib.plot.
+    """
+    def __init__(self, parent, id, pos, style, size, rasterList = []):
+
+        BasePlotFrame.__init__(self, parent)
+
+        self.toolbar = ProfileToolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+        self.SetLabel(_("GRASS Profile Analysis Tool"))
+
+        #
+        # Init variables
+        #
+        self.rasterList = rasterList
+        self.plottype = 'profile'
+        self.coordstr = ''              # string of coordinates for r.profile
+        self.seglist = []               # segment endpoint list
+        self.ppoints = ''               # segment endpoints data         
+        self.transect_length = 0.0      # total transect length        
+        self.ptitle = _('Profile of')   # title of window
+        self.raster = {}
+
+        self.colorList =  ["blue", "red", "green", "yellow", "magenta", "cyan", \
+                    "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
+                    "indigo"]
+
+        if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
+            self.InitRasterOpts(self.rasterList, self.plottype)
+            
+        
+        self._initOpts()
+
+        # determine units (axis labels)
+        if self.parent.Map.projinfo['units'] != '':
+            self.xlabel = _('Distance (%s)') % self.parent.Map.projinfo['units']
+        else:
+            self.xlabel = _("Distance along transect")
+        self.ylabel = _("Cell values")
+        
+    def _initOpts(self):
+        """!Initialize plot options
+        """
+        self.InitPlotOpts('profile')
+
+    def OnDrawTransect(self, event):
+        """!Draws transect to profile in map display
+        """
+        self.mapwin.polycoords = []
+        self.seglist = []
+        self.mapwin.ClearLines(self.mapwin.pdc)
+        self.ppoints = ''
+
+        self.parent.SetFocus()
+        self.parent.Raise()
+        
+        self.mapwin.mouse['use'] = 'profile'
+        self.mapwin.mouse['box'] = 'line'
+        self.mapwin.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
+        self.mapwin.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SHORT_DASH)
+        self.mapwin.SetCursor(self.Parent.cursors["cross"])
+
+    def OnSelectRaster(self, event):
+        """!Select raster map(s) to profile
+        """
+        dlg = dialogs.ProfileRasterDialog(parent = self)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            self.rasterList = dlg.rasterList
+            self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
+            
+            # plot profile
+            if len(self.mapwin.polycoords) > 0 and len(self.rasterList) > 0:
+                self.OnCreateProfile(event = None)
+
+        dlg.Destroy()
+
+    def SetupProfile(self):
+        """!Create coordinate string for profiling. Create segment list for
+           transect segment markers.
+        """
+
+        #
+        # create list of coordinate points for r.profile
+        #                
+        dist = 0
+        cumdist = 0
+        self.coordstr = ''
+        lasteast = lastnorth = None
+        
+        if len(self.mapwin.polycoords) > 0:
+            for point in self.mapwin.polycoords:
+                # build string of coordinate points for r.profile
+                if self.coordstr == '':
+                    self.coordstr = '%d,%d' % (point[0], point[1])
+                else:
+                    self.coordstr = '%s,%d,%d' % (self.coordstr, point[0], point[1])
+
+        if len(self.rasterList) == 0:
+            return
+
+        # title of window
+        self.ptitle = _('Profile of')
+
+        #
+        # create list of coordinates for transect segment markers
+        #
+        if len(self.mapwin.polycoords) > 0:
+            self.seglist = []
+            for point in self.mapwin.polycoords:
+                # get value of raster cell at coordinate point
+                ret = gcmd.RunCommand('r.what',
+                                      parent = self,
+                                      read = True,
+                                      input = self.rasterList[0],
+                                      east_north = '%d,%d' % (point[0],point[1]))
+                
+                val = ret.splitlines()[0].split('|')[3]
+                if val == None or val == '*': continue
+                val = float(val)
+                
+                # calculate distance between coordinate points
+                if lasteast and lastnorth:
+                    dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
+                cumdist += dist
+                
+                #store total transect length
+                self.transect_length = cumdist
+
+                # build a list of distance,value pairs for each segment of transect
+                self.seglist.append((cumdist,val))
+                lasteast = point[0]
+                lastnorth = point[1]
+
+            # delete extra first segment point
+            try:
+                self.seglist.pop(0)
+            except:
+                pass
+
+        #
+        # create datalist of dist/value pairs and y labels for each raster map
+        #    
+        self.ylabel = ''
+        i = 0
+
+        for r in self.raster.iterkeys():
+            self.raster[r]['datalist'] = []
+            datalist = self.CreateDatalist(r, self.coordstr)
+            if len(datalist) > 0:   
+                self.raster[r]['datalist'] = datalist
+
+                # update ylabel to match units if they exist           
+                if self.raster[r]['units'] != '':
+                    self.ylabel += '%s (%d),' % (r['units'], i)
+                i += 1
+
+                # update title
+                self.ptitle += ' %s ,' % r.split('@')[0]
+
+        self.ptitle = self.ptitle.rstrip(',')
+            
+        if self.ylabel == '':
+            self.ylabel = _('Raster values')
+        else:
+            self.ylabel = self.ylabel.rstrip(',')
+
+    def CreateDatalist(self, raster, coords):
+        """!Build a list of distance, value pairs for points along transect using r.profile
+        """
+        datalist = []
+        
+        # keep total number of transect points to 500 or less to avoid 
+        # freezing with large, high resolution maps
+        region = grass.region()
+        curr_res = min(float(region['nsres']),float(region['ewres']))
+        transect_rec = 0
+        if self.transect_length / curr_res > 500:
+            transect_res = self.transect_length / 500
+        else: transect_res = curr_res
+        
+        ret = gcmd.RunCommand("r.profile",
+                              parent = self,
+                              input = raster,
+                              profile = coords,
+                              res = transect_res,
+                              null = "nan",
+                              quiet = True,
+                              read = True)
+        
+        if not ret:
+            return []
+            
+        for line in ret.splitlines():
+            dist, elev = line.strip().split(' ')
+            if dist == None or dist == '' or dist == 'nan' or \
+                elev == None or elev == '' or elev == 'nan':
+                continue
+            dist = float(dist)
+            elev = float(elev)
+            datalist.append((dist,elev))
+
+        return datalist
+
+    def OnCreateProfile(self, event):
+        """!Main routine for creating a profile. Uses r.profile to
+        create a list of distance,cell value pairs. This is passed to
+        plot to create a line graph of the profile. If the profile
+        transect is in multiple segments, these are drawn as
+        points. Profile transect is drawn, using methods in mapdisp.py
+        """
+            
+        if len(self.mapwin.polycoords) == 0 or len(self.rasterList) == 0:
+            dlg = wx.MessageDialog(parent = self,
+                                   message = _('You must draw a transect to profile in the map display window.'),
+                                   caption = _('Nothing to profile'),
+                                   style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+
+        self.mapwin.SetCursor(self.parent.cursors["default"])
+        self.SetCursor(self.parent.cursors["default"])
+        self.SetGraphStyle()
+        self.SetupProfile()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+
+        # reset transect
+        self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
+        self.mapwin.mouse['use'] = 'pointer'
+        self.mapwin.mouse['box'] = 'point'
+
+    def CreatePlotList(self):
+        """!Create a plot data list from transect datalist and
+            transect segment endpoint coordinates.
+        """
+        # graph the distance, value pairs for the transect
+        self.plotlist = []
+
+        # Add segment marker points to plot data list
+        if len(self.seglist) > 0 :
+            self.ppoints = plot.PolyMarker(self.seglist,
+                                           legend = ' ' + self.properties['marker']['legend'],
+                                           colour = wx.Color(self.properties['marker']['color'][0],
+                                                           self.properties['marker']['color'][1],
+                                                           self.properties['marker']['color'][2],
+                                                           255),
+                                           size = self.properties['marker']['size'],
+                                           fillstyle = self.ptfilldict[self.properties['marker']['fill']],
+                                           marker = self.properties['marker']['type'])
+            self.plotlist.append(self.ppoints)
+
+        # Add profile distance/elevation pairs to plot data list for each raster profiled
+        for r in self.rasterList:
+            col = wx.Color(self.raster[r]['pcolor'][0],
+                           self.raster[r]['pcolor'][1],
+                           self.raster[r]['pcolor'][2],
+                           255)
+            self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
+                                                    colour = col,
+                                                    width = self.raster[r]['pwidth'],
+                                                    style = self.linestyledict[self.raster[r]['pstyle']],
+                                                    legend = self.raster[r]['plegend'])
+
+            self.plotlist.append(self.raster[r]['pline'])
+
+        if len(self.plotlist) > 0:        
+            return self.plotlist
+        else:
+            return None
+
+    def Update(self):
+        """!Update profile after changing options
+        """
+        self.SetGraphStyle()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+
+    def SaveProfileToFile(self, event):
+        """!Save r.profile data to a csv file
+        """    
+        wildcard = _("Comma separated value (*.csv)|*.csv")
+        
+        dlg = wx.FileDialog(parent = self,
+                            message = _("Path and prefix (for raster name) to save profile values..."),
+                            defaultDir = os.getcwd(), 
+                            defaultFile = "",  wildcard = wildcard, style = wx.SAVE)
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+            
+            for r in self.rasterList:
+                pfile = path+'_'+str(r['name'])+'.csv'
+                try:
+                    file = open(pfile, "w")
+                except IOError:
+                    wx.MessageBox(parent = self,
+                                  message = _("Unable to open file <%s> for writing.") % pfile,
+                                  caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+                    return False
+                for datapair in self.raster[r]['datalist']:
+                    file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
+                                        
+                file.close()
+
+        dlg.Destroy()
+        
+    def OnStats(self, event):
+        """!Displays regression information in messagebox
+        """
+        message = []
+        title = _('Statistics for Profile(s)')
+
+        for r in self.raster.iterkeys():
+            try:
+                rast = r.split('@')[0] 
+                statstr = 'Profile of %s\n\n' % rast
+
+                iterable = (i[1] for i in self.raster[r]['datalist'])            
+                a = numpy.fromiter(iterable, numpy.float)
+                
+                statstr += 'n: %f\n' % a.size
+                statstr += 'minimum: %f\n' % numpy.amin(a)
+                statstr += 'maximum: %f\n' % numpy.amax(a)
+                statstr += 'range: %f\n' % numpy.ptp(a)
+                statstr += 'mean: %f\n' % numpy.mean(a)
+                statstr += 'standard deviation: %f\n' % numpy.std(a)
+                statstr += 'variance: %f\n' % numpy.var(a)
+                cv = numpy.std(a)/numpy.mean(a)
+                statstr += 'coefficient of variation: %f\n' % cv
+                statstr += 'sum: %f\n' % numpy.sum(a)
+                statstr += 'median: %f\n' % numpy.median(a)
+                statstr += 'distance along transect: %f\n\n' % self.transect_length       
+                message.append(statstr)
+            except:
+                pass
+            
+        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
+                                      title = title)
+
+        if stats.Show() == wx.ID_CLOSE:
+            stats.Destroy()       
+
+    
+class ProfileToolbar(BaseToolbar):
+    """!Toolbar for profiling raster map
+    """ 
+    def __init__(self, parent):
+        BaseToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['plot']
+        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
+                                      self.parent.OnSelectRaster),
+                                     ('transect', icons["transect"],
+                                      self.parent.OnDrawTransect),
+                                     (None, ),
+                                     ('draw', icons["draw"],
+                                      self.parent.OnCreateProfile),
+                                     ('erase', Icons['displayWindow']["erase"],
+                                      self.parent.OnErase),
+                                     ('drag', Icons['displayWindow']['pan'],
+                                      self.parent.OnDrag),
+                                     ('zoom', Icons['displayWindow']['zoomIn'],
+                                      self.parent.OnZoom),
+                                     ('unzoom', Icons['displayWindow']['zoomBack'],
+                                      self.parent.OnRedraw),
+                                     (None, ),
+                                     ('statistics', icons['statistics'],
+                                      self.parent.OnStats),
+                                     ('datasave', icons["save"],
+                                      self.parent.SaveProfileToFile),
+                                     ('image', Icons['displayWindow']["saveFile"],
+                                      self.parent.SaveToFile),
+                                     ('print', Icons['displayWindow']["print"],
+                                      self.parent.PrintMenu),
+                                     (None, ),
+                                     ('settings', icons["options"],
+                                      self.parent.PlotOptionsMenu),
+                                     ('quit', icons["quit"],
+                                      self.parent.OnQuit),
+                                     ))


Property changes on: grass/trunk/gui/wxpython/wxplot/profile.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native

Added: grass/trunk/gui/wxpython/wxplot/scatter.py
===================================================================
--- grass/trunk/gui/wxpython/wxplot/scatter.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/wxplot/scatter.py	2011-11-24 11:46:55 UTC (rev 49347)
@@ -0,0 +1,299 @@
+"""!
+ at package wxplot.scatter
+
+ at brief Scatter plotting using PyPlot
+
+Classes:
+ - ScatterFrame
+ - ScatterToolbar
+
+(C) 2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import sys
+
+import wx
+import wx.lib.plot as plot
+
+import grass.script as grass
+
+from wxplot.base       import BasePlotFrame
+from gui_core.toolbars import BaseToolbar
+
+class ScatterFrame(BasePlotFrame):
+    """!Mainframe for displaying bivariate scatter plot of two raster maps. Uses wx.lib.plot.
+    """
+    def __init__(self, parent, id, pos, style, size, rasterList = []):
+
+        BasePlotFrame.__init__(self, parent)
+        
+        self.toolbar = ScatterToolbar(parent = self)
+        self.SetToolBar(self.toolbar)
+        self.SetLabel(_("GRASS Bivariate Scatterplot Tool"))
+
+        #
+        # Init variables
+        #
+        self.rasterList = rasterList
+        self.plottype = 'scatter'
+        self.ptitle = _('Bivariate Scatterplot')     # title of window
+        self.xlabel = _("Raster cell values")           # default X-axis label
+        self.ylabel = _("Raster cell values")           # default Y-axis label
+        self.maptype = 'raster'                         # default type of scatterplot
+        self.scattertype = 'normal' 
+        self.bins = 255
+        self.colorList = ["blue", "red", "black", "green", "yellow", "magenta", "cyan", \
+                    "aqua", "grey", "orange", "brown", "purple", "violet", \
+                    "indigo"]
+        
+        if len(self.rasterList) > 1: # set raster name(s) from layer manager if a map is selected
+            self.InitRasterOpts(self.rasterList, 'scatter')
+
+        self._initOpts()
+
+    def _initOpts(self):
+        """!Initialize plot options
+        """
+        self.InitPlotOpts('scatter')            
+
+    def OnCreateScatter(self, event):
+        """!Main routine for creating a scatterplot. Uses r.stats to
+        create a list of cell value pairs. This is passed to
+        plot to create a scatterplot.
+        """
+        self.SetCursor(self.parent.cursors["default"])
+        self.SetGraphStyle()
+        self.SetupScatterplot()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+
+    def OnSelectRaster(self, event):
+        """!Select raster map(s) to profile
+        """
+        dlg = dialogs.ScatterRasterDialog(parent = self)
+
+        if dlg.ShowModal() == wx.ID_OK:
+            rlist = dlg.rasterList
+            if rlist < 2: 
+                dlg.Destroy()
+                return                        # need at least 2 rasters for scatterplot
+
+            self.bins = dlg.bins                        # bins for r.stats with float and dcell maps
+            self.scattertype = dlg.scattertype          # scatterplot or bubbleplot
+            self.rasterList = self.CreatePairs(rlist)   # list of raster pairs (tuples)
+            self.raster = self.InitRasterPairs(self.rasterList, 'scatter') # dictionary of raster pairs
+
+            # plot histogram
+            if len(self.rasterList) > 0:
+                self.OnCreateScatter(event = None)
+
+        dlg.Destroy()
+        
+    def CreatePairs(self, rlist):
+        """!Transforms list of rasters into tuples of raster pairs
+        """
+        rasterList = []
+        next = 'first'
+        for r in rlist:
+            if next == 'first':
+                first = r
+                next = 'second'
+            else:
+                second = r
+                t = (first, second)
+                rasterList.append(t)
+                next = 'first'
+                first = second = ''
+                
+        return rasterList
+
+    def SetupScatterplot(self):
+        """!Build data list for ploting each raster
+        """
+
+        #
+        # initialize title string
+        #
+        self.ptitle = _('Bivariate Scatterplot of ')        
+
+        #
+        # create a datalist for plotting for each raster pair
+        #
+        if len(self.rasterList) == 0: return  # at least 1 pair of maps needed to plot        
+        
+        for rpair in self.rasterList:
+            self.raster[rpair]['datalist'] = self.CreateDatalist(rpair)
+            
+            # update title
+            self.ptitle += '%s vs %s, ' % (rpair[0].split('@')[0], rpair[1].split('@')[0])
+
+        self.ptitle = self.ptitle.strip(', ')
+        
+        #
+        # set xlabel & ylabel based on raster maps of first pair to be plotted
+        #
+        units = self.raster[self.rasterList[0]][0]['units']
+        if units != '' and units != '(none)' and units != None:
+            self.xlabel = _('Raster cell values %s') % units
+        else:
+            self.xlabel = _('Raster cell values') 
+
+        units = self.raster[self.rasterList[0]][1]['units']
+        if units != '' and units != '(none)' and units != None:
+            self.ylabel = _('Raster cell values %s') % units
+        else:
+            self.ylabel = _('Raster cell values') 
+
+    def CreateDatalist(self, rpair):
+        """!Build a list of cell value, frequency pairs for histogram
+            frequency can be in cell counts, percents, or area
+        """
+        datalist = []
+        
+        if self.scattertype == 'bubble': 
+            freqflag = 'cn'
+        else:
+            freqflag = 'n'
+                
+        try:
+            ret = gcmd.RunCommand("r.stats",
+                                  parent = self,
+                                  input = '%s,%s' % rpair,
+                                  flags = freqflag,
+                                  nsteps = self.bins,
+                                  fs = ',',
+                                  quiet = True,
+                                  read = True)
+            
+            if not ret:
+                return datalist
+            
+            for line in ret.splitlines():
+                rast1, rast2 = line.strip().split(',')
+                rast1 = rast1.strip()
+                if '-' in rast1: rast1 = rast1.split('-')[0]
+                rast2 = rast2.strip()
+                if '-' in rast2: rast2 = rast2.split('-')[0]
+                
+                rast1 = rast1.encode('ascii', 'ignore')
+                rast2 = rast2.encode('ascii', 'ignore')
+                    
+                datalist.append((rast1,rast2))
+
+            return datalist
+        except gcmd.GException, e:
+            gcmd.GError(parent = self,
+                        message = e.value)
+            return None
+        
+    def CreatePlotList(self):
+        """!Make list of elements to plot
+        """
+        # graph the cell value, frequency pairs for the histogram
+        self.plotlist = []
+
+        for rpair in self.rasterList:
+            if 'datalist' not in self.raster[rpair] or \
+                self.raster[rpair]['datalist'] == None: return
+            
+            if len(self.raster[rpair]['datalist']) > 0:
+                col = wx.Color(self.raster[rpair]['pcolor'][0],
+                               self.raster[rpair]['pcolor'][1],
+                               self.raster[rpair]['pcolor'][2],
+                               255)
+                scatterpoints = plot.PolyMarker(self.raster[rpair]['datalist'],
+                                                legend = ' ' + self.raster[rpair]['plegend'],
+                                                colour = col,size = self.raster[rpair]['psize'],
+                                                fillstyle = self.ptfilldict[self.raster[rpair]['pfill']],
+                                                marker = self.raster[rpair]['ptype'])
+
+                self.plotlist.append(scatterpoints)
+          
+        if len(self.plotlist) > 0:        
+            return self.plotlist
+        else:
+            return None
+
+    def Update(self):
+        """!Update histogram after changing options
+        """
+        self.SetGraphStyle()
+        p = self.CreatePlotList()
+        self.DrawPlot(p)
+    
+    def OnRegression(self, event):
+        """!Displays regression information in messagebox
+        """
+        message = []
+        title = _('Regression Statistics for Scatterplot(s)')
+
+        for rpair in self.rasterList:
+            if isinstance(rpair, tuple) == False: continue
+            rast1, rast2 = rpair
+            rast1 = rast1.split('@')[0] 
+            rast2 = rast2.split('@')[0] 
+            ret = grass.parse_command('r.regression.line', 
+                                      map1 = rast1, 
+                                      map2 = rast2, 
+                                      flags = 'g', quiet = True,
+                                      parse = (grass.parse_key_val, { 'sep' : '=' }))
+            eqtitle = _('Regression equation for %s vs. %s:\n\n')  % (rast1, rast2)
+            eq = _('   %s = %s + %s(%s)\n\n') % (rast2, ret['a'], ret['b'], rast1)
+            num = _('N = %s\n') % ret['N']
+            rval = _('R = %s\n') % ret['R']
+            rsq = _('R-squared = %f\n') % pow(float(ret['R']), 2)
+            ftest = _('F = %s\n') % ret['F']
+            str = eqtitle + eq + num + rval + rsq + ftest
+            message.append(str)
+            
+        stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
+                                      title = title)
+
+        if stats.Show() == wx.ID_CLOSE:
+            stats.Destroy()       
+
+class ScatterplotToolbar(BaseToolbar):
+    """!Toolbar for bivariate scatterplots of raster map pairs
+    """ 
+    def __init__(self, parent):
+        AbstractToolbar.__init__(self, parent)
+        
+        self.InitToolbar(self._toolbarData())
+        
+        # realize the toolbar
+        self.Realize()
+        
+    def _toolbarData(self):
+        """!Toolbar data"""
+        icons = Icons['plot']
+#        icons2 = Icons['modeler']
+        return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
+                                      self.parent.OnSelectRaster),
+                                     (None, ),
+                                     ('draw', icons["draw"],
+                                      self.parent.OnCreateScatter),
+                                     ('erase', Icons['displayWindow']["erase"],
+                                      self.parent.OnErase),
+                                     ('drag', Icons['displayWindow']['pan'],
+                                      self.parent.OnDrag),
+                                     ('zoom', Icons['displayWindow']['zoomIn'],
+                                      self.parent.OnZoom),
+                                     ('unzoom', Icons['displayWindow']['zoomBack'],
+                                      self.parent.OnRedraw),
+                                     (None, ),
+                                     ('statistics', icons['statistics'],
+                                      self.parent.OnRegression),
+                                     ('image', Icons['displayWindow']["saveFile"],
+                                      self.parent.SaveToFile),
+                                     ('print', Icons['displayWindow']["print"],
+                                      self.parent.PrintMenu),
+                                     (None, ),
+                                     ('settings', icons["options"],
+                                      self.parent.PlotOptionsMenu),
+                                     ('quit', icons["quit"],
+                                      self.parent.OnQuit),
+                                     ))


Property changes on: grass/trunk/gui/wxpython/wxplot/scatter.py
___________________________________________________________________
Added: svn:mime-type
   + text/x-python
Added: svn:eol-style
   + native



More information about the grass-commit mailing list