[GRASS-SVN] r49621 - in grass/branches/develbranch_6/gui/wxpython:
. core dbmgr gcp gmodeler gui_core gui_modules lmgr
location_wizard mapdisp modules nviz psmap vdigit wxplot
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Dec 8 07:45:28 EST 2011
Author: martinl
Date: 2011-12-08 04:45:28 -0800 (Thu, 08 Dec 2011)
New Revision: 49621
Added:
grass/branches/develbranch_6/gui/wxpython/core/
grass/branches/develbranch_6/gui/wxpython/core/debug.py
grass/branches/develbranch_6/gui/wxpython/core/gcmd.py
grass/branches/develbranch_6/gui/wxpython/core/globalvar.py
grass/branches/develbranch_6/gui/wxpython/core/menudata.py
grass/branches/develbranch_6/gui/wxpython/core/render.py
grass/branches/develbranch_6/gui/wxpython/core/settings.py
grass/branches/develbranch_6/gui/wxpython/core/units.py
grass/branches/develbranch_6/gui/wxpython/core/utils.py
grass/branches/develbranch_6/gui/wxpython/core/workspace.py
grass/branches/develbranch_6/gui/wxpython/create__init__.py
grass/branches/develbranch_6/gui/wxpython/dbmgr/
grass/branches/develbranch_6/gui/wxpython/dbmgr/dialogs.py
grass/branches/develbranch_6/gui/wxpython/dbmgr/manager.py
grass/branches/develbranch_6/gui/wxpython/dbmgr/sqlbuilder.py
grass/branches/develbranch_6/gui/wxpython/dbmgr/vinfo.py
grass/branches/develbranch_6/gui/wxpython/gcp/
grass/branches/develbranch_6/gui/wxpython/gcp/manager.py
grass/branches/develbranch_6/gui/wxpython/gcp/mapdisplay.py
grass/branches/develbranch_6/gui/wxpython/gcp/toolbars.py
grass/branches/develbranch_6/gui/wxpython/gmodeler/
grass/branches/develbranch_6/gui/wxpython/gmodeler/dialogs.py
grass/branches/develbranch_6/gui/wxpython/gmodeler/frame.py
grass/branches/develbranch_6/gui/wxpython/gmodeler/menudata.py
grass/branches/develbranch_6/gui/wxpython/gmodeler/model.py
grass/branches/develbranch_6/gui/wxpython/gmodeler/preferences.py
grass/branches/develbranch_6/gui/wxpython/gui_core/
grass/branches/develbranch_6/gui/wxpython/gui_core/dialogs.py
grass/branches/develbranch_6/gui/wxpython/gui_core/forms.py
grass/branches/develbranch_6/gui/wxpython/gui_core/ghelp.py
grass/branches/develbranch_6/gui/wxpython/gui_core/goutput.py
grass/branches/develbranch_6/gui/wxpython/gui_core/gselect.py
grass/branches/develbranch_6/gui/wxpython/gui_core/mapdisp.py
grass/branches/develbranch_6/gui/wxpython/gui_core/mapwindow.py
grass/branches/develbranch_6/gui/wxpython/gui_core/menu.py
grass/branches/develbranch_6/gui/wxpython/gui_core/preferences.py
grass/branches/develbranch_6/gui/wxpython/gui_core/prompt.py
grass/branches/develbranch_6/gui/wxpython/gui_core/toolbars.py
grass/branches/develbranch_6/gui/wxpython/gui_core/widgets.py
grass/branches/develbranch_6/gui/wxpython/lmgr/
grass/branches/develbranch_6/gui/wxpython/lmgr/layertree.py
grass/branches/develbranch_6/gui/wxpython/lmgr/menudata.py
grass/branches/develbranch_6/gui/wxpython/lmgr/pyshell.py
grass/branches/develbranch_6/gui/wxpython/lmgr/toolbars.py
grass/branches/develbranch_6/gui/wxpython/location_wizard/
grass/branches/develbranch_6/gui/wxpython/location_wizard/base.py
grass/branches/develbranch_6/gui/wxpython/location_wizard/dialogs.py
grass/branches/develbranch_6/gui/wxpython/location_wizard/wizard.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/
grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/gprint.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/main.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/mapwindow.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/statusbar.py
grass/branches/develbranch_6/gui/wxpython/mapdisp/toolbars.py
grass/branches/develbranch_6/gui/wxpython/modules/
grass/branches/develbranch_6/gui/wxpython/modules/colorrules.py
grass/branches/develbranch_6/gui/wxpython/modules/extensions.py
grass/branches/develbranch_6/gui/wxpython/modules/histogram.py
grass/branches/develbranch_6/gui/wxpython/modules/mcalc_builder.py
grass/branches/develbranch_6/gui/wxpython/modules/ogc_services.py
grass/branches/develbranch_6/gui/wxpython/modules/vclean.py
grass/branches/develbranch_6/gui/wxpython/nviz/
grass/branches/develbranch_6/gui/wxpython/nviz/animation.py
grass/branches/develbranch_6/gui/wxpython/nviz/main.py
grass/branches/develbranch_6/gui/wxpython/nviz/mapwindow.py
grass/branches/develbranch_6/gui/wxpython/nviz/preferences.py
grass/branches/develbranch_6/gui/wxpython/nviz/tools.py
grass/branches/develbranch_6/gui/wxpython/nviz/workspace.py
grass/branches/develbranch_6/gui/wxpython/nviz/wxnviz.py
grass/branches/develbranch_6/gui/wxpython/psmap/
grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py
grass/branches/develbranch_6/gui/wxpython/psmap/frame.py
grass/branches/develbranch_6/gui/wxpython/psmap/menudata.py
grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py
grass/branches/develbranch_6/gui/wxpython/states.txt
grass/branches/develbranch_6/gui/wxpython/vdigit/
grass/branches/develbranch_6/gui/wxpython/vdigit/dialogs.py
grass/branches/develbranch_6/gui/wxpython/vdigit/main.py
grass/branches/develbranch_6/gui/wxpython/vdigit/mapwindow.py
grass/branches/develbranch_6/gui/wxpython/vdigit/preferences.py
grass/branches/develbranch_6/gui/wxpython/vdigit/toolbars.py
grass/branches/develbranch_6/gui/wxpython/vdigit/wxdigit.py
grass/branches/develbranch_6/gui/wxpython/vdigit/wxdisplay.py
grass/branches/develbranch_6/gui/wxpython/wxplot/
grass/branches/develbranch_6/gui/wxpython/wxplot/base.py
grass/branches/develbranch_6/gui/wxpython/wxplot/dialogs.py
grass/branches/develbranch_6/gui/wxpython/wxplot/profile.py
Removed:
grass/branches/develbranch_6/gui/wxpython/gui_modules/colorrules.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_base.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_dialogs.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/debug.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/disp_print.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gdialogs.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/globalvar.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gpyshell.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gselect.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/histogram.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/layertree.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/location_wizard.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_statusbar.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_vdigit.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/mcalc_builder.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/menu.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/menudata.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_animation.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_mapdisp.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_preferences.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_tools.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/ogc_services.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/profile.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap_dialogs.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/render.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/sqlbuilder.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/states.txt
grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/units.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/utils.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/vclean.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/vdigit.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/workspace.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/wxnviz.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdigit.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdriver.py
Modified:
grass/branches/develbranch_6/gui/wxpython/gis_set.py
grass/branches/develbranch_6/gui/wxpython/wxgui.py
grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox
Log:
wxGUI major code reorganization (part 1)
- only layout sync'ed with trunk (not code, except of headers and profile.py)
(based on r49347 from trunk)
Copied: grass/branches/develbranch_6/gui/wxpython/core/debug.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/debug.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/debug.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/debug.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,67 @@
+"""!
+ at package core.debug
+
+ at brief wxGUI debugging
+
+Classes:
+ - debug::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()
Copied: grass/branches/develbranch_6/gui/wxpython/core/gcmd.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/gcmd.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/gcmd.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,673 @@
+"""!
+ at package core.gcmd
+
+ at brief wxGUI command interface
+
+Classes:
+ - gcmd::GError
+ - gcmd::GWarning
+ - gcmd::GMessage
+ - gcmd::GException
+ - gcmd::Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
+ - gcmd::Command
+ - gcmd::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(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
+
+ @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 CmdError 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
+ """
+ def __init__ (self, cmd, stdin = None,
+ verbose = None, wait = True, rerr = False,
+ stdout = None, stderr = 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()
+
+ # TODO: replace ugly hack bellow
+ args = self.cmd
+ if sys.platform == 'win32' and os.path.splitext(self.cmd[0])[1] == '.py':
+ os.chdir(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'scripts'))
+ args = [sys.executable, self.cmd[0]] + self.cmd[1:]
+
+ try:
+ self.module = Popen(args,
+ stdin = subprocess.PIPE,
+ stdout = subprocess.PIPE,
+ stderr = subprocess.PIPE,
+ shell = sys.platform == "win32")
+ except OSError, e:
+ self.error = str(e)
+ print >> sys.stderr, 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, 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 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
+
+ ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
+
+ Debug.msg(2, "gcmd.RunCommand(): command started")
+
+ 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" % ret)
+
+ 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 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/branches/develbranch_6/gui/wxpython/core/globalvar.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/globalvar.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/globalvar.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/globalvar.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,180 @@
+"""!
+ 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, "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 = (700, 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 = '.bat'
+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 and sys.platform != "win32":
+ 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')
+ os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'wxpython', 'scripts')
+ for script in os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts')):
+ patt = "_wrapper" # ignore wrappers
+ if script[-len(patt):] != patt:
+ cmd.append(script)
+
+ if addons and os.getenv('GRASS_ADDON_PATH'):
+ path = os.getenv('GRASS_ADDON_PATH')
+ for ipath in path.split(os.pathsep):
+ if not os.path.exists(ipath):
+ continue
+ for executable in os.listdir(ipath):
+ ext = os.path.splitext(executable)[1]
+ if not EXT_BIN or \
+ ext in (EXT_BIN, EXT_SCT):
+ cmd.append(executable)
+
+ 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/branches/develbranch_6/gui/wxpython/core/menudata.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/menudata.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/menudata.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/menudata.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,233 @@
+"""!
+ at package core.menudata
+
+ at brief Complex list for menu entries for wxGUI
+
+Classes:
+ - menudata::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
+
+import wx
+
+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 = 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')
+
+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", "wxpython"))
+
+ if menu == 'manager':
+ from lmgr.menudata import ManagerData
+ data = ManagerData()
+ else:
+ from gmodeler.menudata 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/branches/develbranch_6/gui/wxpython/core/render.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/render.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/render.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/render.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1316 @@
+"""!
+ at package core.render
+
+ at brief Rendering map layers and overlays into map composition image.
+
+Classes:
+ - render::Layer
+ - render::MapLayer
+ - render::Overlay
+ - render::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 g.pnmcomp for creating image composition or
+# wxPython functionality
+#
+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):
+ """!
+ @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
+ self.gtemp = tempfile.mkstemp()[1]
+ self.maskfile = self.gtemp + ".pgm"
+ if self.type == 'overlay':
+ self.mapfile = self.gtemp + ".png"
+ else:
+ self.mapfile = self.gtemp + ".ppm"
+
+ 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
+ """
+ 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',
+ '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 UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
+# os.environ["GRASS_CAIROFILE"] = self.mapfile
+# if 'cairo' not in gcmd.RunCommand('d.mon',
+# flags='p',
+# read = True):
+# gcmd.RunCommand('d.mon',
+# start = 'cairo')
+ if not self.mapfile:
+ self.gtemp = tempfile.mkstemp()[1]
+ self.maskfile = self.gtemp + ".pgm"
+ if self.type == 'overlay':
+ self.mapfile = self.gtemp + ".png"
+ else:
+ self.mapfile = self.gtemp + ".ppm"
+
+ if self.mapfile:
+ os.environ["GRASS_CAIROFILE"] = self.mapfile
+ else:
+ if not self.mapfile:
+ self.gtemp = tempfile.mkstemp()[1]
+ self.maskfile = self.gtemp + ".pgm"
+ if self.type == 'overlay':
+ self.mapfile = self.gtemp + ".png"
+ else:
+ self.mapfile = self.gtemp + ".ppm"
+
+ 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
+ try:
+ os.remove(self.mapfile)
+ os.remove(self.maskfile)
+ os.remove(self.gtemp)
+ except (OSError, TypeError):
+ pass
+ self.mapfile = None
+ self.maskfile = None
+
+ # stop monitor
+ if UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
+# gcmd.RunCommand('d.mon',
+# stop = 'cairo')
+ del os.environ["GRASS_CAIROFILE"]
+ elif "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',
+ '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):
+ """!Map composition (stack of map layers and overlays)
+ """
+ def __init__(self, gisrc = None):
+ # 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
+ # environment variables, like MAPSET, LOCATION_NAME, etc.
+ self.env = dict()
+ # path to external gisrc
+ self.gisrc = gisrc
+
+ # generated file for g.pnmcomp output for rendering the map
+ self.mapfile = tempfile.mkstemp(suffix = '.ppm')[1]
+
+ # setting some initial env. variables
+ self._initGisEnv() # g.gisenv
+ self.GetWindow()
+ # GRASS environment variable (for rendering)
+ os.environ["GRASS_TRANSPARENT"] = "TRUE"
+ os.environ["GRASS_BACKGROUNDCOLOR"] = "ffffff"
+
+ # 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 ChangeMapSize(self, (width, height)):
+ """!Change size of rendered map.
+
+ @param width,height map size
+
+ @return True on success
+ @return False on failure
+ """
+ try:
+ self.width = int(width)
+ self.height = int(height)
+ Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
+ (self.width, self.height))
+ return True
+ except:
+ self.width = 640
+ self.height = 480
+ return False
+
+ 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, mapWindow, maps, masks, opacities):
+ # render map layers
+ ilayer = 1
+ for layer in self.layers + self.overlays:
+ # skip dead or disabled map layers
+ if layer == None or layer.active == False:
+ continue
+
+ # render if there is no mapfile
+ if force or \
+ layer.force_render or \
+ layer.mapfile == None or \
+ (not os.path.isfile(layer.mapfile) or not os.path.getsize(layer.mapfile)):
+ 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
+
+ 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
+ """
+ maps = []
+ masks = []
+ opacities = []
+
+ 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)
+ if UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
+ os.environ["GRASS_AUTO_WRITE"] = "TRUE"
+ if "GRASS_RENDER_IMMEDIATE" in os.environ:
+ del os.environ["GRASS_RENDER_IMMEDIATE"]
+ os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
+ else:
+ os.environ["GRASS_PNG_AUTO_WRITE"] = "TRUE"
+ os.environ["GRASS_PNG_READ"] = "FALSE"
+ os.environ["GRASS_COMPRESSION"] = "0"
+ os.environ["GRASS_TRUECOLOR"] = "TRUE"
+ os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
+
+ self._renderLayers(force, mapWindow, maps, masks, opacities)
+
+ # ugly hack for MSYS
+ if not subprocess.mswindows:
+ 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('\\', '/')
+
+ # compose command
+ bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
+ subkey = 'color')))
+
+ # render overlays
+ if tmp_region:
+ os.environ["GRASS_REGION"] = tmp_region
+ else:
+ del os.environ["GRASS_REGION"]
+
+ if maps:
+ # run g.pngcomp to get composite image
+ ret, msg = RunCommand('g.pnmcomp',
+ getErrorMsg = True,
+ input = '%s' % ",".join(maps),
+ mask = '%s' % ",".join(masks),
+ opacity = '%s' % ",".join(opacities),
+ background = 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 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 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):
+ """!Clean layer stack - go trough all layers and remove them
+ from layer list.
+
+ Removes also l_mapfile and l_maskfile
+
+ @return False on failure
+ @return True on success
+ """
+ try:
+ dir = os.path.dirname(self.mapfile)
+ base = os.path.basename(self.mapfile).split('.')[0]
+ removepath = os.path.join(dir,base)+r'*'
+ for f in glob.glob(removepath):
+ os.remove(f)
+ for layer in self.layers:
+ if layer.mapfile:
+ dir = os.path.dirname(layer.mapfile)
+ base = os.path.basename(layer.mapfile).split('.')[0]
+ removepath = os.path.join(dir,base)+r'*'
+ for f in glob.glob(removepath):
+ os.remove(f)
+ self.layers.remove(layer)
+
+ for overlay in self.overlays:
+ if overlay.mapfile:
+ dir = os.path.dirname(overlay.mapfile)
+ base = os.path.basename(overlay.mapfile).split('.')[0]
+ removepath = os.path.join(dir,base)+r'*'
+ for f in glob.glob(removepath):
+ os.remove(f)
+ self.overlays.remove(overlay)
+ except:
+ return False
+
+ return True
+
+ 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/branches/develbranch_6/gui/wxpython/core/settings.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/settings.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/settings.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,986 @@
+"""!
+ at package core.settings
+
+ at brief Default GUI settings
+
+List of classes:
+ - settings::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' : 'grass2'
+ }, # grass2, grass, silk
+ },
+ #
+ # display
+ #
+ 'display': {
+ 'font' : {
+ 'type' : '',
+ 'encoding': 'ISO-8859-1',
+ },
+ 'driver': {
+ 'type': 'default'
+ },
+ '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
+ 'rasterOverlay' : {
+ 'enabled' : True
+ },
+ '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,
+ },
+ },
+ 'profile': {
+ 'raster0' : {
+ 'pcolor' : (0, 0, 255, 255), # profile line color
+ 'pwidth' : 1, # profile line width
+ 'pstyle' : 'solid', # profile line pen style
+ },
+ 'raster1' : {
+ 'pcolor' : (255, 0, 0, 255),
+ 'pwidth' : 1,
+ 'pstyle' : 'solid',
+ },
+ 'raster2' : {
+ 'pcolor' : (0, 255, 0, 255),
+ 'pwidth' : 1,
+ 'pstyle' : 'solid',
+ },
+ '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
+ },
+ },
+ '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,
+ },
+ 'points' : {
+ 'show' : False,
+ 'size' : 100,
+ 'width' : 2,
+ 'marker' : 2,
+ 'color' : (0, 0, 255, 255), # blue
+ 'height' : 0,
+ }
+ },
+ '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',
+ 'grass2',
+ 'silk')
+ 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'] = ['default']
+ 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):
+ # try alternative path
+ filename = os.path.join(os.path.expanduser("~"), '.grasswx6')
+ 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])
+
+globalSettings = Settings()
Copied: grass/branches/develbranch_6/gui/wxpython/core/units.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/units.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/units.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/units.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,117 @@
+"""!
+ 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:
+ - units::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/branches/develbranch_6/gui/wxpython/core/utils.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/utils.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/utils.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/utils.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,765 @@
+"""!
+ 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
+ """
+ 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'
+ elif 'labels=' in dcmd[0]:
+ mapname = dcmd[idx].split('=')[1] + ' labels'
+ 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',
+ '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:
+ dcmd[i] = p + '=' + v
+ else:
+ dcmd[i] = v
+ if mapset:
+ dcmd[i] += '@' + mapset
+
+ maps = list()
+ for i, p, v in params:
+ if not p:
+ maps.append(v)
+ else:
+ 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(vector, parent = None):
+ """!Get list of vector layers
+
+ @param vector name of vector map
+ @param parent parent window (to show dialog) or None
+ """
+ layers = []
+ 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
+
+ Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret)
+
+ for line in out.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)
+ 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)
+ """
+ if not projIn:
+ projIn = RunCommand('g.proj',
+ flags = 'jf',
+ read = True)
+ coors = RunCommand('m.proj',
+ flags = flags,
+ proj_in = projIn,
+ proj_out = projOut,
+ stdin = '%f|%f' % (coord[0], coord[1]),
+ read = True)
+ if coors:
+ coors = coors.split('\t')
+ e = coors[0]
+ n = coors[1].split(' ')[0].strip()
+ 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 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)
+
+def _getOGRFormats():
+ """!Get dictionary of avaialble OGR drivers"""
+ ret = grass.read_command('v.in.ogr',
+ quiet = True,
+ flags = 'f')
+
+ return _parseFormats(ret)
+
+def _parseFormats(output):
+ """!Parse r.in.gdal/v.in.ogr -f output"""
+ formats = { 'file' : list(),
+ 'database' : list(),
+ 'protocol' : list()
+ }
+
+ if not output:
+ return formats
+
+ for line in output.splitlines():
+ format = line.strip().rsplit(':', -1)[1].strip()
+ if format in ('Memory', 'Virtual Raster', 'In Memory Raster'):
+ continue
+ if format in ('PostgreSQL', 'SQLite',
+ 'ODBC', 'ESRI Personal GeoDatabase',
+ 'Rasterlite',
+ 'PostGIS WKT Raster driver'):
+ formats['database'].append(format)
+ elif format in ('GeoJSON',
+ 'OGC Web Coverage Service',
+ 'OGC Web Map Service',
+ 'HTTP Fetching Wrapper'):
+ formats['protocol'].append(format)
+ else:
+ formats['file'].append(format)
+
+ for items in formats.itervalues():
+ items.sort()
+
+ return formats
+
+formats = None
+
+def GetFormats():
+ """!Get GDAL/OGR formats"""
+ global formats
+ if not formats:
+ formats = {
+ 'gdal' : _getGDALFormats(),
+ 'ogr' : _getOGRFormats()
+ }
+
+ return formats
+
+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/init.sh and init.bat
+ 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/branches/develbranch_6/gui/wxpython/core/workspace.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/workspace.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/core/workspace.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/core/workspace.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1260 @@
+"""!
+ at package core.workspace
+
+ at brief Open/save workspace definition file
+
+Classes:
+ - workspace::ProcessWorkspaceFile
+ - workspace::WriteWorkspaceFile
+ - workspace::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
+from nviz.workspace import NvizSettings
+
+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 = NvizSettings()
+
+ def __filterValue(self, value):
+ """!Filter value
+
+ @param value
+ """
+ value = value.replace('<', '<')
+ value = value.replace('>', '>')
+
+ 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)
+ lname = item.get('name', None)
+ if lname and '\\n' in lname:
+ lname = lname.replace('\\n', os.linesep)
+
+ self.layers.append( {
+ "type" : item.get('type', None),
+ "name" : lname,
+ "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'])
+
+ # 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'])
+
+ 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', float)
+ 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('<', '<')
+ value = value.replace('>', '>')
+
+ 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).replace(os.linesep, '\\n')
+ 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)))
+ 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>%.2f</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>%.2f</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/branches/develbranch_6/gui/wxpython/create__init__.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/create__init__.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/create__init__.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/create__init__.py
___________________________________________________________________
Added: svn:executable
+ *
Copied: grass/branches/develbranch_6/gui/wxpython/dbmgr/dialogs.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_dialogs.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/dbmgr/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/dbmgr/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,665 @@
+"""!
+ at package dbmgr.dialogs
+
+ at brief DBM-related dialogs
+
+List of classes:
+ - dialogs::DisplayAttributesDialog
+ - dialogs::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 dbmgr.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 __SelectAttributes(self, layer):
+ """!Select attributes"""
+ pass
+
+ 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.notebook.GetPageCount())
+
+ 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 cat=%s" % 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"""
+ 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)
+
+ RunCommand('db.execute',
+ parent = self,
+ quiet = True,
+ stdin = sql)
+
+ 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/branches/develbranch_6/gui/wxpython/dbmgr/manager.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/dbmgr/manager.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/dbmgr/manager.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,3093 @@
+"""!
+ at package dbmgr.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:
+ - manager::Log
+ - manager::VirtualAttributeList
+ - manager::AttributeManager
+ - manager::TableListCtrl
+ - manager::LayerListCtrl
+ - manager::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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+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 dbmgr.sqlbuilder import SQLFrame
+from core.gcmd import RunCommand, GException, GError
+from core.utils import ListOfCatsToRange
+from gui_core.dialogs import CreateNewVector
+from dbmgr.vinfo import VectorDBInfo, unicodeValue, createDbInfoDesc
+from core.debug import Debug
+from dbmgr.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
+ 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
+
+ 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)
+ else:
+ wx.CallAfter(self.notebook.SetSelection, 0) # 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 = 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.renamecol',
+ { '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.dropcol',
+ { '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.dropcol',
+ { '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.addcol command to the list
+ if ctype == 'varchar':
+ ctype += ' (%d)' % length
+ self.listOfCommands.append(('v.db.addcol',
+ { '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.addcol)
+ 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,
+ 'list' : 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,
+ 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/branches/develbranch_6/gui/wxpython/dbmgr/sqlbuilder.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/sqlbuilder.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/dbmgr/sqlbuilder.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/dbmgr/sqlbuilder.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,461 @@
+"""!
+ at package dbmgr.sqlbuilder
+
+ at brief GRASS SQL Builder
+
+Classes:
+ - sqlbuilder::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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+from core import globalvar
+import wx
+
+from core.gcmd import RunCommand, GError
+from dbmgr.vinfo import createDbInfoDesc, VectorDBInfo
+
+import grass.script as grass
+
+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 = 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/branches/develbranch_6/gui/wxpython/dbmgr/vinfo.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_base.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/dbmgr/vinfo.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/dbmgr/vinfo.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,164 @@
+"""
+ at package dbmgr.vinfo
+
+ at brief Support classes for Database Manager
+
+List of classes:
+ - vinfo::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 as VectorDBInfoBase
+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(gselect.VectorDBInfoBase):
+ """!Class providing information about attribute tables
+ linked to the vector map"""
+ def __init__(self, map):
+ VectorDBInfoBase.__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/branches/develbranch_6/gui/wxpython/gcp/manager.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gcp/manager.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gcp/manager.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2779 @@
+"""!
+ at package gcp.manager
+
+ at brief Georectification module for GRASS GIS. Includes ground control
+point management and interactive point and click GCP creation
+
+Classes:
+ - manager::GCPWizard
+ - manager::LocationPage
+ - manager::GroupPage
+ - manager::DispMapPage
+ - manager::GCP
+ - manager::GCPList
+ - manager::VectGroup
+ - manager::EditGCP
+ - manager::GrSettingsDialog
+
+(C) 2006-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.dialogs import GroupDialog
+from core.gcmd import RunCommand, GMessage, GError, GWarning
+from core.settings import UserSettings
+from gcp.mapdisplay import MapFrame
+
+from location_wizard.wizard import 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 g.transform to calculate forward and backward error for each used GCP
+ in POINTS file and insert error values into GCP list.
+ Calculates total forward and backward RMS error for all used points
+ """
+ # save GCPs to points file to make sure that all checked GCPs are used
+ self.SaveGCPs(None)
+ #self.SetStatusText('')
+
+ if self.CheckGCPcount(msg=True) == False:
+ return
+
+ # get list of forward and reverse rms error values for each point
+ self.grwiz.SwitchEnv('source')
+
+ ret = RunCommand('g.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 g.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('g.transform',
+ parent = self,
+ read = True,
+ group = self.xygroup,
+ order = 1,
+ format = 'dst',
+ coords = coord_file)
+
+ elif map == 'target':
+ ret = RunCommand('g.transform',
+ parent = self,
+ read = True,
+ group = self.xygroup,
+ order = 1,
+ flags = 'r',
+ format = 'src',
+ coords = coord_file)
+
+ os.unlink(coord_file)
+
+ self.grwiz.SwitchEnv('target')
+
+ if ret:
+ errlist = ret.splitlines()
+ else:
+ GError(parent = self,
+ message=_('Could not calculate new extends.\n'
+ 'Possible error with g.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"]
+
+ # 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/branches/develbranch_6/gui/wxpython/gcp/mapdisplay.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gcp/mapdisplay.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gcp/mapdisplay.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,629 @@
+"""!
+ at package gcp.mapdisplay
+
+ at brief Display to manage ground control points with two toolbars, one
+for various display management functions, one for manipulating GCPs.
+
+Classes:
+- mapdisplay::MapFrame
+
+(C) 2006-2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import math
+import platform
+
+from core import globalvar
+import wx
+import wx.aui
+
+from 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.mapwindow 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/branches/develbranch_6/gui/wxpython/gcp/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gcp/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gcp/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,129 @@
+"""!
+ at package gcp.toolbars
+
+ at brief Georectification module - toolbars
+
+Classes:
+ - toolbars::GCPManToolbar
+ - toolbars::GCPDisplayToolbar
+
+(C) 2007-2011 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Markus Metz
+"""
+
+import os
+import sys
+
+import wx
+
+from core import globalvar
+from 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))
+ )
Modified: grass/branches/develbranch_6/gui/wxpython/gis_set.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gis_set.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gis_set.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,5 +1,5 @@
"""!
- at package gis_set.py
+ at package gis_set
GRASS start-up screen.
@@ -7,9 +7,9 @@
Location/mapset management (selection, creation, etc.).
Classes:
- - GRASSStartup
- - GListBox
- - StartUp
+ - gis_set::GRASSStartup
+ - gis_set::GListBox
+ - gis_set::StartUp
(C) 2006-2011 by the GRASS Development Team
@@ -22,7 +22,6 @@
import os
import sys
-import glob
import shutil
import copy
import platform
@@ -32,17 +31,16 @@
import gettext
gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-from gui_modules import globalvar
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+from core import globalvar
import wx
-import wx.html
-import wx.lib.rcsizer as rcs
-import wx.lib.filebrowsebutton as filebrowse
import wx.lib.mixins.listctrl as listmix
import wx.lib.scrolledpanel as scrolled
-from gui_modules import goutput
-from gui_modules.ghelp import HelpFrame
-from gui_modules.gcmd import GMessage, GError
+from gui_core.ghelp import HelpFrame
+from core.gcmd import GMessage, GError, DecodeString, RunCommand
+from core.utils import GetListOfLocations, GetListOfMapsets
sys.stderr = codecs.getwriter('utf8')(sys.stderr)
@@ -371,7 +369,7 @@
rc = open(gisrc, "r")
for line in rc.readlines():
key, val = line.split(":", 1)
- grassrc[key.strip()] = utils.DecodeString(val.strip())
+ grassrc[key.strip()] = DecodeString(val.strip())
finally:
rc.close()
@@ -546,7 +544,7 @@
def UpdateLocations(self, dbase):
"""!Update list of locations"""
try:
- self.listOfLocations = utils.GetListOfLocations(dbase)
+ self.listOfLocations = GetListOfLocations(dbase)
except UnicodeEncodeError:
wx.MessageBox(parent = self, caption = _("Error"),
message = _("Unable to set GRASS database. "
@@ -568,29 +566,29 @@
self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
self.listOfMapsetsSelectable = list()
- self.listOfMapsets = utils.GetListOfMapsets(self.gisdbase, location)
+ self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)
self.lbmapsets.Clear()
# disable mapset with denied permission
locationName = os.path.basename(location)
- ret = gcmd.RunCommand('g.mapset',
- read = True,
- flags = 'l',
- location = locationName,
- gisdbase = self.gisdbase)
+ ret = RunCommand('g.mapset',
+ read = True,
+ flags = 'l',
+ location = locationName,
+ gisdbase = self.gisdbase)
if ret:
for line in ret.splitlines():
self.listOfMapsetsSelectable += line.split(' ')
else:
- gcmd.RunCommand("g.gisenv",
- set = "GISDBASE=%s" % self.gisdbase)
- gcmd.RunCommand("g.gisenv",
- set = "LOCATION_NAME=%s" % locationName)
- gcmd.RunCommand("g.gisenv",
- set = "MAPSET=PERMANENT")
+ RunCommand("g.gisenv",
+ set = "GISDBASE=%s" % self.gisdbase)
+ RunCommand("g.gisenv",
+ set = "LOCATION_NAME=%s" % locationName)
+ RunCommand("g.gisenv",
+ set = "MAPSET=PERMANENT")
# first run only
self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
@@ -761,12 +759,12 @@
else:
return
- gcmd.RunCommand("g.gisenv",
- set = "GISDBASE=%s" % dbase)
- gcmd.RunCommand("g.gisenv",
- set = "LOCATION_NAME=%s" % location)
- gcmd.RunCommand("g.gisenv",
- set = "MAPSET=%s" % mapset)
+ RunCommand("g.gisenv",
+ set = "GISDBASE=%s" % dbase)
+ RunCommand("g.gisenv",
+ set = "LOCATION_NAME=%s" % location)
+ RunCommand("g.gisenv",
+ set = "MAPSET=%s" % mapset)
self.Destroy()
sys.exit(0)
@@ -867,15 +865,11 @@
return 1
if __name__ == "__main__":
-
if os.getenv("GISBASE") is None:
- print >> sys.stderr, "Failed to start GUI, GRASS GIS is not running."
- else:
- import gettext
- gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-
- import gui_modules.gcmd as gcmd
- import gui_modules.utils as utils
-
- GRASSStartUp = StartUp(0)
- GRASSStartUp.MainLoop()
+ sys.exit("Failed to start GUI, GRASS GIS is not running.")
+
+ import gettext
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+
+ GRASSStartUp = StartUp(0)
+ GRASSStartUp.MainLoop()
Added: grass/branches/develbranch_6/gui/wxpython/gmodeler/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gmodeler/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gmodeler/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,633 @@
+"""!
+ at package gmodeler.dialogs
+
+ at brief wxGUI Graphical Modeler - dialogs
+
+Classes:
+ - dialogs::ModelDataDialog
+ - dialogs::ModelSearchDialog
+ - dialogs::ModelRelationDialog
+ - dialogs::ModelParamDialog
+ - dialogs::ModelItemDialog
+ - dialogs::ModelLoopDialog
+ - dialogs::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 core import utils
+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 gui_core.prompt import GPromptSTC
+from gui_core.forms import CmdPanel
+
+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 = 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 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 = 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() }
Copied: grass/branches/develbranch_6/gui/wxpython/gmodeler/frame.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gmodeler/frame.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gmodeler/frame.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1935 @@
+"""!
+ at package gmodeler.frame
+
+ at brief wxGUI Graphical Modeler for creating, editing, and managing models
+
+Classes:
+ - frame::ModelToolbar
+ - frame::ModelFrame
+ - frame::ModelCanvas
+ - frame::ModelEvtHandler
+ - frame::ModelListCtrl
+ - frame::VariablePanel
+ - frame::ValiableListCtrl
+ - frame::ItemPanel
+ - frame::ItemListCtrl
+ - frame::ItemCheckListCtrl
+
+(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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+from core import globalvar
+import wx
+from wx.lib import ogl
+import wx.lib.flatnotebook as FN
+import wx.lib.mixins.listctrl as listmix
+
+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 gui_core.menu import Menu
+from gmodeler.menudata import ModelerData
+from icons.icon import Icons
+from gui_core.forms import GUI
+from gmodeler.preferences import PreferencesDialog
+
+from gmodeler.model import *
+from gmodeler.dialogs import *
+
+from grass.script import core as grass
+
+class ModelToolbar(BaseToolbar):
+ """!Graphical modeler toolbar (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 (experimental prototype)"), **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 = toolbars.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 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 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 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
+
+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/branches/develbranch_6/gui/wxpython/gmodeler/menudata.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gmodeler/menudata.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gmodeler/menudata.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,28 @@
+"""!
+ at package gmodeler.menudata
+
+ at brief wxGUI Graphical Modeler - menu data
+
+Classes:
+ - menudata::ModelerData
+
+(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
+
+from core import globalvar
+from core.menudata import MenuData
+
+class ModelerData(MenuData):
+ def __init__(self, filename = None):
+ if not filename:
+ gisbase = os.getenv('GISBASE')
+ filename = os.path.join(globalvar.ETCWXDIR, 'xml', 'menudata_modeler.xml')
+
+ MenuData.__init__(self, filename)
Added: grass/branches/develbranch_6/gui/wxpython/gmodeler/model.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gmodeler/model.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gmodeler/model.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2138 @@
+"""!
+ at package gmodeler.model
+
+ at brief wxGUI Graphical Modeler (base classes & read/write)
+
+Classes:
+ - model::Model
+ - model::ModelObject
+ - model::ModelAction
+ - model::ModelData
+ - model::ModelRelation
+ - model::ModelItem
+ - model::ModelLoop
+ - model::ModelCondition
+ - model::ProcessModelFile
+ - model::WriteModelFile
+ - model::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 getpass
+import copy
+import re
+import mimetypes
+import time
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree # Python <= 2.4
+
+import wx
+from wx.lib import ogl
+
+from core.globalvar import ETCWXDIR
+from core import utils
+from core.gcmd import GMessage, GException, GError, RunCommand, EncodeString, GWarning
+from gmodeler.dialogs import ModelParamDialog
+from core.settings import UserSettings
+from gui_core.forms import GUI
+
+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 = 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_file':
+ 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()
+ dlg.Destroy()
+ 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()
+ dlg.Destroy()
+ 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'] = ''
+
+ 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 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 and cmd[0] in ('r.mapcalc', 'v.type'):
+ cmd[0] += '_wrapper'
+
+ 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 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 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 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 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('<', '<')
+ value = value.replace('>', '>')
+
+ 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('<', '<')
+ value = value.replace('>', '>')
+
+ 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 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
Added: grass/branches/develbranch_6/gui/wxpython/gmodeler/preferences.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gmodeler/preferences.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gmodeler/preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,528 @@
+"""!
+ at package gmodeler.preferences
+
+ at brief wxGUI Graphical Modeler - preferences
+
+Classes:
+ - preferences::PreferencesDialog
+ - preferences::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 = 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'])
Copied: grass/branches/develbranch_6/gui/wxpython/gui_core/dialogs.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gdialogs.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2166 @@
+"""!
+ at package gui_core.dialogs
+
+ at brief Various dialogs used in wxGUI.
+
+List of classes:
+ - dialogs::ElementDialog
+ - dialogs::LocationDialog
+ - dialogs::MapsetDialog
+ - dialogs::NewVectorDialog
+ - dialogs::SavedRegion
+ - dialogs::DecorationDialog
+ - dialogs::TextLayerDialog
+ - dialogs::GroupDialog
+ - dialogs::MapLayersDialog
+ - dialogs::ImportDialog
+ - dialogs::GdalImportDialog
+ - dialogs::DxfImportDialog
+ - dialogs::LayersList (used by MultiImport)
+ - dialogs::SetOpacityDialog
+ - dialogs::ImageSizeDialog
+
+(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 gui_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 = 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,
+ 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 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'],])
+
+ 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)
+
+ 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):
+ self.keycol.Enable(event.IsChecked())
+
+ def _layout(self):
+ """!Do layout"""
+ self.dataSizer.Add(self.element, proportion = 0,
+ flag = wx.EXPAND | wx.ALL, border = 1)
+
+ self.dataSizer.Add(self.table, proportion = 0,
+ flag = wx.EXPAND | wx.ALL, border = 1)
+
+ 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"""
+ return self.keycol.GetValue()
+
+ 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 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
+ """
+ dlg = NewVectorDialog(parent, title = title,
+ disableAdd = disableAdd, disableTable = disableTable)
+
+ 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
+
+ listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
+
+ 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
+
+ # create attribute table
+ if dlg.table.IsEnabled() and dlg.table.IsChecked():
+ 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')
+
+ # 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.Map.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, 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)
+
+ self.subGroup = wx.CheckBox(parent = self, id = wx.ID_ANY,
+ label = _("Define also sub-group (same name as group)"))
+ bodySizer.Add(item = self.subGroup, flag = wx.BOTTOM | wx.EXPAND, 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)
+
+ kwargs = {}
+ if self.subGroup.IsChecked():
+ kwargs['subgroup'] = group
+
+ ret = None
+ if remove:
+ ret = RunCommand('i.group',
+ parent = self,
+ group = group,
+ flags = 'r',
+ input = ','.join(remove),
+ **kwargs)
+
+ if add:
+ ret = RunCommand('i.group',
+ parent = self,
+ group = group,
+ input = ','.join(add),
+ **kwargs)
+
+ return ret
+
+ def CreateNewGroup(self, group):
+ """!Create new group"""
+ layers = self.GetLayers()
+
+ kwargs = {}
+ if self.subGroup.IsChecked():
+ kwargs['subgroup'] = group
+
+ return RunCommand('i.group',
+ parent = self,
+ group = group,
+ input = layers,
+ **kwargs)
+
+ 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
+ #
+ self.list = LayersList(self.panel)
+ 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):
+ """!Dialog for bulk import of various raster/vector data"""
+ def __init__(self, parent, ogr = False, link = False):
+ 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 = True).ParseCommand(cmd = [name])
+
+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, 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)
+ listmix.TextEditMixin.__init__(self)
+
+ self.InsertColumn(0, _('Layer id'))
+ self.InsertColumn(1, _('Layer name'))
+ self.InsertColumn(2, _('Name for GRASS map (editable)'))
+
+ 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 id, name, grassName in data:
+ index = self.InsertStringItem(sys.maxint, str(id))
+ self.SetStringItem(index, 1, "%s" % str(name))
+ self.SetStringItem(index, 2, "%s" % str(grassName))
+ # check by default
+ ### self.CheckItem(index, True)
+
+ self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
+
+ 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 == 2:
+ 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 self.IsChecked(item):
+ # layer / output name
+ data.append((self.GetItem(item, 1).GetText(),
+ self.GetItem(item, 2).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 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)
Copied: grass/branches/develbranch_6/gui/wxpython/gui_core/forms.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/forms.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/forms.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2042 @@
+p"""
+ at package gui_core.forms
+
+ at brief Construct simple wxPython GUI from a GRASS command interface
+description.
+
+Classes:
+ - forms::UpdateThread
+ - forms::UpdateQThread
+ - forms::TaskFrame
+ - forms::CmdPanel
+ - forms::GUI
+ - forms::GrassGUIApp
+
+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 string
+import textwrap
+import os
+import time
+import copy
+import locale
+from threading import Thread
+import Queue
+
+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(gisbase, 'etc', 'gui', 'wxpython')
+
+sys.path.append(wxbase)
+
+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.newevent import NewEvent
+
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree # Python <= 2.4
+
+from grass.script import core as grass
+from grass.script import task as gtask
+
+from gui_core.widgets import StaticWrapText
+from gui_core.ghelp import HelpPanel
+from gui_core import gselect
+from core import gcmd
+from core import utils
+from core.settings import UserSettings
+from gui_core.widgets import FloatValidator, GNotebook
+
+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' : { 'd.legend' : { 'flags' : ['m'] } }
+ }
+
+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()
+
+ if name == 'LayerSelect':
+ if map in cparams and not cparams[map]['layers']:
+ win.InsertLayers(vector = map)
+ win.Reset()
+ cparams[map]['layers'] = win.GetItems()
+
+ elif name == 'TableSelect':
+ pDriver = self.task.get_param('dbdriver', element='prompt', raiseError=False)
+ driver = db = None
+ if pDriver:
+ driver = pDriver['value']
+ pDb = self.task.get_param('dbname', element='prompt', raiseError=False)
+ if pDb:
+ db = pDb['value']
+
+ self.data[win.InsertTables] = { 'driver' : driver,
+ 'database' : db }
+
+ elif name == 'ColumnSelect':
+ pLayer = self.task.get_param('layer', element='element', raiseError=False)
+ if pLayer:
+ if pLayer.get('value', '') != '':
+ layer = pLayer.get('value', '')
+ else:
+ layer = pLayer.get('default', '')
+ else:
+ layer = 1
+
+ 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
+ driver = db = None
+ pDriver = self.task.get_param('dbdriver', element='prompt', raiseError=False)
+ if pDriver:
+ driver = pDriver.get('value', None)
+ pDb = self.task.get_param('dbname', element='prompt', raiseError=False)
+ if pDb:
+ db = pDb.get('value', None)
+ pTable = self.task.get_param('dbtable', element='element', raiseError=False)
+ if pTable and \
+ pTable.get('value', '') != '':
+ if driver and db:
+ self.data[win.InsertTableColumns] = { 'table' : pTable.get('value'),
+ 'driver' : driver,
+ 'database' : db }
+ else:
+ 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 TaskFrame(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,
+ frame = 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)
+ self.SetSize(wx.Size(sizeFrame[0], sizeFrame[1] + 0.33 * 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
+
+ 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:
+
+ 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)
+
+ # 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, frame = None, *args, **kwargs):
+ if frame:
+ self.parent = frame
+ 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',
+ 'layer_zero',
+ 'location',
+ 'mapset',
+ 'dbase') and \
+ p.get('element', '') != 'file':
+ 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)
+ 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')
+
+
+ # 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)
+
+ value = self._getValue(p)
+ if value:
+ selection.SetValue(value) # parameter previously set
+
+ which_sizer.Add(item=selection, proportion=0,
+ flag=wx.ADJUST_MINSIZE| wx.BOTTOM | wx.LEFT | wx.RIGHT, border=5)
+
+ if p.get('prompt', '') in ('vector', 'group'):
+ selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
+ # 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',
+ 'layer_zero',
+ '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',
+ 'layer_zero'):
+
+ if p.get('age', 'old_layer') == 'old_layer':
+ initial = list()
+ if p.get('prompt', '') == 'layer_all':
+ initial.insert(0, '-1')
+ elif p.get('prompt', '') == 'layer_zero':
+ initial.insert(0, '0')
+ lyrvalue = p.get('default')
+ if lyrvalue != '':
+ if lyrvalue not in initial:
+ initial.append(str(lyrvalue))
+ lyrvalue = p.get('value')
+ if lyrvalue != '':
+ if lyrvalue not in initial:
+ initial.append(str(lyrvalue))
+
+ win = gselect.LayerSelect(parent = which_panel,
+ initial = initial,
+ default = p['default'])
+ p['wxGetValue'] = win.GetStringSelection
+ 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
+
+ elif p.get('prompt', '') == 'dbdriver':
+ win = gselect.DriverSelect(parent = which_panel,
+ choices = p.get('values', []),
+ value = value)
+ p['wxGetValue'] = win.GetStringSelection
+ 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_dbtable') == 'old_dbtable':
+ win = gselect.TableSelect(parent=which_panel)
+
+ p['wxGetValue'] = win.GetStringSelection
+ 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':
+ win = gselect.MapsetSelect(parent = which_panel,
+ value = value)
+ win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
+ win.Bind(wx.EVT_COMBOBOX, 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_file') == 'new_file':
+ 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_file') == 'old_file' 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())
+
+ 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
+
+ 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
+
+ pColumnIds = []
+ for p in pColumn:
+ pColumnIds += p['wxId']
+ pLayerIds = []
+ for p in pLayer:
+ pLayerIds += p['wxId']
+
+ 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 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 in ('DriverSelect', 'TableSelect',
+ 'LocationSelect', 'MapsetSelect', 'ProjSelect'):
+ porf['value'] = me.GetStringSelection()
+ elif name == 'GdalSelect':
+ porf['value'] = event.dsn
+ elif name == 'ModelParam':
+ porf['parameterized'] = me.IsChecked()
+ elif name == 'LayerSelect':
+ porf['value'] = me.GetValue()
+ 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 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:
+ params = self.grass_task.get_options()['params']
+ if params:
+ if i == 0: # add key name of first parameter if not given
+ key = params[0]['name']
+ 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
+ if '@' not in value:
+ 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 = TaskFrame(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 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 = TaskFrame(parent = None, ID = wx.ID_ANY, task_description = self.grass_task)
+ self.mf.CentreOnScreen()
+ self.mf.Show(True)
+ self.SetTopWindow(self.mf)
+
+ return True
+
+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])
+ 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/branches/develbranch_6/gui/wxpython/gui_core/ghelp.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/ghelp.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/ghelp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,888 @@
+"""!
+ at package gui_core.ghelp
+
+ at brief Help window
+
+Classes:
+ - ghelp::SearchModuleWindow
+ - ghelp::MenuTreeWindow
+ - ghelp::MenuTree
+ - ghelp::AboutWindow
+ - ghelp::HelpFrame
+ - ghelp::HelpWindow
+ - ghelp::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
+from wx.html import HtmlWindow
+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 core import globalvar
+from core import utils
+from lmgr.menudata import ManagerData
+from core.gcmd import GError, DecodeString
+from gui_core.widgets import GNotebook, StaticWrapText, ItemTree
+
+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 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(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(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 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 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/branches/develbranch_6/gui/wxpython/gui_core/goutput.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/goutput.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/goutput.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1140 @@
+"""!
+ at package gui_core.goutput
+
+ at brief Command output widgets
+
+Classes:
+ - goutput::CmdThread
+ - goutput::GMConsole
+ - goutput::GMStdout
+ - goutput::GMStderr
+ - goutput::GMStc
+
+(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"""
+ 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
+
+ # 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.vect' : 'vector',
+ 'd.vect.thematic': '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 None
+
+ 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|...)
+ # 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"]
+
+ if len(command) == 1:
+ task = gtask.parse_interface(command[0])
+ # if not task.has_required():
+ # task = None # run command
+ else:
+ task = None
+
+ if task and command[0] not in ('v.krige.py'):
+ # process GRASS command without argument
+ GUI(parent = self).ParseCommand(command)
+ else:
+ # 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)
+
+ return None
+
+ # 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 None
+
+ 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 = 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 = EncodeString(txt)
+
+ self.AddText(txt)
+
+ # reset output window to read only
+ self.SetReadOnly(True)
Copied: grass/branches/develbranch_6/gui/wxpython/gui_core/gselect.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gselect.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/gselect.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/gselect.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1695 @@
+"""!
+ at package gui_core.gselect
+
+ at brief Custom control that selects elements
+
+Classes:
+ - gselect::Select
+ - gselect::VectorSelect
+ - gselect::TreeCrtlComboPopup
+ - gselect::VectorDBInfo
+ - gselect::LayerSelect
+ - gselect::DriverSelect
+ - gselect::DatabaseSelect
+ - gselect::TableSelect
+ - gselect::ColumnSelect
+ - gselect::DbaseSelect
+ - gselect::LocationSelect
+ - gselect::MapsetSelect
+ - gselect::SubGroupSelect
+ - gselect::FormatSelect
+ - gselect::GdalSelect
+ - gselect::ProjSelect
+ - gselect::ElementSelect
+
+(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()
+
+ if (len(self.layers.keys()) == 0):
+ return False
+
+ return True
+
+ 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):
+ """!Creates combo box for selecting data layers defined for vector.
+ """
+ def __init__(self, parent,
+ id = wx.ID_ANY, pos = wx.DefaultPosition,
+ size = globalvar.DIALOG_LAYER_SIZE,
+ vector = None, choices = [], initial = [], default = None):
+
+ super(LayerSelect, self).__init__(parent, id, pos=pos, size=size,
+ choices=choices)
+
+ self.parent = parent
+ self.initial = initial
+
+ self.SetName("LayerSelect")
+
+ # default value
+ self.default = default
+
+ self.InsertLayers(vector = vector)
+
+ def InsertLayers(self, vector):
+ """!Insert layers for a vector into the layer combobox
+
+ @param vector name of vector map
+ """
+ if vector:
+ layers = GetVectorNumberOfLayers(vector)
+ else:
+ layers = list()
+
+ for layer in self.initial:
+ if layer in layers:
+ continue
+ layers.append(layer)
+
+ 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) >= 1:
+ self.SetItems(layers)
+
+ def Reset(self):
+ """!Reset value"""
+ items = self.GetItems()
+ if items:
+ if '-1' in items:
+ self.SetStringSelection('-1')
+ else:
+ self.SetSelection(0)
+ else:
+ self.SetValue('')
+
+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, **kwargs):
+ super(MapsetSelect, self).__init__(parent, id, size = size,
+ style = wx.CB_READONLY, **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_COMBOBOX_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,
+ default = 'file',
+ exclude = [],
+ envHandler = None):
+ """!Widget for selecting GDAL/OGR datasource, format
+
+ @param parent parent window
+ @param ogr use OGR selector instead of GDAL
+ """
+ self.parent = parent
+ self.ogr = ogr
+ 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,
+ label=" %s " % _("Source"))
+
+ # source type
+ sources = list()
+ self.sourceMap = { 'file' : -1,
+ 'dir' : -1,
+ 'db' : -1,
+ 'pro' : -1 }
+ idx = 0
+ 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,
+ label = _('Source type'),
+ style = wx.RA_SPECIFY_COLS,
+ choices = sources)
+ 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()[fType]['file']],
+ 'dir' : [_("Directory:"),
+ dsnDir,
+ GetFormats()[fType]['file']],
+ 'db' : [_("Database:"),
+ dsnDbFile,
+ GetFormats()[fType]['database']],
+ 'pro' : [_("Protocol:"),
+ dsnPro,
+ GetFormats()[fType]['protocol']],
+ 'db-win' : { 'file' : dsnDbFile,
+ 'text' : dsnDbText,
+ 'choice' : dsnDbChoice },
+ }
+
+ self.dsnType = default
+ self.input[self.dsnType][1].Show()
+ self.format.SetItems(self.input[self.dsnType][2])
+
+ 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._layout()
+
+ 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(1)
+ self.dsnSizer.AddGrowableCol(3)
+
+ self.dsnSizer.Add(item=self.dsnText,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos = (0, 0))
+ self.dsnSizer.Add(item=self.input[self.dsnType][1],
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+ pos = (0, 1), span = (1, 3))
+
+ self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
+ label = _("Format:")),
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 0))
+ self.dsnSizer.Add(item=self.format,
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 1))
+ self.dsnSizer.Add(item = self.extensionText,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 2))
+ self.dsnSizer.Add(item=self.extension,
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 3))
+
+ inputSizer.Add(item=self.dsnSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL)
+
+ 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 named '%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])
+
+ 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:
+ name, ftype, dsn, format = line.rstrip('\n').split(';')
+ data[name] = (ftype, dsn, format)
+ 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]
+ 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'
+
+ self.dsnText.SetLabel(self.input[self.dsnType][0])
+ if self.parent.GetName() == 'MultiImportDialog':
+ self.parent.list.DeleteAllItems()
+ self.format.SetItems(self.input[self.dsnType][2])
+
+ if sel in (self.sourceMap['file'],
+ self.sourceMap['dir']):
+ win = self.input[self.dsnType][1]
+ self.dsnSizer.Add(item=self.input[self.dsnType][1],
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+ pos = (0, 1))
+ win.SetValue('')
+ win.Show()
+
+ if not self.ogr:
+ self.OnSetFormat(event = None, format = 'GeoTIFF')
+ else:
+ self.OnSetFormat(event = None, format = 'ESRI Shapefile')
+ else:
+ if sel == self.sourceMap['pro']:
+ win = self.input[self.dsnType][1]
+ self.dsnSizer.Add(item=self.input[self.dsnType][1],
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
+ pos = (0, 1))
+ win.SetValue('')
+ win.Show()
+
+ if sel == self.sourceMap['dir']:
+ 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:
+ return
+
+ 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.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 file in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
+ baseName = os.path.basename(file)
+ grassName = GetValidLayerName(baseName.split('.', -1)[0])
+ data.append((layerId, baseName, grassName))
+ layerId += 1
+ elif self.dsnType == 'db':
+ ret = RunCommand('v.in.ogr',
+ quiet = True,
+ read = True,
+ flags = 'l',
+ 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.split(','):
+ layerName = line.strip()
+ grassName = GetValidLayerName(layerName)
+ data.append((layerId, layerName.strip(), grassName.strip()))
+ layerId += 1
+
+ evt = wxGdalSelect(dsn = dsn + '@OGR')
+ 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"""
+ # 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)
+ 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 = (0, 1), span = (1, 3))
+ self.dsnSizer.Layout()
+
+ # update extension
+ self.extension.SetValue(self.GetFormatExt())
+
+ # 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 GetFormatExt(self):
+ """!Get format extension"""
+ return self.format.GetExtension(self.format.GetStringSelection())
+
+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.SetItems(self.values)
+
+ def GetValue(self, name):
+ """!Translate value
+
+ @param name element name
+ """
+ return name
Added: grass/branches/develbranch_6/gui/wxpython/gui_core/mapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/mapdisp.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/mapdisp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,337 @@
+"""!
+ at package gui_core.mapdisp
+
+ at brief Base classes for Map display window
+
+Classes:
+ - mapdisp::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()
Added: grass/branches/develbranch_6/gui/wxpython/gui_core/mapwindow.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/mapwindow.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/mapwindow.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,240 @@
+"""!
+ at package gui_core.mapwindow
+
+ at brief Map display canvas - base class for buffered window.
+
+Classes:
+ - mapwindow::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
+
+from core.settings import UserSettings
+
+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
Copied: grass/branches/develbranch_6/gui/wxpython/gui_core/menu.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/menu.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/menu.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/menu.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,120 @@
+"""!
+ at package gui_core.menu
+
+ at brief Menu classes for wxGUI
+
+Classes:
+ - menu::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(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/branches/develbranch_6/gui/wxpython/gui_core/preferences.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/preferences.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1529 @@
+"""!
+ 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:
+ - preferences::PreferencesBaseDialog
+ - preferences::PreferencesDialog
+ - preferences::DefaultFontDialog
+ - preferences::MapsetAccess
+ - preferences::CheckListMapset
+
+(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 = 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)
+ # check if cairo is available
+ if 'cairo' not in listOfDrivers:
+ for line in RunCommand('d.mon',
+ flags = 'l',
+ read = True).splitlines():
+ if 'cairo' in line:
+ listOfDrivers.append('cairo')
+ break
+
+ 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
+ rasterOverlay = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+ label=_("Overlay raster maps"),
+ name='IsChecked')
+ rasterOverlay.SetValue(self.settings.Get(group='cmd', key='rasterOverlay', subkey='enabled'))
+ self.winId['cmd:rasterOverlay:enabled'] = rasterOverlay.GetId()
+
+ gridSizer.Add(item=rasterOverlay,
+ 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
+ """
+ dlg = DefaultFontDialog(parent = self,
+ title = _('Select output font'),
+ style = wx.DEFAULT_DIALOG_STYLE,
+ type = 'outputfont')
+
+ if dlg.ShowModal() == wx.ID_OK:
+ # set output font and font size variables
+ if dlg.font:
+ self.settings.Set(group = 'appearance', value = dlg.font,
+ key = 'outputfont', subkey = 'type')
+
+ self.settings.Set(group = 'appearance', value = dlg.fontsize,
+ key = 'outputfont', subkey = 'size')
+
+# Standard font dialog broken for Mac in OS X 10.6
+# type = self.settings.Get(group = 'display', key = 'outputfont', subkey = 'type')
+
+# size = self.settings.Get(group = 'display', key = 'outputfont', subkey = 'size')
+# if size == None or size == 0: size = 10
+# size = float(size)
+
+# data = wx.FontData()
+# data.EnableEffects(True)
+# data.SetInitialFont(wx.Font(pointSize = size, family = wx.FONTFAMILY_MODERN, faceName = type, style = wx.NORMAL, weight = 0))
+
+# dlg = wx.FontDialog(self, data)
+
+# if dlg.ShowModal() == wx.ID_OK:
+# data = dlg.GetFontData()
+# font = data.GetChosenFont()
+
+# self.settings.Set(group = 'display', value = font.GetFaceName(),
+# key = 'outputfont', subkey = 'type')
+# self.settings.Set(group = 'display', 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 = []
+
+ 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, **kwargs)
+
+ 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/branches/develbranch_6/gui/wxpython/gui_core/prompt.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/prompt.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/prompt.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1157 @@
+"""!
+ at package gui_core.prompt
+
+ at brief wxGUI command prompt
+
+Classes:
+ - prompt::PromptListCtrl
+ - prompt::TextCtrlAutoComplete
+ - prompt::GPrompt
+ - prompt::GPromptPopUp
+ - prompt::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', 'v.type'):
+ cmd = cmd + '_wrapper'
+
+ 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(EncodeString((line)))
+ cmd = map(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/branches/develbranch_6/gui/wxpython/gui_core/toolbars.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,168 @@
+"""!
+ at package gui_core.toolbars
+
+ at brief Base classes toolbar widgets
+
+Classes:
+ - toolbars::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 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 _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/branches/develbranch_6/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_core/widgets.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/gui_core/widgets.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,393 @@
+"""!
+ at package gui_core.widgets
+
+ at brief Core GUI widgets
+
+Classes:
+ - widgets::GNotebook
+ - widgets::ScrolledPanel
+ - widgets::NTCValidator
+ - widgets::NumTextCtrl
+ - widgets::FloatSlider
+ - widgets::SymbolButton
+ - widgets::StaticWrapText
+ - widgets::FloatValidator
+ - widgets::ItemTree
+
+(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
+try:
+ import wx.lib.agw.customtreectrl as CT
+except ImportError:
+ import wx.lib.customtreectrl as CT
+
+from core import globalvar
+from core.debug import Debug
+
+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 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
+ """
+ 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 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 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 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
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/colorrules.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/colorrules.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/colorrules.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1778 +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
- - 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
- """
- 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 self.inmap and not self.CheckMapset():
- # currently v.colors need the map to be in current mapset
- if self.version7 and self.attributeType == 'color':
- message = _("Selected map <%s> is not in current mapset <%s>. "
- "Color rules cannot be edited.") % \
- (self.inmap, grass.gisenv()['MAPSET'])
- else:
- 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.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))"""
- # 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 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
- old_colrtable = None
- path = grass.find_file(name = self.inmap, element = 'vector')['file']
-
- if os.path.exists(os.path.join(path, 'colr')):
- old_colrtable = os.path.join(path, 'colr')
- 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 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/branches/develbranch_6/gui/wxpython/gui_modules/dbm.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,3089 +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)
- else:
- wx.CallAfter(self.notebook.SetSelection, 0) # 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 = 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.renamecol',
- { '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.dropcol',
- { '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.dropcol',
- { '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.addcol command to the list
- if ctype == 'varchar':
- ctype += ' (%d)' % length
- self.listOfCommands.append(('v.db.addcol',
- { '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.addcol)
- 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,
- 'list' : 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,
- 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/branches/develbranch_6/gui/wxpython/gui_modules/dbm_base.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_base.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_base.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/dbm_dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_dialogs.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/dbm_dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,666 +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 __SelectAttributes(self, layer):
- """!Select attributes"""
- pass
-
- 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.notebook.GetPageCount())
-
- 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 cat=%s" % 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"""
- 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)
-
- gcmd.RunCommand('db.execute',
- parent = self,
- quiet = True,
- stdin = sql)
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/debug.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/debug.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/debug.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/disp_print.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/disp_print.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/disp_print.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,644 +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 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
-
- @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 CmdError 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
- """
- def __init__ (self, cmd, stdin = None,
- verbose = None, wait = True, rerr = False,
- stdout = None, stderr = 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()
-
- # TODO: replace ugly hack bellow
- args = self.cmd
- if sys.platform == 'win32' and os.path.splitext(self.cmd[0])[1] == '.py':
- os.chdir(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'scripts'))
- args = [sys.executable, self.cmd[0]] + self.cmd[1:]
-
- try:
- self.module = Popen(args,
- stdin = subprocess.PIPE,
- stdout = subprocess.PIPE,
- stderr = subprocess.PIPE,
- shell = sys.platform == "win32")
- except OSError, e:
- self.error = str(e)
- print >> sys.stderr, 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, 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 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
-
- ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
-
- Debug.msg(2, "gcmd.RunCommand(): command started")
-
- 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" % ret)
-
- 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 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/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmanager.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2794 +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 g.transform to calculate forward and backward error for each used GCP
- in POINTS file and insert error values into GCP list.
- Calculates total forward and backward RMS error for all used points
- """
- # save GCPs to points file to make sure that all checked GCPs are used
- self.SaveGCPs(None)
- #self.SetStatusText('')
-
- if self.CheckGCPcount(msg=True) == False:
- return
-
- # get list of forward and reverse rms error values for each point
- self.grwiz.SwitchEnv('source')
-
- ret = gcmd.RunCommand('g.transform',
- parent = self,
- read = True,
- group = xygroup,
- order = order)
-
- self.grwiz.SwitchEnv('target')
-
- if ret:
- errlist = ret.splitlines()
- else:
- gcmd.GError(parent = self,
- message=_('Could not calculate RMS Error.\n'
- 'Possible error with g.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('g.transform',
- parent = self,
- read = True,
- group = self.xygroup,
- order = 1,
- format = 'dst',
- coords = coord_file)
-
- elif map == 'target':
- ret = gcmd.RunCommand('g.transform',
- parent = self,
- read = True,
- group = self.xygroup,
- order = 1,
- flags = 'r',
- format = 'src',
- coords = coord_file)
-
- os.unlink(coord_file)
-
- self.grwiz.SwitchEnv('target')
-
- if ret:
- errlist = ret.splitlines()
- else:
- gcmd.GError(parent = self,
- message=_('Could not calculate new extends.\n'
- 'Possible error with g.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"]
-
- # 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/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcpmapdisp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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_command import Command
-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/branches/develbranch_6/gui/wxpython/gui_modules/gdialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gdialogs.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gdialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2200 +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
- - DxfImportDialog
- - LayersList (used by MultiImport)
- - SetOpacityDialog
- - StaticWrapText
- - ImageSizeDialog
-
-(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 debug import Debug
-from preferences import globalSettings as UserSettings
-
-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,
- 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 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'],])
-
- 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)
-
- 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):
- self.keycol.Enable(event.IsChecked())
-
- def _layout(self):
- """!Do layout"""
- self.dataSizer.Add(self.element, proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 1)
-
- self.dataSizer.Add(self.table, proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 1)
-
- 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"""
- return self.keycol.GetValue()
-
- 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 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
- """
- dlg = NewVectorDialog(parent, title = title,
- disableAdd = disableAdd, disableTable = disableTable)
-
- 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
-
- listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
-
- 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
-
- # create attribute table
- if dlg.table.IsEnabled() and dlg.table.IsChecked():
- 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')
-
- # 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.Map.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, 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)
-
- self.subGroup = wx.CheckBox(parent = self, id = wx.ID_ANY,
- label = _("Define also sub-group (same name as group)"))
- bodySizer.Add(item = self.subGroup, flag = wx.BOTTOM | wx.EXPAND, 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)
-
- kwargs = {}
- if self.subGroup.IsChecked():
- kwargs['subgroup'] = group
-
- ret = None
- if remove:
- ret = gcmd.RunCommand('i.group',
- parent = self,
- group = group,
- flags = 'r',
- input = ','.join(remove),
- **kwargs)
-
- if add:
- ret = gcmd.RunCommand('i.group',
- parent = self,
- group = group,
- input = ','.join(add),
- **kwargs)
-
- return ret
-
- def CreateNewGroup(self, group):
- """!Create new group"""
- layers = self.GetLayers()
-
- kwargs = {}
- if self.subGroup.IsChecked():
- kwargs['subgroup'] = group
-
- return gcmd.RunCommand('i.group',
- parent = self,
- group = group,
- input = layers,
- **kwargs)
-
- 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
- #
- self.list = LayersList(self.panel)
- 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):
- """!Dialog for bulk import of various raster/vector data"""
- def __init__(self, parent, ogr = False, link = False):
- 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 = True).ParseCommand(cmd = [name])
-
-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, 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)
- listmix.TextEditMixin.__init__(self)
-
- self.InsertColumn(0, _('Layer id'))
- self.InsertColumn(1, _('Layer name'))
- self.InsertColumn(2, _('Name for GRASS map (editable)'))
-
- 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 id, name, grassName in data:
- index = self.InsertStringItem(sys.maxint, str(id))
- self.SetStringItem(index, 1, "%s" % str(name))
- self.SetStringItem(index, 2, "%s" % str(grassName))
- # check by default
- ### self.CheckItem(index, True)
-
- self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
-
- 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 == 2:
- 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 self.IsChecked(item):
- # layer / output name
- data.append((self.GetItem(item, 1).GetText(),
- self.GetItem(item, 2).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)
-
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/ghelp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1304 +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.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.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.py')
-
- 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'))
-
- 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.py')
-
- 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.py']
-
- 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.py'] + 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',
- '' : '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.py', read = True, parent = self,
- 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 = ''
- 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 = ''
- name = line.strip()
-
- if self._expandPrefix(prefix) == prefix:
- prefix = ''
-
- 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:
- if prefix:
- text = prefix + '.' + name
- else:
- text = name
- new = self.AppendItem(parentId = item,
- text = text)
- 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/branches/develbranch_6/gui/wxpython/gui_modules/globalvar.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/globalvar.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/globalvar.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,183 +0,0 @@
-"""!
- at package global.py
-
- at brief Global variables
-
-This module provide the space for global variables
-used in the code.
-
-(C) 2007-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>
-"""
-
-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, "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 = (700, 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 = '.bat'
-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 and sys.platform != "win32":
- 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')
- os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'wxpython', 'scripts')
- for script in os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts')):
- patt = "_wrapper" # ignore wrappers
- if script[-len(patt):] != patt:
- cmd.append(script)
-
- if addons and os.getenv('GRASS_ADDON_PATH'):
- path = os.getenv('GRASS_ADDON_PATH')
- for ipath in path.split(os.pathsep):
- if not os.path.exists(ipath):
- continue
- for executable in os.listdir(ipath):
- ext = os.path.splitext(executable)[1]
- if not EXT_BIN or \
- ext in (EXT_BIN, EXT_SCT):
- cmd.append(executable)
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,5095 +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_file':
- 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()
- dlg.Destroy()
- 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()
- dlg.Destroy()
- 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'] = ''
-
- 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 (experimental prototype)"), **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 and cmd[0] in ('r.mapcalc', 'v.type'):
- cmd[0] += '_wrapper'
-
- 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('<', '<')
- value = value.replace('>', '>')
-
- 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('<', '<')
- value = value.replace('>', '>')
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1144 +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"""
- 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
-
- # 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.vect' : 'vector',
- 'd.vect.thematic': '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 None
-
- 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|...)
- # 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"]
-
- if len(command) == 1:
- import menuform
- task = gtask.parse_interface(command[0])
- # if not task.has_required():
- # task = None # run command
- else:
- task = None
-
- if task and command[0] not in ('v.krige.py'):
- # process GRASS command without argument
- menuform.GUI(parent = self).ParseCommand(command)
- else:
- # 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)
-
- return None
-
- # 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:
- import menuform
- 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 None
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/gpyshell.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gpyshell.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gpyshell.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/gselect.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gselect.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gselect.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1693 +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
-
-(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()
-
- if (len(self.layers.keys()) == 0):
- return False
-
- return True
-
- 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):
- """!Creates combo box for selecting data layers defined for vector.
- """
- def __init__(self, parent,
- id = wx.ID_ANY, pos = wx.DefaultPosition,
- size = globalvar.DIALOG_LAYER_SIZE,
- vector = None, choices = [], initial = [], default = None):
-
- super(LayerSelect, self).__init__(parent, id, pos=pos, size=size,
- choices=choices)
-
- self.parent = parent
- self.initial = initial
-
- self.SetName("LayerSelect")
-
- # default value
- self.default = default
-
- self.InsertLayers(vector = vector)
-
- def InsertLayers(self, vector):
- """!Insert layers for a vector into the layer combobox
-
- @param vector name of vector map
- """
- if vector:
- layers = utils.GetVectorNumberOfLayers(vector)
- else:
- layers = list()
-
- for layer in self.initial:
- if layer in layers:
- continue
- layers.append(layer)
-
- 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) >= 1:
- self.SetItems(layers)
-
- def Reset(self):
- """!Reset value"""
- items = self.GetItems()
- if items:
- if '-1' in items:
- self.SetStringSelection('-1')
- else:
- self.SetSelection(0)
- else:
- self.SetValue('')
-
-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, **kwargs):
- super(MapsetSelect, self).__init__(parent, id, size = size,
- style = wx.CB_READONLY, **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_COMBOBOX_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,
- default = 'file',
- exclude = [],
- envHandler = None):
- """!Widget for selecting GDAL/OGR datasource, format
-
- @param parent parent window
- @param ogr use OGR selector instead of GDAL
- """
- self.parent = parent
- self.ogr = ogr
- 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,
- label=" %s " % _("Source"))
-
- # source type
- sources = list()
- self.sourceMap = { 'file' : -1,
- 'dir' : -1,
- 'db' : -1,
- 'pro' : -1 }
- idx = 0
- 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,
- label = _('Source type'),
- style = wx.RA_SPECIFY_COLS,
- choices = sources)
- 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()[fType]['file']],
- 'dir' : [_("Directory:"),
- dsnDir,
- utils.GetFormats()[fType]['file']],
- 'db' : [_("Database:"),
- dsnDbFile,
- utils.GetFormats()[fType]['database']],
- 'pro' : [_("Protocol:"),
- dsnPro,
- utils.GetFormats()[fType]['protocol']],
- 'db-win' : { 'file' : dsnDbFile,
- 'text' : dsnDbText,
- 'choice' : dsnDbChoice },
- }
-
- self.dsnType = default
- self.input[self.dsnType][1].Show()
- self.format.SetItems(self.input[self.dsnType][2])
-
- 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._layout()
-
- 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(1)
- self.dsnSizer.AddGrowableCol(3)
-
- self.dsnSizer.Add(item=self.dsnText,
- flag=wx.ALIGN_CENTER_VERTICAL,
- pos = (0, 0))
- self.dsnSizer.Add(item=self.input[self.dsnType][1],
- flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
- pos = (0, 1), span = (1, 3))
-
- self.dsnSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
- label = _("Format:")),
- flag = wx.ALIGN_CENTER_VERTICAL,
- pos = (1, 0))
- self.dsnSizer.Add(item=self.format,
- flag = wx.ALIGN_CENTER_VERTICAL,
- pos = (1, 1))
- self.dsnSizer.Add(item = self.extensionText,
- flag=wx.ALIGN_CENTER_VERTICAL,
- pos = (1, 2))
- self.dsnSizer.Add(item=self.extension,
- flag = wx.ALIGN_CENTER_VERTICAL,
- pos = (1, 3))
-
- inputSizer.Add(item=self.dsnSizer, proportion=1,
- flag=wx.EXPAND | wx.ALL)
-
- 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 named '%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])
-
- 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:
- name, ftype, dsn, format = line.rstrip('\n').split(';')
- data[name] = (ftype, dsn, format)
- 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]
- 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'
-
- self.dsnText.SetLabel(self.input[self.dsnType][0])
- if self.parent.GetName() == 'MultiImportDialog':
- self.parent.list.DeleteAllItems()
- self.format.SetItems(self.input[self.dsnType][2])
-
- if sel in (self.sourceMap['file'],
- self.sourceMap['dir']):
- win = self.input[self.dsnType][1]
- self.dsnSizer.Add(item=self.input[self.dsnType][1],
- flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
- pos = (0, 1))
- win.SetValue('')
- win.Show()
-
- if not self.ogr:
- self.OnSetFormat(event = None, format = 'GeoTIFF')
- else:
- self.OnSetFormat(event = None, format = 'ESRI Shapefile')
- else:
- if sel == self.sourceMap['pro']:
- win = self.input[self.dsnType][1]
- self.dsnSizer.Add(item=self.input[self.dsnType][1],
- flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND,
- pos = (0, 1))
- win.SetValue('')
- win.Show()
-
- if sel == self.sourceMap['dir']:
- 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:
- return
-
- 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.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 file in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
- baseName = os.path.basename(file)
- grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
- data.append((layerId, baseName, grassName))
- layerId += 1
- elif self.dsnType == 'db':
- ret = gcmd.RunCommand('v.in.ogr',
- quiet = True,
- read = True,
- flags = 'l',
- 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.split(','):
- layerName = line.strip()
- grassName = utils.GetValidLayerName(layerName)
- data.append((layerId, layerName.strip(), grassName.strip()))
- layerId += 1
-
- evt = wxGdalSelect(dsn = dsn + '@OGR')
- 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"""
- # 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)
- 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 = (0, 1), span = (1, 3))
- self.dsnSizer.Layout()
-
- # update extension
- self.extension.SetValue(self.GetFormatExt())
-
- # 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 GetFormatExt(self):
- """!Get format extension"""
- return self.format.GetExtension(self.format.GetStringSelection())
-
-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.SetItems(self.values)
-
- def GetValue(self, name):
- """!Translate value
-
- @param name element name
- """
- return name
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/histogram.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/histogram.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/histogram.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,462 +0,0 @@
-"""!
- at package histogram.py
-
-Plotting histogram
-
-Classes:
- - BufferedWindow
- - HistFrame
-
-COPYRIGHT: (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/branches/develbranch_6/gui/wxpython/gui_modules/layertree.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/layertree.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/layertree.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1554 +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
-import profile
-from debug import Debug as Debug
-from icon import Icons as Icons
-from preferences import globalSettings as UserSettings
-from vdigit import haveVDigit
-from gcmd import GWarning, GError
-
-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.MapWindow2D.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'):
- 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'])
-
- 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 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 = profile.ProfileFrame(self.mapdisplay,
- id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
- style = wx.DEFAULT_FRAME_STYLE, 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).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():
- GError(parent = self,
- message = _("Unable to display histogram of "
- "raster map. No map name defined."))
- return
-
- histogramFrame = histogram.HistFrame(parent = self,
- id = wx.ID_ANY,
- pos = wx.DefaultPosition, size = globalvar.HIST_WINDOW_SIZE,
- style = wx.DEFAULT_FRAME_STYLE)
- histogramFrame.Show()
- histogramFrame.SetHistLayer(mapLayer.GetName())
- histogramFrame.HistWindow.UpdateHist()
- histogramFrame.Refresh()
- histogramFrame.Update()
-
- def OnUnivariateStats(self, event):
- """!Univariate raster statistics"""
- name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
- self.lmgr.goutput.RunCmd(['r.univar', 'map=%s' % name], switchPage = True)
-
- 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 self.mapdisplay.GetToolbar('vdigit'): # enable tool
- self.mapdisplay.AddToolbar('vdigit')
-
- if not self.mapdisplay.toolbars['vdigit']:
- return
-
- 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"""
- item = self.layer_selected
- self.GetPyData(item)[0]['label'] = event.GetLabel()
- self.SetItemText(item, self._getLayerName(item)) # not working, why?
-
- 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 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))
-
- # updated progress bar range (mapwindow statusbar)
- if checked is True:
- 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)
-
- cmd = None
- 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='rasterOverlay', subkey='enabled'):
- cmd.append('-o')
-
- elif ltype == '3d-raster':
- cmd = ['d.rast3d']
-
- elif ltype == 'rgb':
- cmd = ['d.rgb']
- if UserSettings.Get(group='cmd', key='rasterOverlay', subkey='enabled'):
- cmd.append('-o')
-
- elif ltype == 'his':
- cmd = ['d.his']
-
- elif ltype == 'shaded':
- cmd = ['d.shadedmap']
-
- elif ltype == 'rastarrow':
- cmd = ['d.rast.arrow']
-
- elif ltype == 'rastnum':
- cmd = ['d.rast.num']
-
- 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)
-
- cmd = ['d.vect', 'type=%s' % ','.join(types)]
-
- elif ltype == 'thememap':
- # -s flag requested, otherwise only first thematic category is displayed
- # should be fixed by C-based d.thematic.* modules
- cmd = ['d.vect.thematic', '-s']
-
- elif ltype == 'themechart':
- cmd = ['d.vect.chart']
-
- elif ltype == 'grid':
- cmd = ['d.grid']
-
- elif ltype == 'geodesic':
- cmd = ['d.geodesic']
-
- elif ltype == 'rhumb':
- cmd = ['d.rhumbline']
-
- elif ltype == 'labels':
- cmd = ['d.labels']
-
- if cmd:
- menuform.GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
- completed = (self.GetOptData,layer,params))
-
- 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:
- # 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.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 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 propertiesdialog 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', '3d-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])
-
- @return item instance
- @return None not found
- """
- item = self.GetFirstChild(self.root)[0]
- 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 FindItemByValue"""
- 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
-
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/location_wizard.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/location_wizard.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/location_wizard.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1749 +0,0 @@
-"""!
- at package mapdisp.py
-
- at brief GIS map display canvas, with toolbar for various display
-management functions, and additional toolbars (vector digitizer, 3d
-view).
-
-Can be used either from Layer Manager or as p.mon backend.
-
-Classes:
- - MapFrameBase
- - MapFrame
- - MapApp
-
-Usage:
-python mapdisp.py monitor-identifier /path/to/command/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
-
-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 mapdisp_statusbar as sb
-import toolbars
-import menuform
-import gselect
-import disp_print
-import gcmd
-import dbm
-import dbm_dialogs
-import histogram
-import profile
-import globalvar
-import utils
-import gdialogs
-from grass.script import core as grass
-from debug import Debug
-from icon import Icons
-from preferences import globalSettings as UserSettings
-
-from mapdisp_command import Command
-from mapdisp_window import BufferedWindow
-
-# for standalone app
-cmdfilename = None
-
-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, mapcontent = self.Map,
- 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'):
- if self.MapWindow.digit:
- 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.toolbars['map']:
- 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('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.Profile, profile)
-
- histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
- histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
- toolsmenu.AppendItem(histogram)
- self.Bind(wx.EVT_MENU, self.Histogram, 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 Profile(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 = 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 Histogram(self, event):
- """!Init histogram display canvas and tools
- """
- self.histogram = histogram.HistFrame(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,5'],
- 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.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.
- """
- self.MapWindow.ZoomToMap()
-
- 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 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']
-
-# end of class MapFrame
-
-class MapApp(wx.App):
- def OnInit(self):
- wx.InitAllImageHandlers()
- if __name__ == "__main__":
- Map = render.Map() # instance of Map class to render GRASS display output to PPM file
- else:
- Map = None
-
- self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
- size = globalvar.MAP_WINDOW_SIZE)
- #self.SetTopWindow(Map)
- self.mapFrm.Show()
-
- if __name__ == "__main__":
- # redraw map, if new command appears
- self.redraw = False
- status = Command(self, Map, cmdfilename)
- status.start()
- self.timer = wx.PyTimer(self.watcher)
- # check each 0.1s
- self.timer.Start(100)
-
- return 1
-
- def OnExit(self):
- if __name__ == "__main__":
- # stop the timer
- self.timer.Stop()
- # terminate thread (a bit ugly)
- os.system("""!echo "quit" >> %s""" % (cmdfilename))
-
- def watcher(self):
- """!Redraw, if new layer appears"""
- if self.redraw:
- self.mapFrm.OnDraw(None)
- self.redraw = False
- return
-# end of class MapApp
-
-if __name__ == "__main__":
-
- ###### SET command variable
- if len(sys.argv) != 3:
- print __doc__
- sys.exit()
-
- title = sys.argv[1]
- cmdfilename = sys.argv[2]
-
- import gettext
- gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-
- print >> sys.stderr, "\nStarting monitor <%s>...\n" % (title)
-
- gm_map = MapApp(0)
- # set title
- gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
- title +
- " - Location: " + grass.gisenv()["LOCATION_NAME"]))
-
- gm_map.MainLoop()
-
- if grass.gisenv().has_key("MONITOR"):
- os.system("d.mon sel=%s" % grass.gisenv()["MONITOR"])
-
- os.remove(cmdfilename)
- os.system("""!g.gisenv set="GRASS_PYCMDFILE" """)
-
- print >> sys.stderr, "\nStoping monitor <%s>...\n" % (title)
-
- sys.exit(0)
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_statusbar.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_statusbar.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_statusbar.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_vdigit.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_vdigit.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_vdigit.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1070 +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()
-
- try:
- item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer())
- except TypeError:
- item = None
-
- if 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.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 = 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()
- item = self.tree.FindItemByData('maplayer', mapLayer)
- vdigit = self.tree.GetPyData(item)[0]['vdigit']
- 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()
- item = self.tree.FindItemByData('maplayer', mapLayer)
- vdigit = self.tree.GetPyData(item)[0]['vdigit']
-
- if vdigit is None 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/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1910 +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 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 \
- 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 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))
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/mcalc_builder.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/mcalc_builder.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/mcalc_builder.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,553 +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
-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_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.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_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.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)
- 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('%s = %s' % (name, expr))]
- self.log.RunCmd(cmd, onDone = self.OnDone)
- self.parent.Raise()
- else:
- gcmd.RunCommand(self.cmd,
- "%s=%s" % (name, expr))
-
- 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()
-
-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/branches/develbranch_6/gui/wxpython/gui_modules/menu.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/menu.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/menu.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/menudata.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/menudata.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/menudata.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,287 +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 <anna.kratochvilova fsv.cvut.cz>
-"""
-
-import os
-import sys
-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", "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)
-
- sys.exit(0)
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2136 +0,0 @@
-#!/usr/bin/env python
-"""
- at brief Construct simple wx.Python 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.
-
-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 todo
- - verify option value types
-"""
-
-import sys
-import re
-import string
-import textwrap
-import os
-import time
-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' : { 'd.legend' : { 'flags' : ['m'] } }
- }
-
-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()
-
- if name == 'LayerSelect':
- if map in cparams and not cparams[map]['layers']:
- win.InsertLayers(vector = map)
- win.Reset()
- cparams[map]['layers'] = win.GetItems()
-
- elif name == 'TableSelect':
- pDriver = self.task.get_param('dbdriver', element='prompt', raiseError=False)
- driver = db = None
- if pDriver:
- driver = pDriver['value']
- pDb = self.task.get_param('dbname', element='prompt', raiseError=False)
- if pDb:
- db = pDb['value']
-
- self.data[win.InsertTables] = { 'driver' : driver,
- 'database' : db }
-
- elif name == 'ColumnSelect':
- pLayer = self.task.get_param('layer', element='element', raiseError=False)
- if pLayer:
- if pLayer.get('value', '') != '':
- layer = pLayer.get('value', '')
- else:
- layer = pLayer.get('default', '')
- else:
- layer = 1
-
- 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
- driver = db = None
- pDriver = self.task.get_param('dbdriver', element='prompt', raiseError=False)
- if pDriver:
- driver = pDriver.get('value', None)
- pDb = self.task.get_param('dbname', element='prompt', raiseError=False)
- if pDb:
- db = pDb.get('value', None)
- pTable = self.task.get_param('dbtable', element='element', raiseError=False)
- if pTable and \
- pTable.get('value', '') != '':
- if driver and db:
- self.data[win.InsertTableColumns] = { 'table' : pTable.get('value'),
- 'driver' : driver,
- 'database' : db }
- else:
- 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)
- self.SetSize(wx.Size(sizeFrame[0], sizeFrame[1] + 0.33 * 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
-
- 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:
-
- 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)
-
- # 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',
- 'layer_zero',
- 'location',
- 'mapset',
- 'dbase') and \
- p.get('element', '') != 'file':
- 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)
- 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')
-
-
- # 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)
-
- value = self._getValue(p)
- if value:
- selection.SetValue(value) # parameter previously set
-
- which_sizer.Add(item=selection, proportion=0,
- flag=wx.ADJUST_MINSIZE| wx.BOTTOM | wx.LEFT | wx.RIGHT, border=5)
-
- if p.get('prompt', '') in ('vector', 'group'):
- selection.Bind(wx.EVT_TEXT, self.OnUpdateSelection)
- # 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',
- 'layer_zero',
- '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',
- 'layer_zero'):
-
- if p.get('age', 'old_layer') == 'old_layer':
- initial = list()
- if p.get('prompt', '') == 'layer_all':
- initial.insert(0, '-1')
- elif p.get('prompt', '') == 'layer_zero':
- initial.insert(0, '0')
- lyrvalue = p.get('default')
- if lyrvalue != '':
- if lyrvalue not in initial:
- initial.append(str(lyrvalue))
- lyrvalue = p.get('value')
- if lyrvalue != '':
- if lyrvalue not in initial:
- initial.append(str(lyrvalue))
-
- win = gselect.LayerSelect(parent = which_panel,
- initial = initial,
- default = p['default'])
- p['wxGetValue'] = win.GetStringSelection
- 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
-
- elif p.get('prompt', '') == 'dbdriver':
- win = gselect.DriverSelect(parent = which_panel,
- choices = p.get('values', []),
- value = value)
- p['wxGetValue'] = win.GetStringSelection
- 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_dbtable') == 'old_dbtable':
- win = gselect.TableSelect(parent=which_panel)
-
- p['wxGetValue'] = win.GetStringSelection
- 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':
- win = gselect.MapsetSelect(parent = which_panel,
- value = value)
- win.Bind(wx.EVT_COMBOBOX, self.OnUpdateSelection)
- win.Bind(wx.EVT_COMBOBOX, 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_file') == 'new_file':
- 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_file') == 'old_file' 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())
-
- 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
-
- 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
-
- pColumnIds = []
- for p in pColumn:
- pColumnIds += p['wxId']
- pLayerIds = []
- for p in pLayer:
- pLayerIds += p['wxId']
-
- 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 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 in ('DriverSelect', 'TableSelect',
- 'LocationSelect', 'MapsetSelect', 'ProjSelect'):
- porf['value'] = me.GetStringSelection()
- elif name == 'GdalSelect':
- porf['value'] = event.dsn
- elif name == 'ModelParam':
- porf['parameterized'] = me.IsChecked()
- elif name == 'LayerSelect':
- porf['value'] = me.GetValue()
- 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:
- params = self.grass_task.get_options()['params']
- if params:
- if i == 0: # add key name of first parameter if not given
- key = params[0]['name']
- 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
- if '@' not in value:
- 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 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/branches/develbranch_6/gui/wxpython/gui_modules/nviz.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/nviz_animation.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_animation.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_animation.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/nviz_mapdisp.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_mapdisp.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_mapdisp.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2475 +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 = tempfile.mktemp() + '.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)
-
- 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'] and 'x' 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')
-
- # 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')
-
- # 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 += "\\\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_transparency_map=" + cmdIsoTrMap.strip(',') + ' '
- if cmdIsoTrVal:
- cmd += "isosurf_transparency_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):
- """!Reset view
- """
- 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/branches/develbranch_6/gui/wxpython/gui_modules/nviz_preferences.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_preferences.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/nviz_tools.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_tools.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_tools.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,5052 +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)
-
- # display
- gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
- label = _("Display")),
- pos = (1, 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 = (1, 1), span = (1,4))
-
- # height
- gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
- label = _("Height above surface:")),
- pos = (2, 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 = (2, 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 = (3, 5), flag = wx.EXPAND|wx.ALIGN_RIGHT)
- gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['text']),
- pos = (4, 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))
-
- 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 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)
-
- #
- # 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'])
-
- # 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)
- for i in range(len(isosurfaces)):
- box.Check(i)
- 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)
- for i in range(len(slices)):
- box.Check(i)
- 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/branches/develbranch_6/gui/wxpython/gui_modules/ogc_services.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/ogc_services.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/ogc_services.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2493 +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' : 'grass2'
- }, # grass2, grass, silk
- },
- #
- # display
- #
- 'display': {
- 'font' : {
- 'type' : '',
- 'encoding': 'ISO-8859-1',
- },
- 'driver': {
- 'type': 'default'
- },
- '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
- 'rasterOverlay' : {
- 'enabled' : True
- },
- '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,
- },
- },
- 'profile': {
- 'raster0' : {
- 'pcolor' : (0, 0, 255, 255), # profile line color
- 'pwidth' : 1, # profile line width
- 'pstyle' : 'solid', # profile line pen style
- },
- 'raster1' : {
- 'pcolor' : (255, 0, 0, 255),
- 'pwidth' : 1,
- 'pstyle' : 'solid',
- },
- 'raster2' : {
- 'pcolor' : (0, 255, 0, 255),
- 'pwidth' : 1,
- 'pstyle' : 'solid',
- },
- '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
- },
- },
- '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,
- },
- 'points' : {
- 'show' : False,
- 'size' : 100,
- 'width' : 2,
- 'marker' : 2,
- 'color' : (0, 0, 255, 255), # blue
- 'height' : 0,
- }
- },
- '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',
- 'grass2',
- 'silk')
- 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'] = ['default']
- 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):
- # try alternative path
- filename = os.path.join(os.path.expanduser("~"), '.grasswx6')
- 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)
- # check if cairo is available
- if 'cairo' not in listOfDrivers:
- for line in gcmd.RunCommand('d.mon',
- flags = 'l',
- read = True).splitlines():
- if 'cairo' in line:
- listOfDrivers.append('cairo')
- break
-
- 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
- rasterOverlay = wx.CheckBox(parent=panel, id=wx.ID_ANY,
- label=_("Overlay raster maps"),
- name='IsChecked')
- rasterOverlay.SetValue(self.settings.Get(group='cmd', key='rasterOverlay', subkey='enabled'))
- self.winId['cmd:rasterOverlay:enabled'] = rasterOverlay.GetId()
-
- gridSizer.Add(item=rasterOverlay,
- 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
- """
- dlg = DefaultFontDialog(parent = self,
- title = _('Select output font'),
- style = wx.DEFAULT_DIALOG_STYLE,
- type = 'outputfont')
-
- if dlg.ShowModal() == wx.ID_OK:
- # set output font and font size variables
- if dlg.font:
- self.settings.Set(group = 'appearance', value = dlg.font,
- key = 'outputfont', subkey = 'type')
-
- self.settings.Set(group = 'appearance', value = dlg.fontsize,
- key = 'outputfont', subkey = 'size')
-
-# Standard font dialog broken for Mac in OS X 10.6
-# type = self.settings.Get(group = 'display', key = 'outputfont', subkey = 'type')
-
-# size = self.settings.Get(group = 'display', key = 'outputfont', subkey = 'size')
-# if size == None or size == 0: size = 10
-# size = float(size)
-
-# data = wx.FontData()
-# data.EnableEffects(True)
-# data.SetInitialFont(wx.Font(pointSize = size, family = wx.FONTFAMILY_MODERN, faceName = type, style = wx.NORMAL, weight = 0))
-
-# dlg = wx.FontDialog(self, data)
-
-# if dlg.ShowModal() == wx.ID_OK:
-# data = dlg.GetFontData()
-# font = data.GetChosenFont()
-
-# self.settings.Set(group = 'display', value = font.GetFaceName(),
-# key = 'outputfont', subkey = 'type')
-# self.settings.Set(group = 'display', 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, **kwargs)
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/profile.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/profile.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/profile.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1433 +0,0 @@
-"""!
- at package profile
-
-Profile analysis of raster maps and images.
-
-Uses PyPlot (wx.lib.plot.py)
-
-Classes:
- - ProfileFrame
- - SetRasterDialog
- - TextDialog
- - OptDialog
-
-(C) 2007-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
- at author Various updates by Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import math
-
-import wx
-import wx.lib.colourselect as csel
-
-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, "profile.py: " + msg
-
-import globalvar
-import gcmd
-from render import Map
-from gselect import Select
-from toolbars import ProfileToolbar
-from debug import Debug
-from icon import Icons
-from preferences import globalSettings as UserSettings
-
-from grass.script import core as grass
-
-class ProfileFrame(wx.Frame):
- """!Mainframe for displaying profile of raster map. Uses wx.lib.plot.
- """
- def __init__(self, parent = None, id = wx.ID_ANY, title = _("GRASS Profile Analysis Tool"),
- rasterList = [],
- style = wx.DEFAULT_FRAME_STYLE, **kwargs):
-
- self.parent = parent # MapFrame
- self.mapwin = self.parent.MapWindow
- self.Map = Map() # instance of render.Map to be associated with display
-
- self.pstyledict = { '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 }
-
- wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
-
- #
- # Icon
- #
- self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-
- #
- # Add toolbar
- #
- self.toolbar = ProfileToolbar(parent = self)
- self.SetToolBar(self.toolbar)
-
- #
- # Add statusbar
- #
- self.statusbar = self.CreateStatusBar(number = 2, style = 0)
- self.statusbar.SetStatusWidths([-2, -1])
-
- #
- # Define canvas
- #
- # plot canvas 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)
-
- #
- # Init variables
- #
- # 0 -> default raster map to profile
- # 1, 2 -> optional raster map to profile
- # units -> map data units (used for y axis legend)
- self.raster = {}
- for idx in (0, 1, 2):
- self.raster[idx] = {}
- self.raster[idx]['name'] = ''
- self.raster[idx]['units'] = ''
- self.raster[idx]['plegend'] = ''
- # list of distance,value pairs for plotting profile
- self.raster[idx]['datalist'] = []
- # first (default) profile line
- self.raster[idx]['pline'] = None
- self.raster[idx]['prop'] = UserSettings.Get(group = 'profile', key = 'raster' + str(idx))
- # changing color string to tuple
- colstr = str(self.raster[idx]['prop']['pcolor'])
- self.raster[idx]['prop']['pcolor'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
-
- # set raster map name (if given)
- for idx in range(len(rasterList)):
- self.raster[idx]['name'] = rasterList[idx]
-
- # string of coordinates for r.profile
- self.coordstr = ''
- # segment endpoint list
- self.seglist = []
- # list of things to plot
- self.plotlist = []
- # segment endpoints data
- self.ppoints = ''
- # plot draw object
- self.profile = None
- # total transect length
- self.transect_length = 0.0
-
- # title of window
- self.ptitle = _('Profile of')
-
- # 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")
-
- self.properties = {}
- self.properties['font'] = {}
- self.properties['font']['prop'] = UserSettings.Get(group = 'profile', key = 'font')
- self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
- wx.FONTSTYLE_NORMAL,
- wx.FONTWEIGHT_NORMAL)
-
- self.properties['marker'] = UserSettings.Get(group = 'profile', key = 'marker')
- # changing color string to tuple
- 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 = 'profile', key = 'grid')
- # changing color string to tuple
- colstr = str(self.properties['grid']['color'])
- 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 = 'profile', key = 'x-axis')
- self.properties['x-axis']['axis'] = None
-
- self.properties['y-axis'] = {}
- self.properties['y-axis']['prop'] = UserSettings.Get(group = 'profile', key = 'y-axis')
- self.properties['y-axis']['axis'] = None
-
- self.properties['legend'] = UserSettings.Get(group = 'profile', key = 'legend')
-
- # zooming disabled
- self.zoom = False
- # draging disabled
- self.drag = False
-
- # vertical and horizontal scrollbars
- self.client.SetShowScrollbars(True)
-
- # 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')
-
- #
- # Bind various events
- #
- self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-
- self.CentreOnScreen()
-
- 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 = SetRasterDialog(parent = self)
-
- if dlg.ShowModal() == wx.ID_OK:
- for r in self.raster.keys():
- self.raster[r]['name'] = dlg.raster[r]['name']
-
- # plot profile
- if self.raster[0]['name'] and len(self.mapwin.polycoords) > 0:
- self.OnCreateProfile(event = None)
-
- dlg.Destroy()
-
- def SetRaster(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 self.raster[0]['name'] == '':
- return
-
- # title of window
- self.ptitle = _('Profile of')
-
- #
- # create list of coordinates for transect segment markers
- #
-
- if len(self.mapwin.polycoords) > 0:
- 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.raster[0]['name'],
- east_north = '%d,%d' % (point[0],point[1]))
-
- val = ret.splitlines()[0].split('|')[3]
-
- # 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 first and last segment point
- try:
- self.seglist.pop(0)
- self.seglist.pop()
- except:
- pass
-
- #
- # create datalist for each raster map
- #
-
- for r in self.raster.itervalues():
- if r['name'] == '':
- continue
- r['datalist'] = self.CreateDatalist(r['name'], self.coordstr)
- r['plegend'] = _('Profile of %s') % r['name']
-
- ret = gcmd.RunCommand('r.info',
- parent = self,
- read = True,
- quiet = True,
- flags = 'u',
- map = r['name'])
-
- if ret:
- r['units'] = ret.splitlines()[0].split('=')[1]
-
- # update title
- self.ptitle += ' %s and' % r['name']
-
- self.ptitle = self.ptitle.rstrip('and')
-
- #
- # set ylabel to match units if they exist
- #
- self.ylabel = ''
- i = 0
-
- for r in self.raster.itervalues():
- if r['name'] == '':
- continue
- if r['units'] != '':
- self.ylabel = '%s (%d),' % (r['units'], i)
- i += 1
- if self.ylabel == '':
- self.ylabel = _('Raster values')
- else:
- self.ylabel = self.ylabel.rstrip(',')
-
- 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']['type'])
-
- 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']))
-
- # self.client.SetPointLabelFunc(self.DrawPointLabel())
-
- def CreateDatalist(self, raster, coords):
- """!Build a list of distance, value pairs for points along transect
- """
- 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 dataset
-
- for line in ret.splitlines():
- dist, elev = line.strip().split(' ')
- if elev != 'nan':
- 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 self.raster[0]['name'] == '':
- 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.SetRaster()
-
- self.DrawPlot()
-
- # 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 DrawPlot(self):
- """!Draw line and point plot from transect datalist and
- transect segment endpoint coordinates.
- """
- # graph the distance, value pairs for the transect
- self.plotlist = []
- 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)
-
- for r in self.raster.itervalues():
- if len(r['datalist']) > 0:
- col = wx.Color(r['prop']['pcolor'][0],
- r['prop']['pcolor'][1],
- r['prop']['pcolor'][2],
- 255)
- r['pline'] = plot.PolyLine(r['datalist'],
- colour = col,
- width = r['prop']['pwidth'],
- style = self.pstyledict[r['prop']['pstyle']],
- legend = r['plegend'])
-
- self.plotlist.append(r['pline'])
-
- self.profile = plot.PlotGraphics(self.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.profile, self.properties['x-axis']['axis'],
- self.properties['y-axis']['axis'])
-
- 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 profile window. Unzoom to original size
- """
- self.client.Reset()
- self.client.Redraw()
-
- def Update(self):
- """!Update profile after changing options
- """
- self.SetGraphStyle()
- self.DrawPlot()
-
- def OnErase(self, event):
- """!Erase the profile window
- """
- self.client.Clear()
- self.mapwin.ClearLines(self.mapwin.pdc)
- self.mapwin.ClearLines(self.mapwin.pdcTmp)
- self.mapwin.polycoords = []
- self.mapwin.Refresh()
- # try:
- # self.mapwin.pdc.ClearId(self.mapwin.lineid)
- # self.mapwin.pdc.ClearId(self.mapwin.plineid)
- # self.mapwin.Refresh()
- # except:
- # pass
-
- def SaveToFile(self, event):
- """!Save profile to graphics file
- """
- self.client.SaveFile()
-
- 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.raster.itervalues():
- if r['name'] == '':
- continue
-
- print 'path = '+str(path)
- pfile = path+'_'+str(r['name'])+'.csv'
- print 'pfile1 = '+str(pfile)
- 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 r['datalist']:
- file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
-
- file.close()
-
- dlg.Destroy()
-
- 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 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 ProfileOptionsMenu(self, event):
- """!Popup menu for profile and text options
- """
- popt = wx.Menu()
-
- for title, handler in ((_('Profile text settings'), self.PText),
- (_('Profile plot settings'), self.POptions)):
- item = wx.MenuItem(popt, wx.ID_ANY, title)
- popt.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(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 OnPText(self, dlg):
- """!Use user's provided profile text settings.
- """
- 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.profile:
- self.profile.setTitle(dlg.ptitle)
- self.profile.setXLabel(dlg.xlabel)
- self.profile.setYLabel(dlg.ylabel)
-
- self.OnRedraw(event = None)
-
- def PText(self, event):
- """!Set custom text values for profile title and axis labels.
- """
- dlg = TextDialog(parent = self, id = wx.ID_ANY, title = _('Profile text settings'))
-
- if dlg.ShowModal() == wx.ID_OK:
- self.OnPText(dlg)
-
- dlg.Destroy()
-
- def POptions(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, title = _('Profile 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
- """
- 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 profile window and clean up
- """
- 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.SetCursor(self.Parent.cursors["default"])
-
- self.mapwin.UpdateMap(render = False, renderVector = False)
-
- self.Destroy()
-
-class SetRasterDialog(wx.Dialog):
- def __init__(self, parent, id = wx.ID_ANY, title = _("Select raster map 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.coordstr = self.parent.coordstr
-
- # if self.coordstr == '':
- # 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()
- # self.Close(True)
- # return
-
- self.raster = { 0 : { 'name' : self.parent.raster[0]['name'],
- 'id' : None },
- 1 : { 'name' : self.parent.raster[1]['name'],
- 'id' : None },
- 2 : { 'name' : self.parent.raster[2]['name'],
- 'id' : None }
- }
-
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- box = wx.GridBagSizer (hgap = 3, vgap = 3)
-
- i = 0
- for txt in [_("Select raster map 1 (required):"),
- _("Select raster map 2 (optional):"),
- _("Select raster map 3 (optional):")]:
- label = wx.StaticText(parent = self, id = wx.ID_ANY, label = txt)
- box.Add(item = label,
- flag = wx.ALIGN_CENTER_VERTICAL, pos = (i, 0))
-
- selection = Select(self, id = wx.ID_ANY,
- size = globalvar.DIALOG_GSELECT_SIZE,
- type = 'cell')
- selection.SetValue(str(self.raster[i]['name']))
- self.raster[i]['id'] = selection.GetChildren()[0].GetId()
- selection.Bind(wx.EVT_TEXT, self.OnSelection)
-
- box.Add(item = selection, pos = (i, 1))
-
- i += 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):
- id = event.GetId()
- for r in self.raster.itervalues():
- if r['id'] == id:
- r['name'] = event.GetString()
- break
-
-class TextDialog(wx.Dialog):
- def __init__(self, parent, id, title,
- style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
- """!Dialog to set profile 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()
-
- # bindigs
- 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['profile'] = UserSettings.Get(group = 'profile')
- file = UserSettings.SaveToFile(fileSettings)
- self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
- self.EndModal(wx.ID_OK)
-
- def OnApply(self, event):
- """!Button 'Apply' pressed"""
- self.UpdateSettings()
- self.parent.OnPText(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,
- style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
- """!Dialog to set various profile options, 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.pstyledict = parent.pstyledict
- self.ptfilldict = parent.ptfilldict
-
- 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.properties = self.parent.properties
-
- self._do_layout()
-
- def _do_layout(self):
- """!Do layout"""
- # dialog layout
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- #
- # profile line settings
- #
- box = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = " %s " % _("Profile line settings"))
- boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
- idx = 1
- self.wxId['pcolor'] = []
- self.wxId['pwidth'] = []
- self.wxId['pstyle'] = []
- self.wxId['plegend'] = []
- for r in self.raster.itervalues():
- box = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = " %s %d " % (_("Profile"), idx))
- boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
-
- gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
- row = 0
- label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line color"))
- gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
- pcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = r['prop']['pcolor'])
- self.wxId['pcolor'].append(pcolor.GetId())
- gridSizer.Add(item = pcolor, 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))
- pwidth = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
- size = (50,-1), style = wx.SP_ARROW_KEYS)
- pwidth.SetRange(1, 10)
- pwidth.SetValue(r['prop']['pwidth'])
- self.wxId['pwidth'].append(pwidth.GetId())
- gridSizer.Add(item = pwidth, 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))
- pstyle = wx.ComboBox(parent = self, id = wx.ID_ANY,
- size = (120, -1), choices = self.pstyledict.keys(), style = wx.CB_DROPDOWN)
- pstyle.SetStringSelection(r['prop']['pstyle'])
- self.wxId['pstyle'].append(pstyle.GetId())
- gridSizer.Add(item = pstyle, 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))
- plegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
- plegend.SetValue(r['plegend'])
- gridSizer.Add(item = plegend, pos = (row, 1))
- self.wxId['plegend'].append(plegend.GetId())
- boxSizer.Add(item = gridSizer)
-
- if idx == 0:
- flag = wx.ALL
- else:
- flag = wx.TOP | wx.BOTTOM | wx.RIGHT
- boxMainSizer.Add(item = boxSizer, flag = flag, border = 3)
-
- idx += 1
-
- sizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
-
- middleSizer = wx.BoxSizer(wx.HORIZONTAL)
-
- #
- # segment marker settings
- #
- box = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = " %s " % _("Transect segment marker settings"))
- boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
- self.wxId['marker'] = {}
- 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))
-
- boxMainSizer.Add(item = gridSizer, flag = wx.ALL, border = 3)
- middleSizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
-
- #
- # axis options
- #
- box = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = " %s " % _("Axis settings"))
- boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
-
- self.wxId['x-axis'] = {}
- self.wxId['y-axis'] = {}
- 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.ComboBox(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
- #
- 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()
-
- # bindigs
- 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)"))
- btnSave.SetDefault()
- btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
- 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)
-
- self.SetSizer(sizer)
- sizer.Fit(self)
-
- def UpdateSettings(self):
- idx = 0
- for r in self.raster.itervalues():
- r['prop']['pcolor'] = self.FindWindowById(self.wxId['pcolor'][idx]).GetColour()
- r['prop']['pwidth'] = int(self.FindWindowById(self.wxId['pwidth'][idx]).GetValue())
- r['prop']['pstyle'] = self.FindWindowById(self.wxId['pstyle'][idx]).GetStringSelection()
- r['plegend'] = self.FindWindowById(self.wxId['plegend'][idx]).GetValue()
- idx +=1
-
- 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()
-
- for axis in ('x-axis', 'y-axis'):
- self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetValue()
- 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()
-
- 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.UpdateSettings()
- fileSettings = {}
- UserSettings.ReadSettingsFile(settings = fileSettings)
- fileSettings['profile'] = UserSettings.Get(group = 'profile')
- file = UserSettings.SaveToFile(fileSettings)
- self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
- self.parent.SetGraphStyle()
- if self.parent.profile:
- self.parent.DrawPlot()
- self.Close()
-
- def OnApply(self, event):
- """!Button 'Apply' pressed. Does not close dialog"""
- self.UpdateSettings()
- self.parent.SetGraphStyle()
- if self.parent.profile:
- self.parent.DrawPlot()
-
- def OnCancel(self, event):
- """!Button 'Cancel' pressed"""
- self.Close()
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1159 +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', 'v.type'):
- cmd = cmd + '_wrapper'
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/psmap.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1713 +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 <anna.kratochvilova fsv.cvut.cz> (bachelor's project)
- at author Martin Landa <landa.martin gmail.com> (mentor)
-"""
-
-import os
-import sys
-import textwrap
-import Queue
-try:
- import Image
- haveImage = True
-except ImportError:
- haveImage = 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 (experimental prototype)"), **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),
- '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)),
- '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 haveImage:
- 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 haveImage 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 = Image.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)
- # 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 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'):
- 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)
-
- 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
- resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
- resol = grass.parse_key_val(resol, val_type = float)
- RunCommand('g.region', nsres = resol['nsres'], ewres = resol['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']:
- 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']:
- 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.itemLabels = { 'map': ['MAP FRAME'],
- 'rasterLegend': ['RASTER LEGEND'],
- 'vectorLegend': ['VECTOR LEGEND'],
- 'mapinfo': ['MAP INFO'],
- 'scalebar': ['SCALE BAR']}
-
- # 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
-
- texts = self.instruction.FindInstructionByType('text', list = True)
- for text in texts:
- e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
- y = self.instruction[text.id]['where'][1], paperToMap = True)
- self.instruction[text.id]['east'], self.instruction[text.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,
- '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),
- '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'):
- 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]
- 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)
- 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 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[self.instruction[drawid].type])
- 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 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]
-
- self.itemLabels['map'] = self.itemLabels['map'][0:1]
- self.itemLabels['map'].append("raster: " + rasterName)
- if vectorId:
- for map in self.instruction[vectorId]['list']:
- self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/psmap_dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap_dialogs.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap_dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,5699 +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
- - Scalebar
- - RasterLegend
- - VectorLegend
- - Raster
- - Vector
- - VProperties
- - PsmapDialog
- - PageSetupDialog
- - MapDialog
- - MapFramePanel
- - RasterPanel
- - VectorPanel
- - RasterDialog
- - MainVectorDialog
- - VPropertiesDialog
- - LegendDialog
- - MapinfoDialog
- - ScalebarDialog
- - TextDialog
-
-(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 <anna.kratochvilova fsv.cvut.cz> (bachelor's project)
- at author Martin Landa <landa.martin gmail.com> (mentor)
-"""
-
-
-import os
-import sys
-import string
-from math import ceil, floor
-from copy import deepcopy
-from time import strftime, localtime
-
-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 == 'text':
- 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 '):
- 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('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'],
- 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,
- rasterLegend = RasterLegend,
- vectorLegend = VectorLegend,
- vector = Vector,
- vProperties = VProperties
- )
-
- myInstruction = psmapInstrDict[instruction]
-
- for i in myInstruction:
- instr = self.FindInstructionByType(i)
- if i in ('text', 'vProperties') or not instr:
-
- id = wx.NewId() #!vProperties expect subtype
- if i == 'vProperties':
- id = kwargs['id']
- newInstr = myInstrDict[i](id, subType = instruction[1:])
- 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 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 = (50, -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):
- 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 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
- map = self.instruction.FindInstructionByType('map')
- if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
- self.rasterDict['isRaster'] = False
- self.rasterDict['raster'] = None
- map['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'] != map['drawMap']:
- map['drawMap'] = False
-
- if self.id not in self.instruction:
- raster = Raster(self.id)
- self.instruction.AddInstruction(raster)
- self.instruction[self.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)
-
- #Position
- 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)
-
- self.positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
- self.paperPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
- self.mapPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
- self.paperPositionCtrl.SetValue(self.textDict['XY'])
- self.mapPositionCtrl.SetValue(not self.textDict['XY'])
-
- gridBagSizer.Add(self.positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
- gridBagSizer.Add(self.paperPositionCtrl, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
- gridBagSizer.Add(self.mapPositionCtrl, 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 = self.textDict)
- panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
- self.AddUnits(parent = panel, dialogDict = self.textDict)
- 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)
-
- self.eastingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
- self.northingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
- self.eastingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
- self.northingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
- east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
- self.eastingCtrl.SetValue(str(east))
- self.northingCtrl.SetValue(str(north))
-
- self.gridBagSizerM.Add(self.eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
- self.gridBagSizerM.Add(self.northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
- self.gridBagSizerM.Add(self.eastingCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
- self.gridBagSizerM.Add(self.northingCtrl, 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)
-
- #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, self.paperPositionCtrl)
- self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.mapPositionCtrl)
- 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.paperPositionCtrl.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.paperPositionCtrl.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.eastingCtrl.GetValue():
- self.textDict['east'] = self.eastingCtrl.GetValue()
- else:
- self.textDict['east'] = self.textDict['east']
-
- if self.northingCtrl.GetValue():
- self.textDict['north'] = self.northingCtrl.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.eastingCtrl.SetValue(str(self.textDict['east']))
- self.northingCtrl.SetValue(str(self.textDict['north']))
-
-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
-
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/render.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/render.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/render.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1324 +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
-
-try:
- import subprocess
-except:
- compatPath = os.path.join(globalvar.ETCWXDIR, "compat")
- sys.path.append(compatPath)
- import subprocess
-import tempfile
-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 g.pnmcomp for creating image composition or
-# wxPython functionality
-#
-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):
- """!
- @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
- self.gtemp = tempfile.mkstemp()[1]
- self.maskfile = self.gtemp + ".pgm"
- if self.type == 'overlay':
- self.mapfile = self.gtemp + ".png"
- else:
- self.mapfile = self.gtemp + ".ppm"
-
- 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
- """
- 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',
- '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 UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
-# os.environ["GRASS_CAIROFILE"] = self.mapfile
-# if 'cairo' not in gcmd.RunCommand('d.mon',
-# flags='p',
-# read = True):
-# gcmd.RunCommand('d.mon',
-# start = 'cairo')
- if not self.mapfile:
- self.gtemp = tempfile.mkstemp()[1]
- self.maskfile = self.gtemp + ".pgm"
- if self.type == 'overlay':
- self.mapfile = self.gtemp + ".png"
- else:
- self.mapfile = self.gtemp + ".ppm"
-
- if self.mapfile:
- os.environ["GRASS_CAIROFILE"] = self.mapfile
- else:
- if not self.mapfile:
- self.gtemp = tempfile.mkstemp()[1]
- self.maskfile = self.gtemp + ".pgm"
- if self.type == 'overlay':
- self.mapfile = self.gtemp + ".png"
- else:
- self.mapfile = self.gtemp + ".ppm"
-
- 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
- try:
- os.remove(self.mapfile)
- os.remove(self.maskfile)
- os.remove(self.gtemp)
- except (OSError, TypeError):
- pass
- self.mapfile = None
- self.maskfile = None
-
- # stop monitor
- if UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
-# gcmd.RunCommand('d.mon',
-# stop = 'cairo')
- del os.environ["GRASS_CAIROFILE"]
- elif "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',
- '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):
- """!Map composition (stack of map layers and overlays)
- """
- def __init__(self, gisrc = None):
- # 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
- # environment variables, like MAPSET, LOCATION_NAME, etc.
- self.env = dict()
- # path to external gisrc
- self.gisrc = gisrc
-
- # generated file for g.pnmcomp output for rendering the map
- self.mapfile = tempfile.mkstemp(suffix = '.ppm')[1]
-
- # setting some initial env. variables
- self._initGisEnv() # g.gisenv
- self.GetWindow()
- # GRASS environment variable (for rendering)
- os.environ["GRASS_TRANSPARENT"] = "TRUE"
- os.environ["GRASS_BACKGROUNDCOLOR"] = "ffffff"
-
- # 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 ChangeMapSize(self, (width, height)):
- """!Change size of rendered map.
-
- @param width,height map size
-
- @return True on success
- @return False on failure
- """
- try:
- self.width = int(width)
- self.height = int(height)
- Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
- (self.width, self.height))
- return True
- except:
- self.width = 640
- self.height = 480
- return False
-
- 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, mapWindow, maps, masks, opacities):
- # render map layers
- ilayer = 1
- for layer in self.layers + self.overlays:
- # skip dead or disabled map layers
- if layer == None or layer.active == False:
- continue
-
- # render if there is no mapfile
- if force or \
- layer.force_render or \
- layer.mapfile == None or \
- (not os.path.isfile(layer.mapfile) or not os.path.getsize(layer.mapfile)):
- 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
-
- 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
- """
- maps = []
- masks = []
- opacities = []
-
- 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)
- if UserSettings.Get(group='display', key='driver', subkey='type') == 'cairo':
- os.environ["GRASS_AUTO_WRITE"] = "TRUE"
- if "GRASS_RENDER_IMMEDIATE" in os.environ:
- del os.environ["GRASS_RENDER_IMMEDIATE"]
- os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
- else:
- os.environ["GRASS_PNG_AUTO_WRITE"] = "TRUE"
- os.environ["GRASS_PNG_READ"] = "FALSE"
- os.environ["GRASS_COMPRESSION"] = "0"
- os.environ["GRASS_TRUECOLOR"] = "TRUE"
- os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
-
- self._renderLayers(force, mapWindow, maps, masks, opacities)
-
- # ugly hack for MSYS
- if not subprocess.mswindows:
- 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('\\', '/')
-
- # compose command
- bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
- subkey = 'color')))
-
- # render overlays
- if tmp_region:
- os.environ["GRASS_REGION"] = tmp_region
- else:
- del os.environ["GRASS_REGION"]
-
- if maps:
- # run g.pngcomp to get composite image
- ret, msg = gcmd.RunCommand('g.pnmcomp',
- getErrorMsg = True,
- input = '%s' % ",".join(maps),
- mask = '%s' % ",".join(masks),
- opacity = '%s' % ",".join(opacities),
- background = 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 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 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):
- """!Clean layer stack - go trough all layers and remove them
- from layer list.
-
- Removes also l_mapfile and l_maskfile
-
- @return False on failure
- @return True on success
- """
- try:
- dir = os.path.dirname(self.mapfile)
- base = os.path.basename(self.mapfile).split('.')[0]
- removepath = os.path.join(dir,base)+r'*'
- for f in glob.glob(removepath):
- os.remove(f)
- for layer in self.layers:
- if layer.mapfile:
- dir = os.path.dirname(layer.mapfile)
- base = os.path.basename(layer.mapfile).split('.')[0]
- removepath = os.path.join(dir,base)+r'*'
- for f in glob.glob(removepath):
- os.remove(f)
- self.layers.remove(layer)
-
- for overlay in self.overlays:
- if overlay.mapfile:
- dir = os.path.dirname(overlay.mapfile)
- base = os.path.basename(overlay.mapfile).split('.')[0]
- removepath = os.path.join(dir,base)+r'*'
- for f in glob.glob(removepath):
- os.remove(f)
- self.overlays.remove(overlay)
- except:
- return False
-
- return True
-
- 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/branches/develbranch_6/gui/wxpython/gui_modules/sqlbuilder.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/sqlbuilder.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/sqlbuilder.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/states.txt
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/states.txt 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/states.txt 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1589 +0,0 @@
-"""!
- at package toolbar
-
- at brief wxGUI toolbar widgets
-
-Classes:
- - AbstractToolbar
- - MapToolbar
- - GCPMapToolbar
- - GCPDisplayToolbar
- - VDigitToolbar
- - ProfileToolbar
- - LMNvizToolbar
- - ModelToolbar
- - HistogramToolbar
- - 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
-import gcmd
-import gdialogs
-from vdigit import VDigitSettingsDialog, haveVDigit, VDigit
-from debug import Debug
-from preferences import globalSettings as UserSettings
-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 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 _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))
- )
-
- def OnZoomMap(self, event):
- """!Zoom to selected map"""
- self.parent.MapWindow.ZoomToMap(layers = self.mapcontent.GetListOfLayers())
- if event:
- event.Skip()
-
-class VDigitToolbar(AbstractToolbar):
- """!Toolbar for digitization
- """
- def __init__(self, parent, mapcontent, layerTree = None, log = None):
- self.mapcontent = mapcontent # Map class instance
- self.layerTree = layerTree # reference to layer tree associated to map display
- self.log = log # log area
- 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 = None
-
- # 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.
- self.combo.Hide()
- self.combo.Show()
-
- # disable undo/redo
- 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']
- return self._getToolbarData(((None, ),
- ("addPoint", icons["addPoint"],
- self.OnAddPoint,
- wx.ITEM_CHECK),
- ("addLine", icons["addLine"],
- self.OnAddLine,
- wx.ITEM_CHECK),
- ("addBoundary", icons["addBoundary"],
- self.OnAddBoundary,
- wx.ITEM_CHECK),
- ("addCentroid", icons["addCentroid"],
- self.OnAddCentroid,
- wx.ITEM_CHECK),
- ("addArea", icons["addArea"],
- self.OnAddArea,
- wx.ITEM_CHECK),
- ("moveVertex", icons["moveVertex"],
- self.OnMoveVertex,
- wx.ITEM_CHECK),
- ("addVertex", icons["addVertex"],
- self.OnAddVertex,
- wx.ITEM_CHECK),
- ("removeVertex", icons["removeVertex"],
- self.OnRemoveVertex,
- wx.ITEM_CHECK),
- ("editLine", icons["editLine"],
- self.OnEditLine,
- wx.ITEM_CHECK),
- ("moveLine", icons["moveLine"],
- self.OnMoveLine,
- wx.ITEM_CHECK),
- ("deleteLine", icons["deleteLine"],
- self.OnDeleteLine,
- wx.ITEM_CHECK),
- ("displayCats", icons["displayCats"],
- self.OnDisplayCats,
- wx.ITEM_CHECK),
- ("displayAttr", icons["displayAttr"],
- self.OnDisplayAttr,
- wx.ITEM_CHECK),
- ("additionalTools", icons["additionalTools"],
- self.OnAdditionalToolMenu,
- wx.ITEM_CHECK),
- (None, ),
- ("undo", icons["undo"],
- self.OnUndo),
- ("settings", icons["settings"],
- self.OnSettings),
- ("quit", icons["quit"],
- self.OnExit))
- )
-
- def OnTool(self, event):
- """!Tool selected -> disable selected tool in map toolbar"""
- aId = self.parent.toolbars['map'].GetAction(type = 'id')
- self.parent.toolbars['map'].ToggleTool(aId, False)
-
- # set cursor
- cursor = self.parent.cursors["cross"]
- self.parent.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.parent.MapWindow.ClearLines(pdc = self.parent.MapWindow.pdcTmp)
- if self.digit and \
- len(self.parent.MapWindow.digit.GetDisplay().GetSelected()) > 0:
- # cancel action
- self.parent.MapWindow.OnMiddleDown(None)
-
- # set focus
- self.parent.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.parent.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.parent.MapWindow.mouse['box'] = 'line'
- ### self.parent.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.parent.MapWindow.polycoords = [] # reset temp line
- self.action = { 'desc' : "addLine",
- 'type' : "boundary",
- 'id' : self.addBoundary }
- self.parent.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.parent.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.parent.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.parent.MapWindow.mouse['use'] = "pointer"
- self.parent.MapWindow.mouse['box'] = "point"
- self.parent.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.parent.MapWindow.mouse['box'] = 'point'
-
- def OnAddVertex(self, event):
- """!Add line vertex"""
- Debug.msg(2, "Digittoolbar.OnAddVertex():")
- self.action = { 'desc' : "addVertex",
- 'id' : self.addVertex }
- self.parent.MapWindow.mouse['box'] = 'point'
-
- def OnRemoveVertex(self, event):
- """!Remove line vertex"""
- Debug.msg(2, "Digittoolbar.OnRemoveVertex():")
- self.action = { 'desc' : "removeVertex",
- 'id' : self.removeVertex }
- self.parent.MapWindow.mouse['box'] = 'point'
-
- def OnEditLine(self, event):
- """!Edit line"""
- Debug.msg(2, "Digittoolbar.OnEditLine():")
- self.action = { 'desc' : "editLine",
- 'id' : self.editLine }
- self.parent.MapWindow.mouse['box'] = 'line'
-
- def OnMoveLine(self, event):
- """!Move line"""
- Debug.msg(2, "Digittoolbar.OnMoveLine():")
- self.action = { 'desc' : "moveLine",
- 'id' : self.moveLine }
- self.parent.MapWindow.mouse['box'] = 'box'
-
- def OnDeleteLine(self, event):
- """!Delete line"""
- Debug.msg(2, "Digittoolbar.OnDeleteLine():")
- self.action = { 'desc' : "deleteLine",
- 'id' : self.deleteLine }
- self.parent.MapWindow.mouse['box'] = 'box'
-
- def OnDisplayCats(self, event):
- """!Display/update categories"""
- Debug.msg(2, "Digittoolbar.OnDisplayCats():")
- self.action = { 'desc' : "displayCats",
- 'id' : self.displayCats }
- self.parent.MapWindow.mouse['box'] = 'point'
-
- def OnDisplayAttr(self, event):
- """!Display/update attributes"""
- Debug.msg(2, "Digittoolbar.OnDisplayAttr():")
- self.action = { 'desc' : "displayAttrs",
- 'id' : self.displayAttr }
- self.parent.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.parent.MapWindow.digit = VDigit(mapwindow = self.parent.MapWindow)
- except SystemExit:
- self.digit = self.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.MapWindow.mouse['box'] = 'box'
-
- def OnZBulk(self, event):
- """!Z bulk-labeling selected lines/boundaries"""
- if not self.digit.IsVector3D():
- gcmd.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.parent.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.parent.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 = gdialogs.CreateNewVector(self.parent,
- exceptMap = openVectorMap, log = self.log,
- cmd = (('v.edit',
- { '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.mapcontent.ChangeLayerActive(mapLayer, False)
-
- # clean map canvas
- self.parent.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.parent.MapWindow.pdcVector = wx.PseudoDC()
- self.digit = self.parent.MapWindow.digit = VDigit(mapwindow = self.parent.MapWindow)
-
- self.mapLayer = mapLayer
-
- # open vector map
- if self.digit.OpenMap(mapLayer.GetName()) is None:
- self.mapLayer = None
- self.StopEditing()
- return False
-
- # update toolbar
- self.combo.SetValue(mapLayer.GetName())
- self.parent.toolbars['map'].combo.SetValue (_('Digitize'))
- 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.parent.MapWindow.mouse['use'] == 'pointer':
- self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
-
- if not self.parent.MapWindow.resize:
- self.parent.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
- """
- 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.mapcontent.ChangeLayerActive(self.mapLayer, True)
-
- # change cursor
- self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
- self.parent.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.parent.MapWindow.digit
-
- self.mapLayer = None
-
- self.parent.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.mapcontent.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:
- 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['profile']
- 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, ),
- ('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.ProfileOptionsMenu),
- ('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:
- gcmd.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 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 haveImage
- if not haveImage:
- 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/branches/develbranch_6/gui/wxpython/gui_modules/units.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/units.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/units.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/utils.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/utils.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/utils.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,767 +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 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'
- elif 'labels=' in dcmd[0]:
- mapname = dcmd[idx].split('=')[1] + ' labels'
- 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',
- '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:
- dcmd[i] = p + '=' + v
- else:
- dcmd[i] = v
- if mapset:
- dcmd[i] += '@' + mapset
-
- maps = list()
- for i, p, v in params:
- if not p:
- maps.append(v)
- else:
- 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(vector, parent = None):
- """!Get list of vector layers
-
- @param vector name of vector map
- @param parent parent window (to show dialog) or None
- """
- layers = []
- 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
-
- Debug.msg(1, "GetVectorNumberOfLayers(): ret %s" % ret)
-
- for line in out.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)
- 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)
- """
- if not projIn:
- projIn = gcmd.RunCommand('g.proj',
- flags = 'jf',
- read = True)
- coors = gcmd.RunCommand('m.proj',
- flags = flags,
- proj_in = projIn,
- proj_out = projOut,
- stdin = '%f|%f' % (coord[0], coord[1]),
- read = True)
- if coors:
- coors = coors.split('\t')
- e = coors[0]
- n = coors[1].split(' ')[0].strip()
- 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)
-
-def _getOGRFormats():
- """!Get dictionary of avaialble OGR drivers"""
- ret = grass.read_command('v.in.ogr',
- quiet = True,
- flags = 'f')
-
- return _parseFormats(ret)
-
-def _parseFormats(output):
- """!Parse r.in.gdal/v.in.ogr -f output"""
- formats = { 'file' : list(),
- 'database' : list(),
- 'protocol' : list()
- }
-
- if not output:
- return formats
-
- for line in output.splitlines():
- format = line.strip().rsplit(':', -1)[1].strip()
- if format in ('Memory', 'Virtual Raster', 'In Memory Raster'):
- continue
- if format in ('PostgreSQL', 'SQLite',
- 'ODBC', 'ESRI Personal GeoDatabase',
- 'Rasterlite',
- 'PostGIS WKT Raster driver'):
- formats['database'].append(format)
- elif format in ('GeoJSON',
- 'OGC Web Coverage Service',
- 'OGC Web Map Service',
- 'HTTP Fetching Wrapper'):
- formats['protocol'].append(format)
- else:
- formats['file'].append(format)
-
- for items in formats.itervalues():
- items.sort()
-
- return formats
-
-formats = None
-
-def GetFormats():
- """!Get GDAL/OGR formats"""
- global formats
- if not formats:
- formats = {
- 'gdal' : _getGDALFormats(),
- 'ogr' : _getOGRFormats()
- }
-
- return formats
-
-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/init.sh and init.bat
- 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/branches/develbranch_6/gui/wxpython/gui_modules/vclean.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/vclean.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/vclean.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,563 +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 OnDone(self, cmd, returncode):
- """!Command done"""
- self.SetStatusText('')
-
- def OnCleaningRun(self, event):
- """!Builds options and runs v.clean
- """
- self.GetCmdStrings()
-
- err = list()
- for p, name in ((self.inmap, _('Name of input vector map')),
- (self.outmap, _('Name for output vector map')),
- (self.tools_string, _('Tools')),
- (self.thresh_string, _('Threshold'))):
- if not p:
- err.append(_("'%s' not defined") % name)
- if err:
- gcmd.GError(_("Some parameters not defined. Operation "
- "cancelled.\n\n%s") % '\n'.join(err),
- parent = self)
- return
-
- self.SetStatusText(_("Executing selected cleaning operations..."))
- snum = len(self.toolslines.keys())
-
- 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, onDone = self.OnDone)
- 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/branches/develbranch_6/gui/wxpython/gui_modules/vdigit.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/vdigit.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/vdigit.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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/branches/develbranch_6/gui/wxpython/gui_modules/workspace.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/workspace.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/workspace.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1583 +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('<', '<')
- value = value.replace('>', '>')
-
- 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)
- lname = item.get('name', None)
- if lname and '\\n' in lname:
- lname = lname.replace('\\n', os.linesep)
-
- self.layers.append( {
- "type" : item.get('type', None),
- "name" : lname,
- "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'])
-
- # 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'])
-
- 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', float)
- 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']) }
- if 'object' in data:
- for attrb in ('color', 'width', 'mode', 'height'):
- 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']) }
-
- if 'object' in data:
- for attrb in ('size', 'width', 'marker', 'color', 'height'):
- 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('<', '<')
- value = value.replace('>', '>')
-
- 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).replace(os.linesep, '\\n')
- 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)))
- 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>%.2f</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>%.2f</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/branches/develbranch_6/gui/wxpython/gui_modules/wxnviz.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/wxnviz.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/wxnviz.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,2034 +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.g3d import *
- from grass.lib.vector import *
- from grass.lib.ogsf import *
- from grass.lib.nviz 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_cell2(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_cell2(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_grid3(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_grid3(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_vectmode(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_sitemode(id, ST_ATT_NONE, 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 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/branches/develbranch_6/gui/wxpython/gui_modules/wxvdigit.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdigit.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdigit.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,1740 +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
-
-(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
-
-from grass.lib.gis import *
-from grass.lib.vector import *
-from grass.lib.vedit import *
-from grass.lib.dbmi import *
-
-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.'),
- 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_list()
- 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.value[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_list(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)
-
- name, mapset = name.split('@')
-
- 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
-
- Debug.msg(3, "IVDigit._addFeature(): area - left=%d right=%d",
- left, right)
-
- # 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, right, 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
-
Deleted: grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdriver.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdriver.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdriver.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,995 +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
-
-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 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)
-
- 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
-
- 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
-
- 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'])
-
-
Copied: grass/branches/develbranch_6/gui/wxpython/lmgr/layertree.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/layertree.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/lmgr/layertree.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/lmgr/layertree.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1542 @@
+"""!
+ at package lmgr.layertree
+
+ at brief Utility classes for map layer management.
+
+Classes:
+ - lmgr::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 SetOpacityDialog
+from gui_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 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.MapWindow2D.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'):
+ 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'])
+
+ 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 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(self.mapdisplay,
+ id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
+ style = wx.DEFAULT_FRAME_STYLE, 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).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():
+ GError(parent = self,
+ message = _("Unable to display histogram of "
+ "raster map. No map name defined."))
+ return
+
+ histogramFrame = HistogramFrame(parent = self,
+ id = wx.ID_ANY,
+ pos = wx.DefaultPosition, size = globalvar.HIST_WINDOW_SIZE,
+ style = wx.DEFAULT_FRAME_STYLE)
+ histogramFrame.Show()
+ histogramFrame.SetHistLayer(mapLayer.GetName())
+ histogramFrame.HistWindow.UpdateHist()
+ histogramFrame.Refresh()
+ histogramFrame.Update()
+
+ def OnUnivariateStats(self, event):
+ """!Univariate raster statistics"""
+ name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+ self.lmgr.goutput.RunCmd(['r.univar', 'map=%s' % name], switchPage = True)
+
+ 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 self.mapdisplay.GetToolbar('vdigit'): # enable tool
+ self.mapdisplay.AddToolbar('vdigit')
+
+ if not self.mapdisplay.toolbars['vdigit']:
+ return
+
+ 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"""
+ item = self.layer_selected
+ self.GetPyData(item)[0]['label'] = event.GetLabel()
+ self.SetItemText(item, self._getLayerName(item)) # not working, why?
+
+ 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 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))
+
+ # updated progress bar range (mapwindow statusbar)
+ if checked is True:
+ 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)
+
+ cmd = None
+ 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='rasterOverlay', subkey='enabled'):
+ cmd.append('-o')
+
+ elif ltype == '3d-raster':
+ cmd = ['d.rast3d']
+
+ elif ltype == 'rgb':
+ cmd = ['d.rgb']
+ if UserSettings.Get(group='cmd', key='rasterOverlay', subkey='enabled'):
+ cmd.append('-o')
+
+ elif ltype == 'his':
+ cmd = ['d.his']
+
+ elif ltype == 'shaded':
+ cmd = ['d.shadedmap']
+
+ elif ltype == 'rastarrow':
+ cmd = ['d.rast.arrow']
+
+ elif ltype == 'rastnum':
+ cmd = ['d.rast.num']
+
+ 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)
+
+ cmd = ['d.vect', 'type=%s' % ','.join(types)]
+
+ elif ltype == 'thememap':
+ # -s flag requested, otherwise only first thematic category is displayed
+ # should be fixed by C-based d.thematic.* modules
+ cmd = ['d.vect.thematic', '-s']
+
+ elif ltype == 'themechart':
+ cmd = ['d.vect.chart']
+
+ elif ltype == 'grid':
+ cmd = ['d.grid']
+
+ elif ltype == 'geodesic':
+ cmd = ['d.geodesic']
+
+ elif ltype == 'rhumb':
+ cmd = ['d.rhumbline']
+
+ elif ltype == 'labels':
+ cmd = ['d.labels']
+
+ if cmd:
+ GUI(parent = self, centreOnParent = False).ParseCommand(cmd,
+ completed = (self.GetOptData,layer,params))
+
+ 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:
+ # 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.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 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 propertiesdialog 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', '3d-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])
+
+ @return item instance
+ @return None not found
+ """
+ item = self.GetFirstChild(self.root)[0]
+ 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 FindItemByValue"""
+ 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
Added: grass/branches/develbranch_6/gui/wxpython/lmgr/menudata.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/lmgr/menudata.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/lmgr/menudata.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,70 @@
+"""!
+ at package lmrg.menudata
+
+ at brief Complex list for menu entries for wxGUI
+
+Classes:
+ - menudata::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')
+ 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
Copied: grass/branches/develbranch_6/gui/wxpython/lmgr/pyshell.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/gpyshell.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/lmgr/pyshell.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/lmgr/pyshell.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,112 @@
+"""!
+ at package lmgr.pyshell
+
+ at brief wxGUI Interactive Python Shell for Layer Manager
+
+Classes:
+ - pyshell::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/branches/develbranch_6/gui/wxpython/lmgr/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/lmgr/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/lmgr/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,211 @@
+"""!
+ at package lmgr.toolbars
+
+ at brief wxGUI Layer Manager - toolbars
+
+Classes:
+ - toolbars::LMWorkspaceToolbar
+ - toolbars::LMDataToolbar
+ - toolbars::LMToolsToolbar
+ - toolbars::LMMiscToolbar
+ - toolbars::LMVectorToolbar
+ - toolbars::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()
Added: grass/branches/develbranch_6/gui/wxpython/location_wizard/base.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/location_wizard/base.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/location_wizard/base.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,45 @@
+"""!
+ at package location_wizard.base
+
+ at brief Location wizard - base classes
+
+Classes:
+ - base::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)
Added: grass/branches/develbranch_6/gui/wxpython/location_wizard/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/location_wizard/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/location_wizard/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,613 @@
+"""!
+ at package location_wizard.dialogs
+
+ at brief Location wizard - dialogs
+
+Classes:
+ - dialogs::RegionDef
+ - dialogs::TransList
+ - dialogs::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
Copied: grass/branches/develbranch_6/gui/wxpython/location_wizard/wizard.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/location_wizard.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/location_wizard/wizard.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/location_wizard/wizard.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2050 @@
+"""!
+ at package location_wizard.wizard
+
+ at brief Location wizard - creates a new GRASS Location. User can choose
+from multiple methods.
+
+Classes:
+ - wizard::TitledPage
+ - wizard::DatabasePage
+ - wizard::CoordinateSystemPage
+ - wizard::ProjectionsPage
+ - wizard::ItemList
+ - wizard::ProjParamsPage
+ - wizard::DatumPage
+ - wizard::EllipsePage
+ - wizard::GeoreferencedFilePage
+ - wizard::WKTPage
+ - wizard::EPSGPage
+ - wizard::CustomPage
+ - wizard::SummaryPage
+ - wizard::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/branches/develbranch_6/gui/wxpython/mapdisp/frame.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/frame.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1342 @@
+"""!
+ 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:
+ - mapdisp::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 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
+from vdigit.toolbars import VDigitToolbar
+from mapdisp.toolbars import MapToolbar
+from mapdisp.gprint import PrintOptions
+from core.gcmd import GError, GMessage, RunCommand
+from dbmgr.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.mapwindow import BufferedWindow
+from modules.histogram import HistogramFrame
+from wxplot.histogram import Histogram2Frame
+from wxplot.profile import ProfileFrame
+from nviz.main import haveNviz
+from nviz.mapwindow import GLWindow
+
+from mapdisp import statusbar as sb
+
+from grass.script import core as grass
+
+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, mapcontent = self.Map,
+ 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
+ """
+ # check for GLCanvas and OpenGL
+ if not 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 = 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'):
+ if self.MapWindow.digit:
+ 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.toolbars['map']:
+ 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('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.Profile, profile)
+
+ histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
+ histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
+ toolsmenu.AppendItem(histogram)
+ self.Bind(wx.EVT_MENU, self.Histogram, 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 Profile(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 Histogram(self, event):
+ """!Init histogram display canvas and tools
+ """
+ self.histogram = histogram.HistogramFrame(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,5'],
+ 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.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.
+ """
+ self.MapWindow.ZoomToMap()
+
+ 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 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']
Copied: grass/branches/develbranch_6/gui/wxpython/mapdisp/gprint.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/disp_print.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/gprint.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/gprint.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,289 @@
+"""!
+ at package mapdisp.gprint
+
+ at brief Print context and utility functions for printing
+contents of map display window.
+
+Classes:
+ - gprint::MapPrint
+ - gprint::PrintOptions
+
+(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)
+"""
+
+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:
+ 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()
+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()
Added: grass/branches/develbranch_6/gui/wxpython/mapdisp/main.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/main.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/main.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,142 @@
+"""!
+ at package mapdisp.main
+
+ at brief Start Map Display as standalone application
+
+Classes:
+ - mapdisp::MapApp
+
+Usage:
+python mapdisp/main.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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+from core import globalvar
+import wx
+
+from core.gcmd import RunCommand
+from core.render import Map
+from mapdisp.frame import MapFrame
+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)
+
+
+class MapApp(wx.App):
+ def OnInit(self):
+ wx.InitAllImageHandlers()
+ if __name__ == "__main__":
+ self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
+ self.Map = Map(cmdfile = monFile['cmd'], mapfile = monFile['map'],
+ envfile = monFile['env'], monitor = monName)
+ else:
+ self.Map = None
+
+ self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = self.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()))
+
+ gmMap = MapApp(0)
+ # set title
+ gmMap.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
+ monName +
+ " - Location: " + grass.gisenv()["LOCATION_NAME"]))
+
+ gmMap.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/branches/develbranch_6/gui/wxpython/mapdisp/mapwindow.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_window.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/mapwindow.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/mapwindow.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1683 @@
+"""!
+ at package mapdisp.mapwindow
+
+ 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 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 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 \
+ 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 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))
Copied: grass/branches/develbranch_6/gui/wxpython/mapdisp/statusbar.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_statusbar.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/statusbar.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/statusbar.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1059 @@
+"""!
+ at package mapdisp.statusbar
+
+ at brief Classes for statusbar management
+
+Classes:
+ - statusbar::SbException
+ - statusbar::SbManager
+ - statusbar::SbItem
+ - statusbar::SbRender
+ - statusbar::SbShowRegion
+ - statusbar::SbAlignExtent
+ - statusbar::SbResolution
+ - statusbar::SbMapScale
+ - statusbar::SbGoTo
+ - statusbar::SbProjection
+ - statusbar::SbMask
+ - statusbar::SbTextItem
+ - statusbar::SbDisplayGeometry
+ - statusbar::SbCoordinates
+ - statusbar::SbRegionExtent
+ - statusbar::SbCompRegionExtent
+ - statusbar::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/branches/develbranch_6/gui/wxpython/mapdisp/statusbar.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/develbranch_6/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/mapdisp/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/mapdisp/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,212 @@
+"""!
+ at package mapdisp.toolbars
+
+ at brief Map display frame - toolbars
+
+Classes:
+ - toolbars::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 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)
Copied: grass/branches/develbranch_6/gui/wxpython/modules/colorrules.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/colorrules.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/colorrules.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/colorrules.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1775 @@
+"""
+ at package module.colorrules
+
+ at brief Dialog for interactive management of raster/vector color tables
+and color rules.
+
+Classes:
+ - colorrules::RulesPanel
+ - colorrules::ColorTable
+ - colorrules::RasterColorTable
+ - colorrules::VectorColorTable
+ - colorrules::BufferedWindow
+
+(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 gui_core.forms import GUI
+from core.debug import Debug as Debug
+from core.settings import UserSettings
+
+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
+ """
+ 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 self.inmap and not self.CheckMapset():
+ # currently v.colors need the map to be in current mapset
+ if self.version7 and self.attributeType == 'color':
+ message = _("Selected map <%s> is not in current mapset <%s>. "
+ "Color rules cannot be edited.") % \
+ (self.inmap, grass.gisenv()['MAPSET'])
+ else:
+ 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.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))"""
+ # 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 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
+ old_colrtable = None
+ path = grass.find_file(name = self.inmap, element = 'vector')['file']
+
+ if os.path.exists(os.path.join(path, 'colr')):
+ old_colrtable = os.path.join(path, 'colr')
+ 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 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')
Added: grass/branches/develbranch_6/gui/wxpython/modules/extensions.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/extensions.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/extensions.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,368 @@
+"""!
+ at package modules.extensions
+
+ at brief GRASS Addons extensions management classes
+
+Classes:
+ - extensions::InstallExtensionWindow
+ - extensions::ExtensionTree
+
+(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 wx
+try:
+ import wx.lib.agw.customtreectrl as CT
+except ImportError:
+ import wx.lib.customtreectrl as CT
+import wx.lib.flatnotebook as FN
+
+import grass.script as grass
+from grass.script import task as gtask
+
+from core import globalvar
+from core.gcmd import GError, RunCommand
+from gui_core.forms import GUI
+from gui_core.widgets import ItemTree
+from gui_core.ghelp import SearchModuleWindow
+
+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.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.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.py')
+
+ 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'))
+
+ 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.py')
+
+ 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.py']
+
+ 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.py'] + 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',
+ '' : '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.py', read = True, parent = self,
+ 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 = ''
+ 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 = ''
+ name = line.strip()
+
+ if self._expandPrefix(prefix) == prefix:
+ prefix = ''
+
+ 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:
+ if prefix:
+ text = prefix + '.' + name
+ else:
+ text = name
+ new = self.AppendItem(parentId = item,
+ text = text)
+ 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
Copied: grass/branches/develbranch_6/gui/wxpython/modules/histogram.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/histogram.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/histogram.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/histogram.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,494 @@
+"""!
+ at package modules.histogram
+
+Plotting histogram based on d.histogram
+
+Classes:
+ - histogram::BufferedWindow
+ - histogram::HistogramFrame
+ - histogram::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 gui_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 HistogramFrame(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/branches/develbranch_6/gui/wxpython/modules/mcalc_builder.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/mcalc_builder.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/mcalc_builder.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/mcalc_builder.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,550 @@
+"""!
+ at package modules::mcalc_builder
+
+ at brief Map calculator, GUI wrapper for r.mapcalc
+
+Classes:
+ - mcalc_builder::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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+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.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_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.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_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.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)
+ 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('%s = %s' % (name, expr))]
+ self.log.RunCmd(cmd, onDone = self.OnDone)
+ self.parent.Raise()
+ else:
+ RunCommand(self.cmd,
+ "%s=%s" % (name, expr))
+
+ 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()
+
+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/branches/develbranch_6/gui/wxpython/modules/ogc_services.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/ogc_services.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/ogc_services.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/ogc_services.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,300 @@
+"""!
+ at package module.ogc_services
+
+ at brief Dialogs for OGC services
+
+Currently only implemeted WMS.
+
+List of classes:
+ - ogc_services::WMSDialog
+ - ogc_services::LayersList
+
+(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>
+"""
+
+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/branches/develbranch_6/gui/wxpython/modules/vclean.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/vclean.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/modules/vclean.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/modules/vclean.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,556 @@
+"""
+ at package modules.vclean
+
+ at brief Dialog for interactive construction of vector cleaning
+operations
+
+Classes:
+ - vclean::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, GError
+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, style = style, **kwargs)
+
+ 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 OnDone(self, cmd, returncode):
+ """!Command done"""
+ self.SetStatusText('')
+
+ def OnCleaningRun(self, event):
+ """!Builds options and runs v.clean
+ """
+ self.GetCmdStrings()
+
+ err = list()
+ for p, name in ((self.inmap, _('Name of input vector map')),
+ (self.outmap, _('Name for output vector map')),
+ (self.tools_string, _('Tools')),
+ (self.thresh_string, _('Threshold'))):
+ if not p:
+ err.append(_("'%s' not defined") % name)
+ if err:
+ GError(_("Some parameters not defined. Operation "
+ "cancelled.\n\n%s") % '\n'.join(err),
+ parent = self)
+ return
+
+ self.SetStatusText(_("Executing selected cleaning operations..."))
+ snum = len(self.toolslines.keys())
+
+ 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, onDone = self.OnDone)
+ 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/branches/develbranch_6/gui/wxpython/nviz/animation.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_animation.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/animation.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/animation.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,207 @@
+"""!
+ at package nviz.animation
+
+ at brief Nviz (3D view) animation
+
+Classes:
+ - animation::Animation
+
+(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 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/branches/develbranch_6/gui/wxpython/nviz/animation.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Copied: grass/branches/develbranch_6/gui/wxpython/nviz/main.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/main.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/main.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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.mapwindow
+ import nviz.tools
+ import wxnviz
+ haveNviz = True
+except ImportError, err:
+ haveNviz = False
+ errorMsg = err
+
+if haveNviz:
+ GLWindow = nviz.mapwindow.GLWindow
+ NvizToolWindow = nviz.tools.NvizToolWindow
+else:
+ GLWindow = None
+ NvizToolWindow = None
Copied: grass/branches/develbranch_6/gui/wxpython/nviz/mapwindow.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_mapdisp.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/mapwindow.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/mapwindow.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2471 @@
+"""!
+ at package nviz.mapwindow
+
+ at brief wxGUI 3D view mode (map canvas)
+
+This module implements 3D visualization mode for map display.
+
+List of classes:
+ - mapwindow::NvizThread
+ - mapwindow::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 gui_core.mapwindow import MapWindow
+from gui_core.goutput import wxCmdOutput
+from nviz.workspace import NvizSettings
+from core.settings import UserSettings
+from nviz.animation import Animation
+from nviz 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 = 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 = tempfile.mktemp() + '.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)
+
+ 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'] and 'x' 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')
+
+ # 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')
+
+ # 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 += "\\\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_transparency_map=" + cmdIsoTrMap.strip(',') + ' '
+ if cmdIsoTrVal:
+ cmd += "isosurf_transparency_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):
+ """!Reset view
+ """
+ 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/branches/develbranch_6/gui/wxpython/nviz/preferences.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_preferences.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/preferences.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,627 @@
+"""
+ at package nviz.preferences
+
+ at brief Nviz (3D view) preferences window
+
+Classes:
+ - preferences::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/branches/develbranch_6/gui/wxpython/nviz/tools.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/nviz_tools.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/tools.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/tools.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,4883 @@
+"""!
+ at package nviz.tools
+
+ at brief Nviz (3D view) tools window
+
+Classes:
+ - tools::NvizToolWindow
+ - tools::PositionWindow
+ - tools::ViewPositionWindow
+ - tools::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 core.gcmd import GMessage, RunCommand
+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 gui_core.gselect import Select
+from core.debug import Debug
+try:
+ from nviz.mapwindow import wxUpdateProperties, wxUpdateView,\
+ wxUpdateLight, wxUpdateCPlane
+ import 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)
+## 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 = 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)
+
+ # display
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Display")),
+ pos = (1, 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 = (1, 1), span = (1,4))
+
+ # height
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Height above surface:")),
+ pos = (2, 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 = (2, 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 = (3, 5), flag = wx.EXPAND|wx.ALIGN_RIGHT)
+ gridSizer.Add(item = self.FindWindowById(self.win['vector']['lines']['height']['text']),
+ pos = (4, 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))
+
+ 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 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)
+
+ #
+ # 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'])
+
+ # 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)
+ for i in range(len(isosurfaces)):
+ box.Check(i)
+ 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)
+ for i in range(len(slices)):
+ box.Check(i)
+ 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/branches/develbranch_6/gui/wxpython/nviz/workspace.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/workspace.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/workspace.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,327 @@
+"""!
+ at package nviz.workspace
+
+ at brief wxNviz workspace settings
+
+Classes:
+ - workspace::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:
+ from nviz import 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']) }
+ if 'object' in data:
+ for attrb in ('color', 'width', 'mode', 'height'):
+ 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']) }
+
+ if 'object' in data:
+ for attrb in ('size', 'width', 'marker', 'color', 'height'):
+ 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
Copied: grass/branches/develbranch_6/gui/wxpython/nviz/wxnviz.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/wxnviz.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/nviz/wxnviz.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/nviz/wxnviz.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,2043 @@
+"""!
+ 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:
+ - wxnviz::Nviz
+ - wxnviz::Texture
+ - wxnviz::ImageTexture
+ - wxnviz::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_cell2(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_cell2(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_grid3(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_grid3(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_vectmode(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_sitemode(id, ST_ATT_NONE, 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 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/branches/develbranch_6/gui/wxpython/psmap/dialogs.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap_dialogs.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,5703 @@
+"""!
+ at package psmap.dialogs
+
+ at brief Map feature objects and dialogs for wxPsMap
+
+Classes:
+ - dialogs::UnitConversion
+ - dialogs::TCValidator
+ - dialogs::PenStyleComboBox
+ - dialogs::CheckListCtrl
+ - dialogs::Instruction
+ - dialogs::InstructionObject
+ - dialogs::InitMap
+ - dialogs::MapFrame
+ - dialogs::PageSetup
+ - dialogs::Mapinfo
+ - dialogs::Text
+ - dialogs::Image
+ - dialogs::NorthArrow
+ - dialogs::Scalebar
+ - dialogs::RasterLegend
+ - dialogs::VectorLegend
+ - dialogs::Raster
+ - dialogs::Vector
+ - dialogs::VProperties
+ - dialogs::PsmapDialog
+ - dialogs::PageSetupDialog
+ - dialogs::MapDialog
+ - dialogs::MapFramePanel
+ - dialogs::RasterPanel
+ - dialogs::VectorPanel
+ - dialogs::RasterDialog
+ - dialogs::MainVectorDialog
+ - dialogs::VPropertiesDialog
+ - dialogs::LegendDialog
+ - dialogs::MapinfoDialog
+ - dialogs::ScalebarDialog
+ - dialogs::TextDialog
+ - dialogs::ImageDialog
+ - dialogs::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 dbmgr.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 == 'text':
+ 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 '):
+ 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('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'],
+ 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,
+ rasterLegend = RasterLegend,
+ vectorLegend = VectorLegend,
+ vector = Vector,
+ vProperties = VProperties
+ )
+
+ myInstruction = psmapInstrDict[instruction]
+
+ for i in myInstruction:
+ instr = self.FindInstructionByType(i)
+ if i in ('text', 'vProperties') or not instr:
+
+ id = wx.NewId() #!vProperties expect subtype
+ if i == 'vProperties':
+ id = kwargs['id']
+ newInstr = myInstrDict[i](id, subType = instruction[1:])
+ 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 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 = (50, -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):
+ 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 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
+ map = self.instruction.FindInstructionByType('map')
+ if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
+ self.rasterDict['isRaster'] = False
+ self.rasterDict['raster'] = None
+ map['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'] != map['drawMap']:
+ map['drawMap'] = False
+
+ if self.id not in self.instruction:
+ raster = Raster(self.id)
+ self.instruction.AddInstruction(raster)
+ self.instruction[self.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)
+
+ #Position
+ 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)
+
+ self.positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
+ self.paperPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
+ self.mapPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
+ self.paperPositionCtrl.SetValue(self.textDict['XY'])
+ self.mapPositionCtrl.SetValue(not self.textDict['XY'])
+
+ gridBagSizer.Add(self.positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+ gridBagSizer.Add(self.paperPositionCtrl, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+ gridBagSizer.Add(self.mapPositionCtrl, 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 = self.textDict)
+ panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
+ self.AddUnits(parent = panel, dialogDict = self.textDict)
+ 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)
+
+ self.eastingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
+ self.northingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
+ self.eastingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+ self.northingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+ east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
+ self.eastingCtrl.SetValue(str(east))
+ self.northingCtrl.SetValue(str(north))
+
+ self.gridBagSizerM.Add(self.eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(self.northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(self.eastingCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(self.northingCtrl, 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)
+
+ #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, self.paperPositionCtrl)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.mapPositionCtrl)
+ 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.paperPositionCtrl.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.paperPositionCtrl.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.eastingCtrl.GetValue():
+ self.textDict['east'] = self.eastingCtrl.GetValue()
+ else:
+ self.textDict['east'] = self.textDict['east']
+
+ if self.northingCtrl.GetValue():
+ self.textDict['north'] = self.northingCtrl.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.eastingCtrl.SetValue(str(self.textDict['east']))
+ self.northingCtrl.SetValue(str(self.textDict['north']))
+
+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
Copied: grass/branches/develbranch_6/gui/wxpython/psmap/frame.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/psmap.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/frame.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/frame.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1709 @@
+"""!
+ at package psmap.frame
+
+ at brief GUI for ps.map
+
+Classes:
+ - frame::PsMapFrame
+ - frame::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
+
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
+from core import globalvar
+import wx
+
+try:
+ import wx.lib.agw.flatnotebook as fnb
+except ImportError:
+ import wx.lib.flatnotebook as fnb
+
+import grass.script as grass
+
+from gui_core.menu import Menu
+from gui_core.goutput import CmdThread, EVT_CMD_DONE
+from psmap.toolbars import PsMapToolbar
+from icon import Icons
+from core.gcmd import RunCommand, GError, GMessage
+from gui_core.forms import GUI
+from psmap.menudata import PsMapData
+
+from psmap.dialogs import *
+
+class PsMapFrame(wx.Frame):
+ def __init__(self, parent = None, id = wx.ID_ANY,
+ title = _("GRASS GIS Cartographic Composer (experimental prototype)"), **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),
+ '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)),
+ '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 haveImage:
+ 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 haveImage 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 = Image.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)
+ # 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 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'):
+ 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)
+
+ 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
+ resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
+ resol = grass.parse_key_val(resol, val_type = float)
+ RunCommand('g.region', nsres = resol['nsres'], ewres = resol['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']:
+ 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']:
+ 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.itemLabels = { 'map': ['MAP FRAME'],
+ 'rasterLegend': ['RASTER LEGEND'],
+ 'vectorLegend': ['VECTOR LEGEND'],
+ 'mapinfo': ['MAP INFO'],
+ 'scalebar': ['SCALE BAR']}
+
+ # 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
+
+ texts = self.instruction.FindInstructionByType('text', list = True)
+ for text in texts:
+ e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
+ y = self.instruction[text.id]['where'][1], paperToMap = True)
+ self.instruction[text.id]['east'], self.instruction[text.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,
+ '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),
+ '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'):
+ 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]
+ 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)
+ 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 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[self.instruction[drawid].type])
+ 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 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]
+
+ self.itemLabels['map'] = self.itemLabels['map'][0:1]
+ self.itemLabels['map'].append("raster: " + rasterName)
+ if vectorId:
+ for map in self.instruction[vectorId]['list']:
+ self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
+
+ 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/branches/develbranch_6/gui/wxpython/psmap/menudata.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/menudata.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/menudata.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,33 @@
+"""!
+ at package ps.menudata
+
+ at brief wxPsMap - menu entries
+
+Classes:
+ - menudata::PsMapData
+
+(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 Anna Kratochvilova <kratochanna gmail.com>
+"""
+
+import os
+
+from core import globalvar
+from core.menudata import MenuData
+
+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(globalvar.ETCWXDIR, 'xml', 'menudata_psmap.xml')
+
+ MenuData.__init__(self, path)
Added: grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/psmap/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,94 @@
+"""!
+ at package psmap.toolbars
+
+ at brief wxPsMap toolbars classes
+
+Classes:
+ - toolbars::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
+ """
+ BaseToolbar.__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 haveImage
+ if not haveImage:
+ 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))
+ )
Copied: grass/branches/develbranch_6/gui/wxpython/states.txt (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/states.txt)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/states.txt (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/states.txt 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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
Added: grass/branches/develbranch_6/gui/wxpython/vdigit/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,754 @@
+"""!
+ at package vdigit.dialogs
+
+ at brief wxGUI vector digitizer dialogs
+
+Classes:
+ - dialogs::VDigitCategoryDialog
+ - dialogs::CategoryListCtrl
+ - dialogs::VDigitZBulkDialog
+ - dialogs::VDigitDuplicatesDialog
+ - dialogs::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
Added: grass/branches/develbranch_6/gui/wxpython/vdigit/main.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/main.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/main.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,35 @@
+"""!
+ at package vdigit.main
+
+ at brief wxGUI vector digitizer
+
+Classes:
+ - main::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)
Copied: grass/branches/develbranch_6/gui/wxpython/vdigit/mapwindow.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/mapdisp_vdigit.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/mapwindow.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/mapwindow.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1064 @@
+"""!
+ at package vdigit.mapwindow
+
+ at brief Map display canvas for wxGUI vector digitizer
+
+Classes:
+ - mapwindow::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 dbmgr.dialogs import DisplayAttributesDialog
+from core.gcmd import RunCommand, GMessage, GError
+from core.debug import Debug
+from mapdisp.mapwindow import BufferedWindow
+from core.settings import UserSettings
+from core.utils import ListOfCatsToRange
+from core.globalvar import QUERYLAYER
+from vdigit.dialogs import VDigitCategoryDialog, VDigitZBulkDialog, 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()
+
+ try:
+ item = self.tree.FindItemByData('maplayer', self.toolbar.GetLayer())
+ except TypeError:
+ item = None
+
+ if 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.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 = 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()
+ item = self.tree.FindItemByData('maplayer', mapLayer)
+ vdigit = self.tree.GetPyData(item)[0]['vdigit']
+ 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()
+ item = self.tree.FindItemByData('maplayer', mapLayer)
+ vdigit = self.tree.GetPyData(item)[0]['vdigit']
+
+ if vdigit is None 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/branches/develbranch_6/gui/wxpython/vdigit/preferences.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/vdigit.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/preferences.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/preferences.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,782 @@
+"""!
+ at package vdigit.preferences
+
+ at brief wxGUI vector digitizer preferences dialogs
+
+Classes:
+ - preferences::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/branches/develbranch_6/gui/wxpython/vdigit/toolbars.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/toolbars.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/toolbars.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,754 @@
+"""!
+ at package vdigit.toolbars
+
+ at brief wxGUI vector digitizer toolbars
+
+List of classes:
+ - toolbars::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>
+"""
+import wx
+
+from grass.script import core as grass
+
+from gui_core.toolbars import BaseToolbar
+from gui_core.dialogs import CreateNewVector
+from icons.icon import Icons
+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, mapcontent, layerTree = None, log = None):
+ self.mapcontent = mapcontent # Map class instance
+ self.layerTree = layerTree # reference to layer tree associated to map display
+ self.log = log # log area
+ 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 = None
+
+ # 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.
+ self.combo.Hide()
+ self.combo.Show()
+
+ # disable undo/redo
+ 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']
+ return self._getToolbarData(((None, ),
+ ("addPoint", icons["addPoint"],
+ self.OnAddPoint,
+ wx.ITEM_CHECK),
+ ("addLine", icons["addLine"],
+ self.OnAddLine,
+ wx.ITEM_CHECK),
+ ("addBoundary", icons["addBoundary"],
+ self.OnAddBoundary,
+ wx.ITEM_CHECK),
+ ("addCentroid", icons["addCentroid"],
+ self.OnAddCentroid,
+ wx.ITEM_CHECK),
+ ("addArea", icons["addArea"],
+ self.OnAddArea,
+ wx.ITEM_CHECK),
+ ("moveVertex", icons["moveVertex"],
+ self.OnMoveVertex,
+ wx.ITEM_CHECK),
+ ("addVertex", icons["addVertex"],
+ self.OnAddVertex,
+ wx.ITEM_CHECK),
+ ("removeVertex", icons["removeVertex"],
+ self.OnRemoveVertex,
+ wx.ITEM_CHECK),
+ ("editLine", icons["editLine"],
+ self.OnEditLine,
+ wx.ITEM_CHECK),
+ ("moveLine", icons["moveLine"],
+ self.OnMoveLine,
+ wx.ITEM_CHECK),
+ ("deleteLine", icons["deleteLine"],
+ self.OnDeleteLine,
+ wx.ITEM_CHECK),
+ ("displayCats", icons["displayCats"],
+ self.OnDisplayCats,
+ wx.ITEM_CHECK),
+ ("displayAttr", icons["displayAttr"],
+ self.OnDisplayAttr,
+ wx.ITEM_CHECK),
+ ("additionalTools", icons["additionalTools"],
+ self.OnAdditionalToolMenu,
+ wx.ITEM_CHECK),
+ (None, ),
+ ("undo", icons["undo"],
+ self.OnUndo),
+ ("settings", icons["settings"],
+ self.OnSettings),
+ ("quit", icons["quit"],
+ self.OnExit))
+ )
+
+ def OnTool(self, event):
+ """!Tool selected -> disable selected tool in map toolbar"""
+ aId = self.parent.toolbars['map'].GetAction(type = 'id')
+ self.parent.toolbars['map'].ToggleTool(aId, False)
+
+ # set cursor
+ cursor = self.parent.cursors["cross"]
+ self.parent.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.parent.MapWindow.ClearLines(pdc = self.parent.MapWindow.pdcTmp)
+ if self.digit and \
+ len(self.parent.MapWindow.digit.GetDisplay().GetSelected()) > 0:
+ # cancel action
+ self.parent.MapWindow.OnMiddleDown(None)
+
+ # set focus
+ self.parent.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.parent.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.parent.MapWindow.mouse['box'] = 'line'
+ ### self.parent.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.parent.MapWindow.polycoords = [] # reset temp line
+ self.action = { 'desc' : "addLine",
+ 'type' : "boundary",
+ 'id' : self.addBoundary }
+ self.parent.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.parent.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.parent.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.parent.MapWindow.mouse['use'] = "pointer"
+ self.parent.MapWindow.mouse['box'] = "point"
+ self.parent.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.parent.MapWindow.mouse['box'] = 'point'
+
+ def OnAddVertex(self, event):
+ """!Add line vertex"""
+ Debug.msg(2, "Digittoolbar.OnAddVertex():")
+ self.action = { 'desc' : "addVertex",
+ 'id' : self.addVertex }
+ self.parent.MapWindow.mouse['box'] = 'point'
+
+ def OnRemoveVertex(self, event):
+ """!Remove line vertex"""
+ Debug.msg(2, "Digittoolbar.OnRemoveVertex():")
+ self.action = { 'desc' : "removeVertex",
+ 'id' : self.removeVertex }
+ self.parent.MapWindow.mouse['box'] = 'point'
+
+ def OnEditLine(self, event):
+ """!Edit line"""
+ Debug.msg(2, "Digittoolbar.OnEditLine():")
+ self.action = { 'desc' : "editLine",
+ 'id' : self.editLine }
+ self.parent.MapWindow.mouse['box'] = 'line'
+
+ def OnMoveLine(self, event):
+ """!Move line"""
+ Debug.msg(2, "Digittoolbar.OnMoveLine():")
+ self.action = { 'desc' : "moveLine",
+ 'id' : self.moveLine }
+ self.parent.MapWindow.mouse['box'] = 'box'
+
+ def OnDeleteLine(self, event):
+ """!Delete line"""
+ Debug.msg(2, "Digittoolbar.OnDeleteLine():")
+ self.action = { 'desc' : "deleteLine",
+ 'id' : self.deleteLine }
+ self.parent.MapWindow.mouse['box'] = 'box'
+
+ def OnDisplayCats(self, event):
+ """!Display/update categories"""
+ Debug.msg(2, "Digittoolbar.OnDisplayCats():")
+ self.action = { 'desc' : "displayCats",
+ 'id' : self.displayCats }
+ self.parent.MapWindow.mouse['box'] = 'point'
+
+ def OnDisplayAttr(self, event):
+ """!Display/update attributes"""
+ Debug.msg(2, "Digittoolbar.OnDisplayAttr():")
+ self.action = { 'desc' : "displayAttrs",
+ 'id' : self.displayAttr }
+ self.parent.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.parent.MapWindow.digit = VDigit(mapwindow = self.parent.MapWindow)
+ except SystemExit:
+ self.digit = self.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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.parent.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',
+ { '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.mapcontent.ChangeLayerActive(mapLayer, False)
+
+ # clean map canvas
+ self.parent.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.parent.MapWindow.pdcVector = wx.PseudoDC()
+ self.digit = self.parent.MapWindow.digit = VDigit(mapwindow = self.parent.MapWindow)
+
+ self.mapLayer = mapLayer
+
+ # open vector map
+ if self.digit.OpenMap(mapLayer.GetName()) is None:
+ self.mapLayer = None
+ self.StopEditing()
+ return False
+
+ # update toolbar
+ self.combo.SetValue(mapLayer.GetName())
+ self.parent.toolbars['map'].combo.SetValue (_('Digitize'))
+ 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.parent.MapWindow.mouse['use'] == 'pointer':
+ self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
+
+ if not self.parent.MapWindow.resize:
+ self.parent.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
+ """
+ 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.mapcontent.ChangeLayerActive(self.mapLayer, True)
+
+ # change cursor
+ self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
+ self.parent.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.parent.MapWindow.digit
+
+ self.mapLayer = None
+
+ self.parent.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.mapcontent.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:
+ 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
Copied: grass/branches/develbranch_6/gui/wxpython/vdigit/wxdigit.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdigit.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/wxdigit.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/wxdigit.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,1750 @@
+"""!
+ 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:
+ - wxdigit::VDigitError
+ - wxdigit::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.gcmd import GError
+from core.debug import Debug
+from core.settings import UserSettings
+from vdigit.wxdisplay import DisplayDriver
+
+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.'),
+ 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_list()
+ 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.value[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_list(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)
+
+ name, mapset = name.split('@')
+
+ 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
+
+ Debug.msg(3, "IVDigit._addFeature(): area - left=%d right=%d",
+ left, right)
+
+ # 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, right, 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
Copied: grass/branches/develbranch_6/gui/wxpython/vdigit/wxdisplay.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/wxvdriver.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/vdigit/wxdisplay.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/vdigit/wxdisplay.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,995 @@
+"""!
+ 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:
+ - wxdisplay::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
+
+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 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)
+
+ 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
+
+ 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
+
+ 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/branches/develbranch_6/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxgui.py 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/wxgui.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -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
+ - wxgui::GMFrame
+ - wxgui::GMApp
+ - wxgui::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,59 @@
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 profile
-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.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, Command
+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 HistogramFrame
+from modules.mcalc_builder import MapCalcFrame
+from dbmgr.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
+from modules.extensions import InstallExtensionWindow
+from lmgr.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
+from lmgr.toolbars import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
+from lmgr.pyshell import PyShellWindow
+from gui_core.forms import GUI
-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)
@@ -231,7 +223,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()
@@ -247,7 +239,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:
@@ -258,7 +250,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()
@@ -294,8 +286,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')
@@ -340,10 +332,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()
@@ -362,7 +354,7 @@
def OnGModeler(self, event):
"""!Launch Graphical Modeler"""
- win = gmodeler.ModelFrame(parent = self)
+ win = ModelFrame(parent = self)
win.CentreOnScreen()
win.Show()
@@ -373,12 +365,12 @@
try:
from gui_modules import psmap
except:
- gcmd.GError(parent = self.parent,
- message = _("Hardcopy Map Output Utility is not available. You can install it by %s") % \
- 'g.extension.py -s svnurl=https://svn.osgeo.org/grass/grass-addons extension=wx.psmap')
+ GError(parent = self.parent,
+ message = _("Hardcopy Map Output Utility is not available. You can install it by %s") % \
+ 'g.extension.py -s svnurl=https://svn.osgeo.org/grass/grass-addons extension=wx.psmap')
return
- win = psmap.PsMapFrame(parent = self)
+ win = PsMapFrame(parent = self)
win.CentreOnScreen()
win.Show()
@@ -403,7 +395,7 @@
dlg.Destroy()
return
- self.model = gmodeler.Model()
+ self.model = Model()
self.model.LoadModel(filename)
self.model.Run(log = self.goutput, onDone = self.OnDone, parent = self)
@@ -412,15 +404,15 @@
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"""
old_pgnum = event.GetOldSelection()
@@ -523,7 +515,7 @@
if layer and len(cmdlist) == 1: # only if no paramaters given
if (type == 'raster' and cmdlist[0][0] == 'r' and cmdlist[0][1] != '3') or \
(type == 'vector' and cmdlist[0][0] == 'v'):
- input = menuform.GUI().GetCommandInputMapParamKey(cmdlist[0])
+ input = GUI().GetCommandInputMapParamKey(cmdlist[0])
if input:
cmdlist.append("%s=%s" % (input, name))
@@ -539,7 +531,7 @@
"""!Parse command selected from menu"""
if event:
cmd = self.GetMenuCmd(event)
- menuform.GUI(parent = self).ParseCommand(cmd)
+ GUI(parent = self).ParseCommand(cmd)
def OnVDigit(self, event):
"""!Start vector digitizer
@@ -562,14 +554,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]:
@@ -595,9 +587,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)
@@ -605,14 +597,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>.") % \
@@ -637,43 +629,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
@@ -796,10 +788,10 @@
# 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"
+ GError(parent = self,
+ message = _("Reading workspace file <%s> failed.\n"
"Invalid file, unable to parse XML document.") % filename)
return
@@ -940,7 +932,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'],
@@ -1009,11 +1001,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:
@@ -1022,8 +1014,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()
@@ -1067,9 +1059,9 @@
cmd = self.GetMenuCmd(event)
if cmd[0] == 'r.colors':
- ctable = colorrules.RasterColorTable(self)
+ ctable = RasterColorTable(self)
else:
- ctable = colorrules.VectorColorTable(self, attributeType = 'color')
+ ctable = VectorColorTable(self, attributeType = 'color')
ctable.CentreOnScreen()
ctable.Show()
@@ -1093,9 +1085,9 @@
xmonlist = []
# make list of xmons that are not running
- ret = gcmd.RunCommand('d.mon',
- flags = 'L',
- read = True)
+ ret = RunCommand('d.mon',
+ flags = 'L',
+ read = True)
for line in ret.split('\n'):
line = line.strip()
@@ -1107,7 +1099,7 @@
# bring up the xmon
cmdlist = ['d.mon', xmon]
- p = gcmd.Command(cmdlist, wait=False)
+ p = Command(cmdlist, wait=False)
# run the command
command = self.GetMenuCmd(event)
@@ -1127,7 +1119,7 @@
grassrun = os.path.join(gisbase,'etc','grass-run.sh')
cmdlist = [xtermwrapper, '-e', grassrun, command]
- p = gcmd.Command(cmdlist, wait=False)
+ p = Command(cmdlist, wait=False)
# reset display mode
os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE'
@@ -1135,7 +1127,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()
@@ -1149,11 +1141,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()
@@ -1166,10 +1158,9 @@
"""
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 = HistogramFrame(self, size = (400,300),
+ style = wx.DEFAULT_FRAME_STYLE)
+
#show new display
self.histogram.Show()
self.histogram.Refresh()
@@ -1195,8 +1186,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()
@@ -1207,43 +1198,43 @@
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()
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
@@ -1293,7 +1284,7 @@
maptype = None
if not maptype or maptype != 'vector':
- gcmd.GMessage(parent = self,
+ GMessage(parent = self,
message = _("Selected map layer is not vector."))
return
@@ -1307,10 +1298,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()
@@ -1329,10 +1320,10 @@
try:
from gui_modules.wms.wmsmenu import DisplayWMSMenu
except:
- gcmd.GError(parent = self.parent,
- message = _("Experimental WMS support for wxGUI not available. "
- "You can install it by '%s'") % \
- "g.extension -s extension=wx.wms")
+ GError(parent = self.parent,
+ message = _("Experimental WMS support for wxGUI not available. "
+ "You can install it by '%s'") % \
+ "g.extension -s extension=wx.wms")
return
DisplayWMSMenu()
@@ -1357,12 +1348,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)
@@ -1390,7 +1381,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()
@@ -1414,8 +1405,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,
@@ -1829,6 +1820,6 @@
q = wx.LogNull()
app.MainLoop()
-
+
if __name__ == "__main__":
sys.exit(main())
Added: grass/branches/develbranch_6/gui/wxpython/wxplot/base.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxplot/base.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/wxplot/base.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,526 @@
+"""!
+ at package wxplot.base
+
+ at brief Base classes for iinteractive plotting using PyPlot
+
+Classes:
+ - base::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
+from core.render import Map
+
+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
+
+
+ rdict[r]['units'] = ''
+ if ret['units'] not in ('(none)', '"none"', '', None):
+ rdict[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] = {}
+ rdict[rpair][0]['units'] = ''
+ rdict[rpair][1]['units'] = ''
+
+ if ret0['units'] not in ('(none)', '"none"', '', None):
+ rdict[rpair][0]['units'] = ret0['units']
+ if ret1['units'] not in ('(none)', '"none"', '', None):
+ rdict[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()
+
Added: grass/branches/develbranch_6/gui/wxpython/wxplot/dialogs.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxplot/dialogs.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/wxplot/dialogs.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,192 @@
+"""!
+ at package wxplot.dialogs
+
+ at brief Dialogs for different plotting routines
+
+Classes:
+ - dialogs::ProfileRasterDialog
+ - dialogs::PlotStatsFrame
+
+(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 gui_core.gselect import Select
+
+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 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)
Copied: grass/branches/develbranch_6/gui/wxpython/wxplot/profile.py (from rev 49620, grass/branches/develbranch_6/gui/wxpython/gui_modules/profile.py)
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxplot/profile.py (rev 0)
+++ grass/branches/develbranch_6/gui/wxpython/wxplot/profile.py 2011-12-08 12:45:28 UTC (rev 49621)
@@ -0,0 +1,429 @@
+"""!
+ at package wxplot.profile
+
+ at brief Profiling using PyPlot
+
+Classes:
+ - profile::ProfileFrame
+ - profile::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
+from icons.icon import Icons
+from wxplot.dialogs import ProfileRasterDialog, PlotStatsFrame
+from core.gcmd import RunCommand
+
+class ProfileFrame(BasePlotFrame):
+ """!Mainframe for displaying profile of one or more raster maps. Uses wx.lib.plot.
+ """
+ def __init__(self, parent, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE,
+ rasterList = [], **kwargs):
+ BasePlotFrame.__init__(self, parent, **kwargs)
+
+ 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.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.raster = self.InitRasterOpts(self.rasterList, self.plottype)
+ else:
+ self.raster = {}
+
+ 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 = 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 = 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 = 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 = 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),
+ ))
Modified: grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox 2011-12-08 12:19:10 UTC (rev 49620)
+++ grass/branches/develbranch_6/gui/wxpython/wxpythonlib.dox 2011-12-08 12:45:28 UTC (rev 49621)
@@ -1,4 +1,4 @@
-/*! \page wxpythonlib GRASS WxPython-based Graphical User Interface
+/*! \page wxpythonlib GRASS wxPython-based GUI
The GUI (Graphical User Interface) is written in the Python
programming language using <a
@@ -24,17 +24,19 @@
- \ref background
- \ref classes
- \ref core
+ - \ref gui_core
- \ref lmgr
- \ref mapdisp
- \ref wscreen
- - \ref atm
- - \ref georect
+ - \ref dbmgr
+ - \ref gpc
- \ref gmodeler
- \ref vdigit
- \ref wxnviz
+ - \ref psmap
- \ref locWizard
- - \ref mcalc
- - \ref misc
+ - \ref plot
+ - \ref other
- \ref devel
- \ref seeAlso
- \ref refs
@@ -52,322 +54,412 @@
\subsection core Core modules
-- gui_modules/debug.py
- - gui_modules::debug::DebugMsg
+- core::debug
+ - debug::DebugMsg
+- core::globalvar
+- core::gcmd
+ - gcmd::GError
+ - gcmd::GWarning
+ - gcmd::GMessage
+ - gcmd::GException
+ - gcmd::Popen
+ - gcmd::Command
+ - gcmd::CommandThread
+- core::menudata
+ - menudata::MenuData
+- core::render
+ - render::Layer
+ - render::Layer
+ - render::MapLayer
+ - render::Overlay
+ - render::Map
+- core::settings
+ - settings::Settings
+- core::units
+ - units::BaseUnits
+- core::utils
+- core::workspace
+ - workspace::ProcessWorkspaceFile
+ - workspace::WriteWorkspaceFile
+ - workspace::ProcessGrcFile
-- gui_modules/gcmd.py
- - gui_modules::gcmd::GError
- - gui_modules::gcmd::GWarning
- - gui_modules::gcmd::GMessage
- - gui_modules::gcmd::GException
- - gui_modules::gcmd::Popen
- - gui_modules::gcmd::Command
- - gui_modules::gcmd::CommandThread
+\subsection gui_core GUI core modules
-- gui_modules/globalvar.py
+- gui_core::dialogs
+ - dialogs::ElementDialog
+ - dialogs::LocationDialog
+ - dialogs::MapsetDialog
+ - dialogs::NewVectorDialog
+ - dialogs::SavedRegion
+ - dialogs::DecorationDialog
+ - dialogs::TextLayerDialog
+ - dialogs::GroupDialog
+ - dialogs::MapLayersDialog
+ - dialogs::ImportDialog
+ - dialogs::GdalImportDialog
+ - dialogs::GdalOutputDialog
+ - dialogs::DxfImportDialog
+ - dialogs::LayersList (used by MultiImport)
+ - dialogs::SetOpacityDialog
+ - dialogs::StaticWrapText
+ - dialogs::ImageSizeDialog
+ - dialogs::SqlQueryFrame
+- gui_core::forms
+ - forms::TaskFrame
+ - forms::CmdPanel
+ - forms::GrassGUIApp
+- gui_core::ghelp
+ - ghelp::SearchModuleWindow
+ - ghelp::MenuTreeWindow
+ - ghelp::MenuTree
+ - ghelp::AboutWindow
+ - ghelp::HelpFrame
+ - ghelp::HelpWindow
+ - ghelp::HelpPanel
+- gui_core::goutput
+ - goutput::CmdThread
+ - goutput::GMConsole
+ - goutput::GMStc
+ - goutput::GMStdout
+ - goutput::GMStderr
+- gui_core::gselect
+ - gselect::Select
+ - gselect::VectorSelect
+ - gselect::TreeCrtlComboPopup
+ - gselect::VectorDBInfo
+ - gselect::LayerSelect
+ - gselect::DriverSelect
+ - gselect::DatabaseSelect
+ - gselect::ColumnSelect
+ - gselect::DbaseSelect
+ - gselect::LocationSelect
+ - gselect::MapsetSelect
+ - gselect::SubGroupSelect
+ - gselect::FormatSelect
+ - gselect::GdalSelect
+ - gselect::ProjSelect
+ - gselect::ElementSelect
+ - gselect::OgrTypeSelect
+- gui_core::mapdisp
+ - mapdisp::MapFrameBase
+- gui_core::mapwindow
+ - mapwindow::MapWindow
+- gui_core::menu
+ - menu::Menu
+- gui_core::preferences
+ - preferences::PreferencesBaseDialog
+ - preferences::PreferencesDialog
+ - preferences::DefaultFontDialog
+ - preferences::MapsetAccess
+- gui_core::prompt
+ - prompt::PromptListCtrl
+ - prompt::TextCtrlAutoComplete
+ - prompt::GPrompt
+ - prompt::GPromptPopUp
+ - prompt::GPromptSTC
+- gui_core::toolbars
+ - toolbars::BaseToolbar
+- gui_core::widgets
+ - widgets::ScrolledPanel
+ - widgets::NTCValidator
+ - widgets::NumTextCtrl
+ - widgets::FloatSlider
+ - widgets::SymbolButton
+ - widgets::StaticWrapText
+ - widgets::FloatValidator
+ - widgets::ItemTree
-- gui_modules/gselect.py
- - gui_modules::gselect::Select
- - gui_modules::gselect::VectorSelect
- - gui_modules::gselect::TreeCtrlComboPopup
- - gui_modules::gselect::VectorDBInfo
- - gui_modules::gselect::LayerSelect
- - gui_modules::gselect::LayerNameSelect
- - gui_modules::gselect::DriverSelect
- - gui_modules::gselect::DatabaseSelect
- - gui_modules::gselect::TableSelect
- - gui_modules::gselect::ColumnSelect
- - gui_modules::gselect::LocationSelect
- - gui_modules::gselect::MapsetSelect
- - gui_modules::gselect::SubGroupSelect
- - gui_modules::gselect::FormatSelect
- - gui_modules::gselect::GdalSelect
-
-- gui_modules/menuform.py
- - gui_modules::menuform::UpdateThread
- - gui_modules::menuform::UpdateQThread
- - gui_modules::menuform::grassTask
- - gui_modules::menuform::processTask
- - gui_modules::menuform::mainFrame
- - gui_modules::menuform::cmdPanel
- - gui_modules::menuform::GrassGUIApp
- - gui_modules::menuform::GUI
- - gui_modules::menuform::FloatValidator
-
-- gui_modules/units.py
- - gui_modules::units::BaseUnits
-
-- gui_modules/utils.py
-
\subsection lmgr Layer Manager
-- wxgui.py
+- wxgui
- wxgui::GMFrame
- wxgui::GMApp
+ - wxgui::Usage
+- lmgr::layertree
+ - lmgr::LayerTree
+- lmgr::menudata
+ - menudata::MenuData
+- lmgr::pyshell
+ - pyshell::PyShellWindow
+- lmgr::toolbars
+ - toolbars::LMWorkspaceToolbar
+ - toolbars::LMDataToolbar
+ - toolbars::LMToolsToolbar
+ - toolbars::LMMiscToolbar
+ - toolbars::LMVectorToolbar
+ - toolbars::LMNvizToolbar
-- gui_modules/layertree.py
- - gui_modules::layertree::LayerTree
-
-- gui_modules/goutput.py
- - gui_modules::goutput::CmdThread
- - gui_modules::goutput::GMConsole
- - gui_modules::goutput::GMStdout
- - gui_modules::goutput::GMStderr
- - gui_modules::goutput::GMStc
-
-- gui_modules/ghelp.py
- - gui_modules::ghelp::HelpFrame
- - gui_modules::ghelp::SearchModuleWindow
- - gui_modules::ghelp::MenuTreeWindow
- - gui_modules::ghelp::ItemTree
- - gui_modules::ghelp::MenuTree
- - gui_modules::ghelp::AboutWindow
- - gui_modules::ghelp::InstallExtensionWindow
- - gui_modules::ghelp::ExtensionTree
- - gui_modules::ghelp::HelpWindow
- - gui_modules::ghelp::HelpPanel
-
-- gui_modules/menudata.py
- - gui_modules::menudata::MenuData
- - gui_modules::menudata::ManagerData
- - gui_modules::menudata::ModelerData
-
-- gui_modules/menu.py
- - gui_modules::menu::Menu
-
-- gui_modules/preferences.py
- - gui_modules::preferences::Settings
- - gui_modules::preferences::PreferencesBaseDialog
- - gui_modules::preferences::PreferencesDialog
- - gui_modules::preferences::DefaultFontDialog
- - gui_modules::preferences::MapsetAccess
- - gui_modules::preferences::CheckListMapset
-
-- gui_modules/prompt.py
- - gui_modules::prompt::PromptListCtrl
- - gui_modules::prompt::TextCtrlAutoComplete
- - gui_modules::prompt::GPrompt
- - gui_modules::prompt::GPromptPopUp
- - gui_modules::prompt::GPromptSTC
-
\subsection mapdisp Map Display Window
-- gui_modules/disp_print.py
- - gui_modules::disp_print::MapPrint
- - gui_modules::disp_print::PrintOptions
+- mapdisp::frame
+ - mapdisp::MapFrame
+ - mapdisp::MapApp
+- mapdisp::gprint
+ - gprint::MapPrint
+ - gprint::PrintOptions
+- mapdisp::mapwindow
+ - mapwindow::BufferedWindow
+- mapdisp::statusbar
+ - statusbar::SbException
+ - statusbar::SbManager
+ - statusbar::SbItem
+ - statusbar::SbRender
+ - statusbar::SbShowRegion
+ - statusbar::SbAlignExtent
+ - statusbar::SbResolution
+ - statusbar::SbMapScale
+ - statusbar::SbGoTo
+ - statusbar::SbProjection
+ - statusbar::SbMask
+ - statusbar::SbTextItem
+ - statusbar::SbDisplayGeometry
+ - statusbar::SbCoordinates
+ - statusbar::SbRegionExtent
+ - statusbar::SbCompRegionExtent
+ - statusbar::SbProgress
+- mapdisp::toolbars
+ - toolbars::MapToolbar
-- gui_modules/mapdisp_command.py
- - gui_modules::mapdisp_command::Command
-
-- gui_modules/mapdisp.py
- - gui_modules::mapdisp::MapFrame
- - gui_modules::mapdisp::MapApp
-
-- gui_modules/mapdisp_window.py
- - gui_modules::mapdisp_window::MapWindow
- - gui_modules::mapdisp_window::BufferedWindow
-
-- gui_modules/render.py
- - gui_modules::render::Layer
- - gui_modules::render::MapLayer
- - gui_modules::render::Overlay
- - gui_modules::render::Map
-
-- gui_modules/toolbars.py
- - gui_modules::toolbars::AbstractToolbar
- - gui_modules::toolbars::MapToolbar
- - gui_modules::toolbars::GCPManToolbar
- - gui_modules::toolbars::GCPDisplayToolbar
- - gui_modules::toolbars::GRToolbar
- - gui_modules::toolbars::GCPToolbar
- - gui_modules::toolbars::VDigitToolbar
- - gui_modules::toolbars::ProfileToolbar
- - gui_modules::toolbars::NvizToolbar
- - gui_modules::toolbars::ModelToolbar
- - gui_modules::toolbars::HistogramToolbar
- - gui_modules::toolbars::LayerManagerToolbar
-
\subsection wscreen Welcome screen
-- gis_set_error.py
-- gis_set.py
+- gis_set_error
+- gis_set
- gis_set::GRASSStartup
- gis_set::StartUp
- gis_set::GListBox
-\subsection atm Attribute Table Manager
+\subsection dbmgr Database Manager
-- gui_modules/dbm_base.py
- - gui_modules::dbm_base::VectorDBInfo
+- dbmgr::dialogs
+ - dialogs::DisplayAttributesDialog
+ - dialogs::ModifyTableRecord
+- dbmgr::manager
+ - manager::Log
+ - manager::VirtualAttributeList
+ - manager::AttributeManager
+ - manager::TableListCtrl
+ - manager::LayerListCtrl
+ - manager::LayerBook
+- dbmgr::sqlbuilder
+ - sqlbuilder::SQLFrame
+- dbmgr::vinfo
+ - vinfo::VectorDBInfo
-- gui_modules/dbm_dialogs.py
- - gui_modules::dbm_dialogs::DisplayAttributesDialog
- - gui_modules::dbm_dialogs::ModifyTableRecord
+\subsection gpc Georectifier
-- gui_modules/dbm.py
- - gui_modules::dbm::Log
- - gui_modules::dbm::VirtualAttributeList
- - gui_modules::dbm::AttributeManager
- - gui_modules::dbm::TableListCtrl
- - gui_modules::dbm::LayerListCtrl
- - gui_modules::dbm::LayerBook
+- gcp::manager
+ - manager::GCPWizard
+ - manager::LocationPage
+ - manager::GroupPage
+ - manager::DispMapPage
+ - manager::GCP
+ - manager::GCPList
+ - manager::VectGroup
+ - manager::EditGCP
+ - manager::GrSettingsDialog
+- gcp::mapdisplay
+- mapdisplay::MapFrame
+- gcp::toolbars
+ - toolbars::GCPMapToolbar
+ - toolbars::GCPDisplayToolbar
-- gui_modules/sqlbuilder.py
- - gui_modules::sqlbuilder::SQLFrame
-
-\subsection georect Georectifier
-
-- gui_modules/gcpmanager.py
- - gui_modules::gcpmanager::GCPWizard
- - gui_modules::gcpmanager::LocationPage
- - gui_modules::gcpmanager::GroupPage
- - gui_modules::gcpmanager::DispMapPage
- - gui_modules::gcpmanager::GCP
- - gui_modules::gcpmanager::GCPList
- - gui_modules::gcpmanager::VectGroup
- - gui_modules::gcpmanager::EditGCP
- - gui_modules::gcpmanager::GrSettingsDialog
-
-- gui_modules/gcpmapdisp.py
- - gui_modules::gcpmapdisp::MapFrame
-
\subsection gmodeler Graphical Modeler
-- gui_modules/gmodeler.py
- - gui_modules::gmodeler::Model
- - gui_modules::gmodeler::ModelFrame
- - gui_modules::gmodeler::ModelCanvas
- - gui_modules::gmodeler::ModelObject
- - gui_modules::gmodeler::ModelAction
- - gui_modules::gmodeler::ModelData
- - gui_modules::gmodeler::ModelDataDialog
- - gui_modules::gmodeler::ModelEvtHandler
- - gui_modules::gmodeler::ModelSearchDialog
- - gui_modules::gmodeler::ModelRelation
- - gui_modules::gmodeler::ProcessModelFile
- - gui_modules::gmodeler::WriteModelFile
- - gui_modules::gmodeler::PreferencesDialog
- - gui_modules::gmodeler::PropertiesDialog
- - gui_modules::gmodeler::ModelParamDialog
- - gui_modules::gmodeler::ModelListCtrl
- - gui_modules::gmodeler::VariablePanel
- - gui_modules::gmodeler::VariableListCtrl
- - gui_modules::gmodeler::ModelItem
- - gui_modules::gmodeler::ModelItemDialog
- - gui_modules::gmodeler::ModelLoop
- - gui_modules::gmodeler::ModelLoopDialog
- - gui_modules::gmodeler::ItemPanel
- - gui_modules::gmodeler::ItemListCtrl
- - gui_modules::gmodeler::ItemCheckListCtrl
- - gui_modules::gmodeler::ModelCondition
- - gui_modules::gmodeler::ModelConditionDialog
- - gui_modules::gmodeler::WritePythonFile
+- gmodeler::dialogs
+ - dialogs::ModelDataDialog
+ - dialogs::ModelSearchDialog
+ - dialogs::ModelRelationDialog
+ - dialogs::ModelParamDialog
+ - dialogs::ModelItemDialog
+ - dialogs::ModelLoopDialog
+ - dialogs::ModelConditionDialog
+- gmodeler::frame
+ - frame::ModelToolbar
+ - frame::ModelFrame
+ - frame::ModelCanvas
+ - frame::ModelEvtHandler
+ - frame::ModelListCtrl
+ - frame::VariablePanel
+ - frame::ValiableListCtrl
+ - frame::ItemPanel
+ - frame::ItemListCtrl
+ - frame::ItemCheckListCtrl
+- gmodeler::menudata
+ - menudata::ModelerData
+- gmodeler::model
+ - model::Model
+ - model::ModelObject
+ - model::ModelAction
+ - model::ModelData
+ - model::ModelRelation
+ - model::ModelItem
+ - model::ModelLoop
+ - model::ModelCondition
+ - model::ProcessModelFile
+ - model::WriteModelFile
+ - model::WritePythonFile
+- gmodeler::preferences
+ - preferences::PreferencesDialog
+ - preferences::PropertiesDialog
\subsection vdigit Vector digitizer
-- gui_modules/vdigit.py
- - gui_modules::vdigit::VDigit
- - gui_modules::vdigit::VDigitSettingsDialog
- - gui_modules::vdigit::VDigitCategoryDialog
- - gui_modules::vdigit::CategoryListCtrl
- - gui_modules::vdigit::VDigitZBulkDialog
- - gui_modules::vdigit::VDigitDuplicatesDialog
- - gui_modules::vdigit::CheckListFeature
+- vdigit::dialogs
+ - dialogs::VDigitCategoryDialog
+ - dialogs::CategoryListCtrl
+ - dialogs::VDigitZBulkDialog
+ - dialogs::VDigitDuplicatesDialog
+ - dialogs::CheckListFeature
+- vdigit::main
+ - main::VDigit
+- vdigit::mapwindow
+ - mapwindow::VDigitWindow
+- vdigit::preferences
+ - preferences::VDigitSettingsDialog
+- vdigit::toolbars
+ - toolbars::VDigitToolbar
+- vdigit::wxvdigit
+ - wxdigit::VDigitError
+ - wxdigit::IVDigit
+- vdigit::wxdisplay
+ - wxdisplay::DisplayDriver
-- gui_modules/wxvdriver.py
- - gui_modules::wxvdriver::DisplayDriver
-
-- gui_modules/wxvdigit.py
- - gui_modules::wxvdigit::VDigitError
- - gui_modules::wxvdigit::IVDigit
-
\subsection wxnviz 3D view mode (wxNviz)
-- gui_modules/nviz_mapdisp.py
- - gui_modules::nviz_mapdisp::NvizThread
- - gui_modules::nviz_mapdisp::GLWindow
+- nviz::animation
+ - animation::Animation
+- nviz::main
+- nviz::mapwindow
+ - mapwindow::NvizThread
+ - mapwindow::GLWindow
+- nviz::preferences
+ - preferences::NvizPreferencesDialog
+- nviz::tools
+ - tools::NvizToolWindow
+ - tools::PositionWindow
+ - tools::ViewPositionWindow
+ - tools::LightPositionWindow
+- nviz::workspace
+ - workspace::NvizSettings
+- nviz::wxnviz
+ - wxnviz::Nviz
+ - wxnviz::Texture
+ - wxnviz::ImageTexture
+ - wxnviz::TextTexture
-- gui_modules/nviz_preferences.py
- - gui_modules::nviz_preferences::NvizPreferencesDialog
+\subsection psmap Cartograpic Composer
-- gui_modules/nviz.py
+- psmap::dialogs
+ - dialogs::UnitConversion
+ - dialogs::TCValidator
+ - dialogs::PenStyleComboBox
+ - dialogs::CheckListCtrl
+ - dialogs::Instruction
+ - dialogs::InstructionObject
+ - dialogs::InitMap
+ - dialogs::MapFrame
+ - dialogs::PageSetup
+ - dialogs::Mapinfo
+ - dialogs::Text
+ - dialogs::Image
+ - dialogs::NorthArrow
+ - dialogs::Scalebar
+ - dialogs::RasterLegend
+ - dialogs::VectorLegend
+ - dialogs::Raster
+ - dialogs::Vector
+ - dialogs::VProperties
+ - dialogs::PsmapDialog
+ - dialogs::PageSetupDialog
+ - dialogs::MapDialog
+ - dialogs::MapFramePanel
+ - dialogs::RasterPanel
+ - dialogs::VectorPanel
+ - dialogs::RasterDialog
+ - dialogs::MainVectorDialog
+ - dialogs::VPropertiesDialog
+ - dialogs::LegendDialog
+ - dialogs::MapinfoDialog
+ - dialogs::ScalebarDialog
+ - dialogs::TextDialog
+ - dialogs::ImageDialog
+ - dialogs::NorthArrowDialog
+- psmap::frame
+ - frame::PsMapFrame
+ - frame::PsMapBufferedWindow
+- psmap::menudata
+ - menudata::PsMapData
+- psmap::toolbars
+ - toolbars::PsMapToolbar
-- gui_modules/nviz_tools.py
- - gui_modules::nviz_tools::NvizToolWindow
- - gui_modules::nviz_tools::PositionWindow
- - gui_modules::nviz_tools::ViewPositionWindow
- - gui_modules::nviz_tools::LightPositionWindow
-
-- gui_modules/wxnviz.py
- - gui_modules::wxnviz::Nviz
-
\subsection locWizard Location Wizard
-- gui_modules/location_wizard.py
- - gui_modules::location_wizard::BaseClass
- - gui_modules::location_wizard::TitledPage
- - gui_modules::location_wizard::DatabasePage
- - gui_modules::location_wizard::CoordinateSystemPage
- - gui_modules::location_wizard::ProjectionsPage
- - gui_modules::location_wizard::ItemList
- - gui_modules::location_wizard::ProjParamsPage
- - gui_modules::location_wizard::DatumPage
- - gui_modules::location_wizard::EllipsePage
- - gui_modules::location_wizard::GeoreferencedFilePage
- - gui_modules::location_wizard::WKTPage
- - gui_modules::location_wizard::EPSGPage
- - gui_modules::location_wizard::CustomPage
- - gui_modules::location_wizard::SummaryPage
- - gui_modules::location_wizard::LocationWizard
- - gui_modules::location_wizard::RegionDef
- - gui_modules::location_wizard::TransList
- - gui_modules::location_wizard::SelectTransformDialog
+- location_wizard::base
+ - location_wizard::BaseClass
+- location_wizard::dialogs
+ - dialogs::RegionDef
+ - dialogs::TransList
+ - dialogs::SelectTransformDialog
+- location_wizard::wizard
+ - wizard::TitledPage
+ - wizard::DatabasePage
+ - wizard::CoordinateSystemPage
+ - wizard::ProjectionsPage
+ - wizard::ItemList
+ - wizard::ProjParamsPage
+ - wizard::DatumPage
+ - wizard::EllipsePage
+ - wizard::GeoreferencedFilePage
+ - wizard::EPSGPage
+ - wizard::CustomPage
+ - wizard::SummaryPage
+ - wizard::LocationWizard
-\subsection mcalc Map Calculator
+\subsection plot Plotting modules
-- gui_modules/mcalc_builder.py
- - gui_modules::mcalc_builder::MapCalcFrame
+- wxplot::base
+ - base::BasePlotFrame
+- wxplot::dialogs
+ - dialogs::ProfileRasterDialog
+ - dialogs::ScatterRasterDialog
+ - dialogs::PlotStatsFrame
+ - dialogs::HistRasterDialog
+ - dialogs::TextDialog
+ - dialogs::OptDialog
+- wxplot::histogram
+ - histogram::Histogram2Frame
+ - histogram::Histogram2Toolbar
+- wxplot::profile
+ - profile::ProfileFrame
+ - profile::ProfileToolbar
+- wxplot::scatter
+ - scatter::ScatterFrame
+ - scatter::ScatterToolbar
-\subsection misc Miscellaneous
+\subsection other Other GUI modules
-- gui_modules/colorrules.py
- - gui_modules::colorrules::ColorTable
- - gui_modules::colorrules::BufferedWindow
+- modules::colorrules
+ - colorrules::RulesPanel
+ - colorrules::ColorTable
+ - colorrules::RasterColorTable
+ - colorrules::VectorColorTable
+ - colorrules::ThematicVectorTable
+ - colorrules::BufferedWindow
+- modules::extensions
+ - extensions::InstallExtensionWindow
+ - extensions::ExtensionTree
+- modules::histogram
+ - histogram::BufferedWindow
+ - histogram::HistogramFrame
+ - histogram::HistogramToolbar
+- modules::mcalc_builder
+ - mcalc_builder::MapCalcFrame
+- modules::ogc_services
+ - ogc_services::WMSDialog
+ - ogc_services::LayersList
+- modules::vclean
+ - vclean::VectorCleaningFrame
-- gui_modules/gdialogs.py
- - gui_modules::gdialogs::ElementDialog
- - gui_modules::gdialogs::LocationDialog
- - gui_modules::gdialogs::MapsetDialog
- - gui_modules::gdialogs::NewVectorDialog
- - gui_modules::gdialogs::SavedRegion
- - gui_modules::gdialogs::DecorationDialog
- - gui_modules::gdialogs::TextLayerDialog
- - gui_modules::gdialogs::LoadMapLayersDialog
- - gui_modules::gdialogs::ImportDialog
- - gui_modules::gdialogs::GdalImportDialog
- - gui_modules::gdialogs::DxfImportDialog
- - gui_modules::gdialogs::LayersList
- - gui_modules::gdialogs::SetOpacityDialog
- - gui_modules::gdialogs::StaticWrapText
- - gui_modules::gdialogs::ImageSizeDialog
-
-- gui_modules/histogram.py
- - gui_modules::histogram::BufferedWindow
- - gui_modules::histogram::HistFrame
-
-- gui_modules/ogc_services.py
- - gui_modules::ogc_services::WMSDialog
- - gui_modules::ogc_services::LayersList
-
-- gui_modules/profile.py
- - gui_modules::profile::ProfileFrame
- - gui_modules::profile::SetRasterDialog
- - gui_modules::profile::TextDialog
- - gui_modules::profile::OptDialog
-
-- gui_modules/vclean.py
- - gui_modules::vclean::VectorCleaningFrame
-
\section devel Further Development
Ongoing development focuses on stability, portability and on the
More information about the grass-commit
mailing list